blob: 6a2f3289f8941ed1993f922207a3ecb96546232f [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
Ben Murdochb8e0da22011-05-16 14:20:40 +0100817static void* expected_ptr;
818static v8::Handle<v8::Value> callback(const v8::Arguments& args) {
819 void* ptr = v8::External::Unwrap(args.Data());
820 CHECK_EQ(expected_ptr, ptr);
821 return v8::Boolean::New(true);
822}
823
824
825static void TestExternalPointerWrapping() {
826 v8::HandleScope scope;
827 LocalContext env;
828
829 v8::Handle<v8::Value> data = v8::External::Wrap(expected_ptr);
830
831 v8::Handle<v8::Object> obj = v8::Object::New();
832 obj->Set(v8_str("func"),
833 v8::FunctionTemplate::New(callback, data)->GetFunction());
834 env->Global()->Set(v8_str("obj"), obj);
835
836 CHECK(CompileRun(
837 "function foo() {\n"
838 " for (var i = 0; i < 13; i++) obj.func();\n"
839 "}\n"
840 "foo(), true")->BooleanValue());
841}
842
843
844THREADED_TEST(ExternalWrap) {
845 // Check heap allocated object.
846 int* ptr = new int;
847 expected_ptr = ptr;
848 TestExternalPointerWrapping();
849 delete ptr;
850
851 // Check stack allocated object.
852 int foo;
853 expected_ptr = &foo;
854 TestExternalPointerWrapping();
855
856 // Check not aligned addresses.
857 const int n = 100;
858 char* s = new char[n];
859 for (int i = 0; i < n; i++) {
860 expected_ptr = s + i;
861 TestExternalPointerWrapping();
862 }
863
864 delete[] s;
865
866 // Check several invalid addresses.
867 expected_ptr = reinterpret_cast<void*>(1);
868 TestExternalPointerWrapping();
869
870 expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
871 TestExternalPointerWrapping();
872
873 expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
874 TestExternalPointerWrapping();
875
876#if defined(V8_HOST_ARCH_X64)
877 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
878 TestExternalPointerWrapping();
879
880 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
881 TestExternalPointerWrapping();
882#endif
883}
884
885
Steve Blocka7e24c12009-10-30 11:49:00 +0000886THREADED_TEST(FindInstanceInPrototypeChain) {
887 v8::HandleScope scope;
888 LocalContext env;
889
890 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
891 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
892 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
893 derived->Inherit(base);
894
895 Local<v8::Function> base_function = base->GetFunction();
896 Local<v8::Function> derived_function = derived->GetFunction();
897 Local<v8::Function> other_function = other->GetFunction();
898
899 Local<v8::Object> base_instance = base_function->NewInstance();
900 Local<v8::Object> derived_instance = derived_function->NewInstance();
901 Local<v8::Object> derived_instance2 = derived_function->NewInstance();
902 Local<v8::Object> other_instance = other_function->NewInstance();
903 derived_instance2->Set(v8_str("__proto__"), derived_instance);
904 other_instance->Set(v8_str("__proto__"), derived_instance2);
905
906 // base_instance is only an instance of base.
907 CHECK_EQ(base_instance,
908 base_instance->FindInstanceInPrototypeChain(base));
909 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
910 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
911
912 // derived_instance is an instance of base and derived.
913 CHECK_EQ(derived_instance,
914 derived_instance->FindInstanceInPrototypeChain(base));
915 CHECK_EQ(derived_instance,
916 derived_instance->FindInstanceInPrototypeChain(derived));
917 CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
918
919 // other_instance is an instance of other and its immediate
920 // prototype derived_instance2 is an instance of base and derived.
921 // Note, derived_instance is an instance of base and derived too,
922 // but it comes after derived_instance2 in the prototype chain of
923 // other_instance.
924 CHECK_EQ(derived_instance2,
925 other_instance->FindInstanceInPrototypeChain(base));
926 CHECK_EQ(derived_instance2,
927 other_instance->FindInstanceInPrototypeChain(derived));
928 CHECK_EQ(other_instance,
929 other_instance->FindInstanceInPrototypeChain(other));
930}
931
932
Steve Block3ce2e202009-11-05 08:53:23 +0000933THREADED_TEST(TinyInteger) {
934 v8::HandleScope scope;
935 LocalContext env;
936 int32_t value = 239;
937 Local<v8::Integer> value_obj = v8::Integer::New(value);
938 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
939}
940
941
942THREADED_TEST(BigSmiInteger) {
943 v8::HandleScope scope;
944 LocalContext env;
945 int32_t value = i::Smi::kMaxValue;
946 // We cannot add one to a Smi::kMaxValue without wrapping.
947 if (i::kSmiValueSize < 32) {
948 CHECK(i::Smi::IsValid(value));
949 CHECK(!i::Smi::IsValid(value + 1));
950 Local<v8::Integer> value_obj = v8::Integer::New(value);
951 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
952 }
953}
954
955
956THREADED_TEST(BigInteger) {
957 v8::HandleScope scope;
958 LocalContext env;
959 // We cannot add one to a Smi::kMaxValue without wrapping.
960 if (i::kSmiValueSize < 32) {
961 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
962 // The code will not be run in that case, due to the "if" guard.
963 int32_t value =
964 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
965 CHECK(value > i::Smi::kMaxValue);
966 CHECK(!i::Smi::IsValid(value));
967 Local<v8::Integer> value_obj = v8::Integer::New(value);
968 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
969 }
970}
971
972
973THREADED_TEST(TinyUnsignedInteger) {
974 v8::HandleScope scope;
975 LocalContext env;
976 uint32_t value = 239;
977 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
978 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
979}
980
981
982THREADED_TEST(BigUnsignedSmiInteger) {
983 v8::HandleScope scope;
984 LocalContext env;
985 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
986 CHECK(i::Smi::IsValid(value));
987 CHECK(!i::Smi::IsValid(value + 1));
988 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
989 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
990}
991
992
993THREADED_TEST(BigUnsignedInteger) {
994 v8::HandleScope scope;
995 LocalContext env;
996 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
997 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
998 CHECK(!i::Smi::IsValid(value));
999 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1000 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1001}
1002
1003
1004THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1005 v8::HandleScope scope;
1006 LocalContext env;
1007 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1008 uint32_t value = INT32_MAX_AS_UINT + 1;
1009 CHECK(value > INT32_MAX_AS_UINT); // No overflow.
1010 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1011 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1012}
1013
1014
Steve Blocka7e24c12009-10-30 11:49:00 +00001015THREADED_TEST(Number) {
1016 v8::HandleScope scope;
1017 LocalContext env;
1018 double PI = 3.1415926;
1019 Local<v8::Number> pi_obj = v8::Number::New(PI);
1020 CHECK_EQ(PI, pi_obj->NumberValue());
1021}
1022
1023
1024THREADED_TEST(ToNumber) {
1025 v8::HandleScope scope;
1026 LocalContext env;
1027 Local<String> str = v8_str("3.1415926");
1028 CHECK_EQ(3.1415926, str->NumberValue());
1029 v8::Handle<v8::Boolean> t = v8::True();
1030 CHECK_EQ(1.0, t->NumberValue());
1031 v8::Handle<v8::Boolean> f = v8::False();
1032 CHECK_EQ(0.0, f->NumberValue());
1033}
1034
1035
1036THREADED_TEST(Date) {
1037 v8::HandleScope scope;
1038 LocalContext env;
1039 double PI = 3.1415926;
1040 Local<Value> date_obj = v8::Date::New(PI);
1041 CHECK_EQ(3.0, date_obj->NumberValue());
1042}
1043
1044
1045THREADED_TEST(Boolean) {
1046 v8::HandleScope scope;
1047 LocalContext env;
1048 v8::Handle<v8::Boolean> t = v8::True();
1049 CHECK(t->Value());
1050 v8::Handle<v8::Boolean> f = v8::False();
1051 CHECK(!f->Value());
1052 v8::Handle<v8::Primitive> u = v8::Undefined();
1053 CHECK(!u->BooleanValue());
1054 v8::Handle<v8::Primitive> n = v8::Null();
1055 CHECK(!n->BooleanValue());
1056 v8::Handle<String> str1 = v8_str("");
1057 CHECK(!str1->BooleanValue());
1058 v8::Handle<String> str2 = v8_str("x");
1059 CHECK(str2->BooleanValue());
1060 CHECK(!v8::Number::New(0)->BooleanValue());
1061 CHECK(v8::Number::New(-1)->BooleanValue());
1062 CHECK(v8::Number::New(1)->BooleanValue());
1063 CHECK(v8::Number::New(42)->BooleanValue());
1064 CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1065}
1066
1067
1068static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
1069 ApiTestFuzzer::Fuzz();
1070 return v8_num(13.4);
1071}
1072
1073
1074static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
1075 ApiTestFuzzer::Fuzz();
1076 return v8_num(876);
1077}
1078
1079
1080THREADED_TEST(GlobalPrototype) {
1081 v8::HandleScope scope;
1082 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
1083 func_templ->PrototypeTemplate()->Set(
1084 "dummy",
1085 v8::FunctionTemplate::New(DummyCallHandler));
1086 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1087 templ->Set("x", v8_num(200));
1088 templ->SetAccessor(v8_str("m"), GetM);
1089 LocalContext env(0, templ);
1090 v8::Handle<v8::Object> obj = env->Global();
1091 v8::Handle<Script> script = v8_compile("dummy()");
1092 v8::Handle<Value> result = script->Run();
1093 CHECK_EQ(13.4, result->NumberValue());
1094 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1095 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1096}
1097
1098
Steve Blocka7e24c12009-10-30 11:49:00 +00001099THREADED_TEST(ObjectTemplate) {
1100 v8::HandleScope scope;
1101 Local<ObjectTemplate> templ1 = ObjectTemplate::New();
1102 templ1->Set("x", v8_num(10));
1103 templ1->Set("y", v8_num(13));
1104 LocalContext env;
1105 Local<v8::Object> instance1 = templ1->NewInstance();
1106 env->Global()->Set(v8_str("p"), instance1);
1107 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1108 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1109 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
1110 fun->PrototypeTemplate()->Set("nirk", v8_num(123));
1111 Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1112 templ2->Set("a", v8_num(12));
1113 templ2->Set("b", templ1);
1114 Local<v8::Object> instance2 = templ2->NewInstance();
1115 env->Global()->Set(v8_str("q"), instance2);
1116 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1117 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1118 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1119 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1120}
1121
1122
1123static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
1124 ApiTestFuzzer::Fuzz();
1125 return v8_num(17.2);
1126}
1127
1128
1129static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
1130 ApiTestFuzzer::Fuzz();
1131 return v8_num(15.2);
1132}
1133
1134
1135THREADED_TEST(DescriptorInheritance) {
1136 v8::HandleScope scope;
1137 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
1138 super->PrototypeTemplate()->Set("flabby",
1139 v8::FunctionTemplate::New(GetFlabby));
1140 super->PrototypeTemplate()->Set("PI", v8_num(3.14));
1141
1142 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1143
1144 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
1145 base1->Inherit(super);
1146 base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
1147
1148 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
1149 base2->Inherit(super);
1150 base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
1151
1152 LocalContext env;
1153
1154 env->Global()->Set(v8_str("s"), super->GetFunction());
1155 env->Global()->Set(v8_str("base1"), base1->GetFunction());
1156 env->Global()->Set(v8_str("base2"), base2->GetFunction());
1157
1158 // Checks right __proto__ chain.
1159 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1160 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1161
1162 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1163
1164 // Instance accessor should not be visible on function object or its prototype
1165 CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1166 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1167 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1168
1169 env->Global()->Set(v8_str("obj"),
1170 base1->GetFunction()->NewInstance());
1171 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1172 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1173 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1174 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1175 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1176
1177 env->Global()->Set(v8_str("obj2"),
1178 base2->GetFunction()->NewInstance());
1179 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1180 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1181 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1182 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1183 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1184
1185 // base1 and base2 cannot cross reference to each's prototype
1186 CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1187 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1188}
1189
1190
1191int echo_named_call_count;
1192
1193
1194static v8::Handle<Value> EchoNamedProperty(Local<String> name,
1195 const AccessorInfo& info) {
1196 ApiTestFuzzer::Fuzz();
1197 CHECK_EQ(v8_str("data"), info.Data());
1198 echo_named_call_count++;
1199 return name;
1200}
1201
1202
1203THREADED_TEST(NamedPropertyHandlerGetter) {
1204 echo_named_call_count = 0;
1205 v8::HandleScope scope;
1206 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1207 templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
1208 0, 0, 0, 0,
1209 v8_str("data"));
1210 LocalContext env;
1211 env->Global()->Set(v8_str("obj"),
1212 templ->GetFunction()->NewInstance());
1213 CHECK_EQ(echo_named_call_count, 0);
1214 v8_compile("obj.x")->Run();
1215 CHECK_EQ(echo_named_call_count, 1);
1216 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
1217 v8::Handle<Value> str = CompileRun(code);
1218 String::AsciiValue value(str);
1219 CHECK_EQ(*value, "oddlepoddle");
1220 // Check default behavior
1221 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
1222 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
1223 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
1224}
1225
1226
1227int echo_indexed_call_count = 0;
1228
1229
1230static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
1231 const AccessorInfo& info) {
1232 ApiTestFuzzer::Fuzz();
1233 CHECK_EQ(v8_num(637), info.Data());
1234 echo_indexed_call_count++;
1235 return v8_num(index);
1236}
1237
1238
1239THREADED_TEST(IndexedPropertyHandlerGetter) {
1240 v8::HandleScope scope;
1241 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1242 templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
1243 0, 0, 0, 0,
1244 v8_num(637));
1245 LocalContext env;
1246 env->Global()->Set(v8_str("obj"),
1247 templ->GetFunction()->NewInstance());
1248 Local<Script> script = v8_compile("obj[900]");
1249 CHECK_EQ(script->Run()->Int32Value(), 900);
1250}
1251
1252
1253v8::Handle<v8::Object> bottom;
1254
1255static v8::Handle<Value> CheckThisIndexedPropertyHandler(
1256 uint32_t index,
1257 const AccessorInfo& info) {
1258 ApiTestFuzzer::Fuzz();
1259 CHECK(info.This()->Equals(bottom));
1260 return v8::Handle<Value>();
1261}
1262
1263static v8::Handle<Value> CheckThisNamedPropertyHandler(
1264 Local<String> name,
1265 const AccessorInfo& info) {
1266 ApiTestFuzzer::Fuzz();
1267 CHECK(info.This()->Equals(bottom));
1268 return v8::Handle<Value>();
1269}
1270
1271
1272v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
1273 Local<Value> value,
1274 const AccessorInfo& info) {
1275 ApiTestFuzzer::Fuzz();
1276 CHECK(info.This()->Equals(bottom));
1277 return v8::Handle<Value>();
1278}
1279
1280
1281v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
1282 Local<Value> value,
1283 const AccessorInfo& info) {
1284 ApiTestFuzzer::Fuzz();
1285 CHECK(info.This()->Equals(bottom));
1286 return v8::Handle<Value>();
1287}
1288
Iain Merrick75681382010-08-19 15:07:18 +01001289v8::Handle<v8::Integer> CheckThisIndexedPropertyQuery(
Steve Blocka7e24c12009-10-30 11:49:00 +00001290 uint32_t index,
1291 const AccessorInfo& info) {
1292 ApiTestFuzzer::Fuzz();
1293 CHECK(info.This()->Equals(bottom));
Iain Merrick75681382010-08-19 15:07:18 +01001294 return v8::Handle<v8::Integer>();
Steve Blocka7e24c12009-10-30 11:49:00 +00001295}
1296
1297
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001298v8::Handle<v8::Integer> CheckThisNamedPropertyQuery(Local<String> property,
Steve Blocka7e24c12009-10-30 11:49:00 +00001299 const AccessorInfo& info) {
1300 ApiTestFuzzer::Fuzz();
1301 CHECK(info.This()->Equals(bottom));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001302 return v8::Handle<v8::Integer>();
Steve Blocka7e24c12009-10-30 11:49:00 +00001303}
1304
1305
1306v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
1307 uint32_t index,
1308 const AccessorInfo& info) {
1309 ApiTestFuzzer::Fuzz();
1310 CHECK(info.This()->Equals(bottom));
1311 return v8::Handle<v8::Boolean>();
1312}
1313
1314
1315v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
1316 Local<String> property,
1317 const AccessorInfo& info) {
1318 ApiTestFuzzer::Fuzz();
1319 CHECK(info.This()->Equals(bottom));
1320 return v8::Handle<v8::Boolean>();
1321}
1322
1323
1324v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
1325 const AccessorInfo& info) {
1326 ApiTestFuzzer::Fuzz();
1327 CHECK(info.This()->Equals(bottom));
1328 return v8::Handle<v8::Array>();
1329}
1330
1331
1332v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
1333 const AccessorInfo& info) {
1334 ApiTestFuzzer::Fuzz();
1335 CHECK(info.This()->Equals(bottom));
1336 return v8::Handle<v8::Array>();
1337}
1338
1339
1340THREADED_TEST(PropertyHandlerInPrototype) {
1341 v8::HandleScope scope;
1342 LocalContext env;
1343
1344 // Set up a prototype chain with three interceptors.
1345 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1346 templ->InstanceTemplate()->SetIndexedPropertyHandler(
1347 CheckThisIndexedPropertyHandler,
1348 CheckThisIndexedPropertySetter,
1349 CheckThisIndexedPropertyQuery,
1350 CheckThisIndexedPropertyDeleter,
1351 CheckThisIndexedPropertyEnumerator);
1352
1353 templ->InstanceTemplate()->SetNamedPropertyHandler(
1354 CheckThisNamedPropertyHandler,
1355 CheckThisNamedPropertySetter,
1356 CheckThisNamedPropertyQuery,
1357 CheckThisNamedPropertyDeleter,
1358 CheckThisNamedPropertyEnumerator);
1359
1360 bottom = templ->GetFunction()->NewInstance();
1361 Local<v8::Object> top = templ->GetFunction()->NewInstance();
1362 Local<v8::Object> middle = templ->GetFunction()->NewInstance();
1363
1364 bottom->Set(v8_str("__proto__"), middle);
1365 middle->Set(v8_str("__proto__"), top);
1366 env->Global()->Set(v8_str("obj"), bottom);
1367
1368 // Indexed and named get.
1369 Script::Compile(v8_str("obj[0]"))->Run();
1370 Script::Compile(v8_str("obj.x"))->Run();
1371
1372 // Indexed and named set.
1373 Script::Compile(v8_str("obj[1] = 42"))->Run();
1374 Script::Compile(v8_str("obj.y = 42"))->Run();
1375
1376 // Indexed and named query.
1377 Script::Compile(v8_str("0 in obj"))->Run();
1378 Script::Compile(v8_str("'x' in obj"))->Run();
1379
1380 // Indexed and named deleter.
1381 Script::Compile(v8_str("delete obj[0]"))->Run();
1382 Script::Compile(v8_str("delete obj.x"))->Run();
1383
1384 // Enumerators.
1385 Script::Compile(v8_str("for (var p in obj) ;"))->Run();
1386}
1387
1388
1389static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
1390 const AccessorInfo& info) {
1391 ApiTestFuzzer::Fuzz();
1392 if (v8_str("pre")->Equals(key)) {
1393 return v8_str("PrePropertyHandler: pre");
1394 }
1395 return v8::Handle<String>();
1396}
1397
1398
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001399static v8::Handle<v8::Integer> PrePropertyHandlerQuery(Local<String> key,
1400 const AccessorInfo&) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001401 if (v8_str("pre")->Equals(key)) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001402 return v8::Integer::New(v8::None);
Steve Blocka7e24c12009-10-30 11:49:00 +00001403 }
1404
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001405 return v8::Handle<v8::Integer>(); // do not intercept the call
Steve Blocka7e24c12009-10-30 11:49:00 +00001406}
1407
1408
1409THREADED_TEST(PrePropertyHandler) {
1410 v8::HandleScope scope;
1411 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
1412 desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
1413 0,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001414 PrePropertyHandlerQuery);
Steve Blocka7e24c12009-10-30 11:49:00 +00001415 LocalContext env(NULL, desc->InstanceTemplate());
1416 Script::Compile(v8_str(
1417 "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
1418 v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
1419 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
1420 v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
1421 CHECK_EQ(v8_str("Object: on"), result_on);
1422 v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
1423 CHECK(result_post.IsEmpty());
1424}
1425
1426
1427THREADED_TEST(UndefinedIsNotEnumerable) {
1428 v8::HandleScope scope;
1429 LocalContext env;
1430 v8::Handle<Value> result = Script::Compile(v8_str(
1431 "this.propertyIsEnumerable(undefined)"))->Run();
1432 CHECK(result->IsFalse());
1433}
1434
1435
1436v8::Handle<Script> call_recursively_script;
Leon Clarke4515c472010-02-03 11:58:03 +00001437static const int kTargetRecursionDepth = 200; // near maximum
Steve Blocka7e24c12009-10-30 11:49:00 +00001438
1439
1440static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
1441 ApiTestFuzzer::Fuzz();
1442 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1443 if (depth == kTargetRecursionDepth) return v8::Undefined();
1444 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1445 return call_recursively_script->Run();
1446}
1447
1448
1449static v8::Handle<Value> CallFunctionRecursivelyCall(
1450 const v8::Arguments& args) {
1451 ApiTestFuzzer::Fuzz();
1452 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1453 if (depth == kTargetRecursionDepth) {
1454 printf("[depth = %d]\n", depth);
1455 return v8::Undefined();
1456 }
1457 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1458 v8::Handle<Value> function =
1459 args.This()->Get(v8_str("callFunctionRecursively"));
Steve Block6ded16b2010-05-10 14:33:55 +01001460 return function.As<Function>()->Call(args.This(), 0, NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001461}
1462
1463
1464THREADED_TEST(DeepCrossLanguageRecursion) {
1465 v8::HandleScope scope;
1466 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
1467 global->Set(v8_str("callScriptRecursively"),
1468 v8::FunctionTemplate::New(CallScriptRecursivelyCall));
1469 global->Set(v8_str("callFunctionRecursively"),
1470 v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
1471 LocalContext env(NULL, global);
1472
1473 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1474 call_recursively_script = v8_compile("callScriptRecursively()");
1475 v8::Handle<Value> result = call_recursively_script->Run();
1476 call_recursively_script = v8::Handle<Script>();
1477
1478 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1479 Script::Compile(v8_str("callFunctionRecursively()"))->Run();
1480}
1481
1482
1483static v8::Handle<Value>
1484 ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1485 ApiTestFuzzer::Fuzz();
1486 return v8::ThrowException(key);
1487}
1488
1489
1490static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
1491 Local<Value>,
1492 const AccessorInfo&) {
1493 v8::ThrowException(key);
1494 return v8::Undefined(); // not the same as v8::Handle<v8::Value>()
1495}
1496
1497
1498THREADED_TEST(CallbackExceptionRegression) {
1499 v8::HandleScope scope;
1500 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1501 obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
1502 ThrowingPropertyHandlerSet);
1503 LocalContext env;
1504 env->Global()->Set(v8_str("obj"), obj->NewInstance());
1505 v8::Handle<Value> otto = Script::Compile(v8_str(
1506 "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
1507 CHECK_EQ(v8_str("otto"), otto);
1508 v8::Handle<Value> netto = Script::Compile(v8_str(
1509 "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
1510 CHECK_EQ(v8_str("netto"), netto);
1511}
1512
1513
Steve Blocka7e24c12009-10-30 11:49:00 +00001514THREADED_TEST(FunctionPrototype) {
1515 v8::HandleScope scope;
1516 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
1517 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
1518 LocalContext env;
1519 env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
1520 Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
1521 CHECK_EQ(script->Run()->Int32Value(), 321);
1522}
1523
1524
1525THREADED_TEST(InternalFields) {
1526 v8::HandleScope scope;
1527 LocalContext env;
1528
1529 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1530 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1531 instance_templ->SetInternalFieldCount(1);
1532 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1533 CHECK_EQ(1, obj->InternalFieldCount());
1534 CHECK(obj->GetInternalField(0)->IsUndefined());
1535 obj->SetInternalField(0, v8_num(17));
1536 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
1537}
1538
1539
Steve Block6ded16b2010-05-10 14:33:55 +01001540THREADED_TEST(GlobalObjectInternalFields) {
1541 v8::HandleScope scope;
1542 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
1543 global_template->SetInternalFieldCount(1);
1544 LocalContext env(NULL, global_template);
1545 v8::Handle<v8::Object> global_proxy = env->Global();
1546 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
1547 CHECK_EQ(1, global->InternalFieldCount());
1548 CHECK(global->GetInternalField(0)->IsUndefined());
1549 global->SetInternalField(0, v8_num(17));
1550 CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
1551}
1552
1553
Steve Blocka7e24c12009-10-30 11:49:00 +00001554THREADED_TEST(InternalFieldsNativePointers) {
1555 v8::HandleScope scope;
1556 LocalContext env;
1557
1558 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1559 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1560 instance_templ->SetInternalFieldCount(1);
1561 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1562 CHECK_EQ(1, obj->InternalFieldCount());
1563 CHECK(obj->GetPointerFromInternalField(0) == NULL);
1564
1565 char* data = new char[100];
1566
1567 void* aligned = data;
Ben Murdochf87a2032010-10-22 12:50:53 +01001568 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
Steve Blocka7e24c12009-10-30 11:49:00 +00001569 void* unaligned = data + 1;
Ben Murdochf87a2032010-10-22 12:50:53 +01001570 CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
Steve Blocka7e24c12009-10-30 11:49:00 +00001571
1572 // Check reading and writing aligned pointers.
1573 obj->SetPointerInInternalField(0, aligned);
1574 i::Heap::CollectAllGarbage(false);
1575 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1576
1577 // Check reading and writing unaligned pointers.
1578 obj->SetPointerInInternalField(0, unaligned);
1579 i::Heap::CollectAllGarbage(false);
1580 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1581
1582 delete[] data;
1583}
1584
1585
Steve Block3ce2e202009-11-05 08:53:23 +00001586THREADED_TEST(InternalFieldsNativePointersAndExternal) {
1587 v8::HandleScope scope;
1588 LocalContext env;
1589
1590 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1591 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1592 instance_templ->SetInternalFieldCount(1);
1593 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1594 CHECK_EQ(1, obj->InternalFieldCount());
1595 CHECK(obj->GetPointerFromInternalField(0) == NULL);
1596
1597 char* data = new char[100];
1598
1599 void* aligned = data;
Ben Murdochf87a2032010-10-22 12:50:53 +01001600 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
Steve Block3ce2e202009-11-05 08:53:23 +00001601 void* unaligned = data + 1;
Ben Murdochf87a2032010-10-22 12:50:53 +01001602 CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
Steve Block3ce2e202009-11-05 08:53:23 +00001603
1604 obj->SetPointerInInternalField(0, aligned);
1605 i::Heap::CollectAllGarbage(false);
1606 CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0)));
1607
1608 obj->SetPointerInInternalField(0, unaligned);
1609 i::Heap::CollectAllGarbage(false);
1610 CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0)));
1611
1612 obj->SetInternalField(0, v8::External::Wrap(aligned));
1613 i::Heap::CollectAllGarbage(false);
1614 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1615
1616 obj->SetInternalField(0, v8::External::Wrap(unaligned));
1617 i::Heap::CollectAllGarbage(false);
1618 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1619
1620 delete[] data;
1621}
1622
1623
Steve Blocka7e24c12009-10-30 11:49:00 +00001624THREADED_TEST(IdentityHash) {
1625 v8::HandleScope scope;
1626 LocalContext env;
1627
1628 // Ensure that the test starts with an fresh heap to test whether the hash
1629 // code is based on the address.
1630 i::Heap::CollectAllGarbage(false);
1631 Local<v8::Object> obj = v8::Object::New();
1632 int hash = obj->GetIdentityHash();
1633 int hash1 = obj->GetIdentityHash();
1634 CHECK_EQ(hash, hash1);
1635 int hash2 = v8::Object::New()->GetIdentityHash();
1636 // Since the identity hash is essentially a random number two consecutive
1637 // objects should not be assigned the same hash code. If the test below fails
1638 // the random number generator should be evaluated.
1639 CHECK_NE(hash, hash2);
1640 i::Heap::CollectAllGarbage(false);
1641 int hash3 = v8::Object::New()->GetIdentityHash();
1642 // Make sure that the identity hash is not based on the initial address of
1643 // the object alone. If the test below fails the random number generator
1644 // should be evaluated.
1645 CHECK_NE(hash, hash3);
1646 int hash4 = obj->GetIdentityHash();
1647 CHECK_EQ(hash, hash4);
1648}
1649
1650
1651THREADED_TEST(HiddenProperties) {
1652 v8::HandleScope scope;
1653 LocalContext env;
1654
1655 v8::Local<v8::Object> obj = v8::Object::New();
1656 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1657 v8::Local<v8::String> empty = v8_str("");
1658 v8::Local<v8::String> prop_name = v8_str("prop_name");
1659
1660 i::Heap::CollectAllGarbage(false);
1661
1662 // Make sure delete of a non-existent hidden value works
1663 CHECK(obj->DeleteHiddenValue(key));
1664
1665 CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
1666 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
1667 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
1668 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1669
1670 i::Heap::CollectAllGarbage(false);
1671
1672 // Make sure we do not find the hidden property.
1673 CHECK(!obj->Has(empty));
1674 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1675 CHECK(obj->Get(empty)->IsUndefined());
1676 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1677 CHECK(obj->Set(empty, v8::Integer::New(2003)));
1678 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1679 CHECK_EQ(2003, obj->Get(empty)->Int32Value());
1680
1681 i::Heap::CollectAllGarbage(false);
1682
1683 // Add another property and delete it afterwards to force the object in
1684 // slow case.
1685 CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
1686 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1687 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
1688 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1689 CHECK(obj->Delete(prop_name));
1690 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1691
1692 i::Heap::CollectAllGarbage(false);
1693
1694 CHECK(obj->DeleteHiddenValue(key));
1695 CHECK(obj->GetHiddenValue(key).IsEmpty());
1696}
1697
1698
Steve Blockd0582a62009-12-15 09:54:21 +00001699static bool interceptor_for_hidden_properties_called;
Steve Blocka7e24c12009-10-30 11:49:00 +00001700static v8::Handle<Value> InterceptorForHiddenProperties(
1701 Local<String> name, const AccessorInfo& info) {
Steve Blockd0582a62009-12-15 09:54:21 +00001702 interceptor_for_hidden_properties_called = true;
Steve Blocka7e24c12009-10-30 11:49:00 +00001703 return v8::Handle<Value>();
1704}
1705
1706
1707THREADED_TEST(HiddenPropertiesWithInterceptors) {
1708 v8::HandleScope scope;
1709 LocalContext context;
1710
Steve Blockd0582a62009-12-15 09:54:21 +00001711 interceptor_for_hidden_properties_called = false;
1712
Steve Blocka7e24c12009-10-30 11:49:00 +00001713 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1714
1715 // Associate an interceptor with an object and start setting hidden values.
1716 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
1717 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
1718 instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
1719 Local<v8::Function> function = fun_templ->GetFunction();
1720 Local<v8::Object> obj = function->NewInstance();
1721 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
1722 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
Steve Blockd0582a62009-12-15 09:54:21 +00001723 CHECK(!interceptor_for_hidden_properties_called);
Steve Blocka7e24c12009-10-30 11:49:00 +00001724}
1725
1726
1727THREADED_TEST(External) {
1728 v8::HandleScope scope;
1729 int x = 3;
1730 Local<v8::External> ext = v8::External::New(&x);
1731 LocalContext env;
1732 env->Global()->Set(v8_str("ext"), ext);
1733 Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
Steve Block6ded16b2010-05-10 14:33:55 +01001734 v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
Steve Blocka7e24c12009-10-30 11:49:00 +00001735 int* ptr = static_cast<int*>(reext->Value());
1736 CHECK_EQ(x, 3);
1737 *ptr = 10;
1738 CHECK_EQ(x, 10);
1739
1740 // Make sure unaligned pointers are wrapped properly.
1741 char* data = i::StrDup("0123456789");
1742 Local<v8::Value> zero = v8::External::Wrap(&data[0]);
1743 Local<v8::Value> one = v8::External::Wrap(&data[1]);
1744 Local<v8::Value> two = v8::External::Wrap(&data[2]);
1745 Local<v8::Value> three = v8::External::Wrap(&data[3]);
1746
1747 char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero));
1748 CHECK_EQ('0', *char_ptr);
1749 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one));
1750 CHECK_EQ('1', *char_ptr);
1751 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two));
1752 CHECK_EQ('2', *char_ptr);
1753 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three));
1754 CHECK_EQ('3', *char_ptr);
1755 i::DeleteArray(data);
1756}
1757
1758
1759THREADED_TEST(GlobalHandle) {
1760 v8::Persistent<String> global;
1761 {
1762 v8::HandleScope scope;
1763 Local<String> str = v8_str("str");
1764 global = v8::Persistent<String>::New(str);
1765 }
1766 CHECK_EQ(global->Length(), 3);
1767 global.Dispose();
1768}
1769
1770
1771THREADED_TEST(ScriptException) {
1772 v8::HandleScope scope;
1773 LocalContext env;
1774 Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
1775 v8::TryCatch try_catch;
1776 Local<Value> result = script->Run();
1777 CHECK(result.IsEmpty());
1778 CHECK(try_catch.HasCaught());
1779 String::AsciiValue exception_value(try_catch.Exception());
1780 CHECK_EQ(*exception_value, "panama!");
1781}
1782
1783
1784bool message_received;
1785
1786
1787static void check_message(v8::Handle<v8::Message> message,
1788 v8::Handle<Value> data) {
1789 CHECK_EQ(5.76, data->NumberValue());
1790 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
1791 CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
1792 message_received = true;
1793}
1794
1795
1796THREADED_TEST(MessageHandlerData) {
1797 message_received = false;
1798 v8::HandleScope scope;
1799 CHECK(!message_received);
1800 v8::V8::AddMessageListener(check_message, v8_num(5.76));
1801 LocalContext context;
1802 v8::ScriptOrigin origin =
1803 v8::ScriptOrigin(v8_str("6.75"));
1804 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
1805 &origin);
1806 script->SetData(v8_str("7.56"));
1807 script->Run();
1808 CHECK(message_received);
1809 // clear out the message listener
1810 v8::V8::RemoveMessageListeners(check_message);
1811}
1812
1813
1814THREADED_TEST(GetSetProperty) {
1815 v8::HandleScope scope;
1816 LocalContext context;
1817 context->Global()->Set(v8_str("foo"), v8_num(14));
1818 context->Global()->Set(v8_str("12"), v8_num(92));
1819 context->Global()->Set(v8::Integer::New(16), v8_num(32));
1820 context->Global()->Set(v8_num(13), v8_num(56));
1821 Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
1822 CHECK_EQ(14, foo->Int32Value());
1823 Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
1824 CHECK_EQ(92, twelve->Int32Value());
1825 Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
1826 CHECK_EQ(32, sixteen->Int32Value());
1827 Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
1828 CHECK_EQ(56, thirteen->Int32Value());
1829 CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
1830 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
1831 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
1832 CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
1833 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
1834 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
1835 CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
1836 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
1837 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
1838}
1839
1840
1841THREADED_TEST(PropertyAttributes) {
1842 v8::HandleScope scope;
1843 LocalContext context;
1844 // read-only
1845 Local<String> prop = v8_str("read_only");
1846 context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
1847 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1848 Script::Compile(v8_str("read_only = 9"))->Run();
1849 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1850 context->Global()->Set(prop, v8_num(10));
1851 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1852 // dont-delete
1853 prop = v8_str("dont_delete");
1854 context->Global()->Set(prop, v8_num(13), v8::DontDelete);
1855 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
1856 Script::Compile(v8_str("delete dont_delete"))->Run();
1857 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
1858}
1859
1860
1861THREADED_TEST(Array) {
1862 v8::HandleScope scope;
1863 LocalContext context;
1864 Local<v8::Array> array = v8::Array::New();
1865 CHECK_EQ(0, array->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01001866 CHECK(array->Get(0)->IsUndefined());
Steve Blocka7e24c12009-10-30 11:49:00 +00001867 CHECK(!array->Has(0));
Steve Block6ded16b2010-05-10 14:33:55 +01001868 CHECK(array->Get(100)->IsUndefined());
Steve Blocka7e24c12009-10-30 11:49:00 +00001869 CHECK(!array->Has(100));
Steve Block6ded16b2010-05-10 14:33:55 +01001870 array->Set(2, v8_num(7));
Steve Blocka7e24c12009-10-30 11:49:00 +00001871 CHECK_EQ(3, array->Length());
1872 CHECK(!array->Has(0));
1873 CHECK(!array->Has(1));
1874 CHECK(array->Has(2));
Steve Block6ded16b2010-05-10 14:33:55 +01001875 CHECK_EQ(7, array->Get(2)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00001876 Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
Steve Block6ded16b2010-05-10 14:33:55 +01001877 Local<v8::Array> arr = obj.As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00001878 CHECK_EQ(3, arr->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01001879 CHECK_EQ(1, arr->Get(0)->Int32Value());
1880 CHECK_EQ(2, arr->Get(1)->Int32Value());
1881 CHECK_EQ(3, arr->Get(2)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00001882}
1883
1884
1885v8::Handle<Value> HandleF(const v8::Arguments& args) {
1886 v8::HandleScope scope;
1887 ApiTestFuzzer::Fuzz();
1888 Local<v8::Array> result = v8::Array::New(args.Length());
1889 for (int i = 0; i < args.Length(); i++)
Steve Block6ded16b2010-05-10 14:33:55 +01001890 result->Set(i, args[i]);
Steve Blocka7e24c12009-10-30 11:49:00 +00001891 return scope.Close(result);
1892}
1893
1894
1895THREADED_TEST(Vector) {
1896 v8::HandleScope scope;
1897 Local<ObjectTemplate> global = ObjectTemplate::New();
1898 global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
1899 LocalContext context(0, global);
1900
1901 const char* fun = "f()";
Steve Block6ded16b2010-05-10 14:33:55 +01001902 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00001903 CHECK_EQ(0, a0->Length());
1904
1905 const char* fun2 = "f(11)";
Steve Block6ded16b2010-05-10 14:33:55 +01001906 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00001907 CHECK_EQ(1, a1->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01001908 CHECK_EQ(11, a1->Get(0)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00001909
1910 const char* fun3 = "f(12, 13)";
Steve Block6ded16b2010-05-10 14:33:55 +01001911 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00001912 CHECK_EQ(2, a2->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01001913 CHECK_EQ(12, a2->Get(0)->Int32Value());
1914 CHECK_EQ(13, a2->Get(1)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00001915
1916 const char* fun4 = "f(14, 15, 16)";
Steve Block6ded16b2010-05-10 14:33:55 +01001917 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00001918 CHECK_EQ(3, a3->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01001919 CHECK_EQ(14, a3->Get(0)->Int32Value());
1920 CHECK_EQ(15, a3->Get(1)->Int32Value());
1921 CHECK_EQ(16, a3->Get(2)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00001922
1923 const char* fun5 = "f(17, 18, 19, 20)";
Steve Block6ded16b2010-05-10 14:33:55 +01001924 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00001925 CHECK_EQ(4, a4->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01001926 CHECK_EQ(17, a4->Get(0)->Int32Value());
1927 CHECK_EQ(18, a4->Get(1)->Int32Value());
1928 CHECK_EQ(19, a4->Get(2)->Int32Value());
1929 CHECK_EQ(20, a4->Get(3)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00001930}
1931
1932
1933THREADED_TEST(FunctionCall) {
1934 v8::HandleScope scope;
1935 LocalContext context;
1936 CompileRun(
1937 "function Foo() {"
1938 " var result = [];"
1939 " for (var i = 0; i < arguments.length; i++) {"
1940 " result.push(arguments[i]);"
1941 " }"
1942 " return result;"
1943 "}");
1944 Local<Function> Foo =
1945 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
1946
1947 v8::Handle<Value>* args0 = NULL;
1948 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
1949 CHECK_EQ(0, a0->Length());
1950
1951 v8::Handle<Value> args1[] = { v8_num(1.1) };
1952 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
1953 CHECK_EQ(1, a1->Length());
1954 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
1955
1956 v8::Handle<Value> args2[] = { v8_num(2.2),
1957 v8_num(3.3) };
1958 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
1959 CHECK_EQ(2, a2->Length());
1960 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
1961 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
1962
1963 v8::Handle<Value> args3[] = { v8_num(4.4),
1964 v8_num(5.5),
1965 v8_num(6.6) };
1966 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
1967 CHECK_EQ(3, a3->Length());
1968 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
1969 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
1970 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
1971
1972 v8::Handle<Value> args4[] = { v8_num(7.7),
1973 v8_num(8.8),
1974 v8_num(9.9),
1975 v8_num(10.11) };
1976 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
1977 CHECK_EQ(4, a4->Length());
1978 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
1979 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
1980 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
1981 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
1982}
1983
1984
1985static const char* js_code_causing_out_of_memory =
1986 "var a = new Array(); while(true) a.push(a);";
1987
1988
1989// These tests run for a long time and prevent us from running tests
1990// that come after them so they cannot run in parallel.
1991TEST(OutOfMemory) {
1992 // It's not possible to read a snapshot into a heap with different dimensions.
Steve Block8defd9f2010-07-08 12:39:36 +01001993 if (i::Snapshot::IsEnabled()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00001994 // Set heap limits.
1995 static const int K = 1024;
1996 v8::ResourceConstraints constraints;
1997 constraints.set_max_young_space_size(256 * K);
1998 constraints.set_max_old_space_size(4 * K * K);
1999 v8::SetResourceConstraints(&constraints);
2000
2001 // Execute a script that causes out of memory.
2002 v8::HandleScope scope;
2003 LocalContext context;
2004 v8::V8::IgnoreOutOfMemoryException();
2005 Local<Script> script =
2006 Script::Compile(String::New(js_code_causing_out_of_memory));
2007 Local<Value> result = script->Run();
2008
2009 // Check for out of memory state.
2010 CHECK(result.IsEmpty());
2011 CHECK(context->HasOutOfMemoryException());
2012}
2013
2014
2015v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
2016 ApiTestFuzzer::Fuzz();
2017
2018 v8::HandleScope scope;
2019 LocalContext context;
2020 Local<Script> script =
2021 Script::Compile(String::New(js_code_causing_out_of_memory));
2022 Local<Value> result = script->Run();
2023
2024 // Check for out of memory state.
2025 CHECK(result.IsEmpty());
2026 CHECK(context->HasOutOfMemoryException());
2027
2028 return result;
2029}
2030
2031
2032TEST(OutOfMemoryNested) {
2033 // It's not possible to read a snapshot into a heap with different dimensions.
Steve Block8defd9f2010-07-08 12:39:36 +01002034 if (i::Snapshot::IsEnabled()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00002035 // Set heap limits.
2036 static const int K = 1024;
2037 v8::ResourceConstraints constraints;
2038 constraints.set_max_young_space_size(256 * K);
2039 constraints.set_max_old_space_size(4 * K * K);
2040 v8::SetResourceConstraints(&constraints);
2041
2042 v8::HandleScope scope;
2043 Local<ObjectTemplate> templ = ObjectTemplate::New();
2044 templ->Set(v8_str("ProvokeOutOfMemory"),
2045 v8::FunctionTemplate::New(ProvokeOutOfMemory));
2046 LocalContext context(0, templ);
2047 v8::V8::IgnoreOutOfMemoryException();
2048 Local<Value> result = CompileRun(
2049 "var thrown = false;"
2050 "try {"
2051 " ProvokeOutOfMemory();"
2052 "} catch (e) {"
2053 " thrown = true;"
2054 "}");
2055 // Check for out of memory state.
2056 CHECK(result.IsEmpty());
2057 CHECK(context->HasOutOfMemoryException());
2058}
2059
2060
2061TEST(HugeConsStringOutOfMemory) {
2062 // It's not possible to read a snapshot into a heap with different dimensions.
Steve Block8defd9f2010-07-08 12:39:36 +01002063 if (i::Snapshot::IsEnabled()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00002064 v8::HandleScope scope;
2065 LocalContext context;
2066 // Set heap limits.
2067 static const int K = 1024;
2068 v8::ResourceConstraints constraints;
2069 constraints.set_max_young_space_size(256 * K);
2070 constraints.set_max_old_space_size(2 * K * K);
2071 v8::SetResourceConstraints(&constraints);
2072
2073 // Execute a script that causes out of memory.
2074 v8::V8::IgnoreOutOfMemoryException();
2075
2076 // Build huge string. This should fail with out of memory exception.
2077 Local<Value> result = CompileRun(
2078 "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
Steve Block3ce2e202009-11-05 08:53:23 +00002079 "for (var i = 0; i < 22; i++) { str = str + str; }");
Steve Blocka7e24c12009-10-30 11:49:00 +00002080
2081 // Check for out of memory state.
2082 CHECK(result.IsEmpty());
2083 CHECK(context->HasOutOfMemoryException());
2084}
2085
2086
2087THREADED_TEST(ConstructCall) {
2088 v8::HandleScope scope;
2089 LocalContext context;
2090 CompileRun(
2091 "function Foo() {"
2092 " var result = [];"
2093 " for (var i = 0; i < arguments.length; i++) {"
2094 " result.push(arguments[i]);"
2095 " }"
2096 " return result;"
2097 "}");
2098 Local<Function> Foo =
2099 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2100
2101 v8::Handle<Value>* args0 = NULL;
2102 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
2103 CHECK_EQ(0, a0->Length());
2104
2105 v8::Handle<Value> args1[] = { v8_num(1.1) };
2106 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
2107 CHECK_EQ(1, a1->Length());
2108 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2109
2110 v8::Handle<Value> args2[] = { v8_num(2.2),
2111 v8_num(3.3) };
2112 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
2113 CHECK_EQ(2, a2->Length());
2114 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2115 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2116
2117 v8::Handle<Value> args3[] = { v8_num(4.4),
2118 v8_num(5.5),
2119 v8_num(6.6) };
2120 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
2121 CHECK_EQ(3, a3->Length());
2122 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2123 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2124 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2125
2126 v8::Handle<Value> args4[] = { v8_num(7.7),
2127 v8_num(8.8),
2128 v8_num(9.9),
2129 v8_num(10.11) };
2130 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
2131 CHECK_EQ(4, a4->Length());
2132 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2133 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2134 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2135 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2136}
2137
2138
2139static void CheckUncle(v8::TryCatch* try_catch) {
2140 CHECK(try_catch->HasCaught());
2141 String::AsciiValue str_value(try_catch->Exception());
2142 CHECK_EQ(*str_value, "uncle?");
2143 try_catch->Reset();
2144}
2145
2146
Steve Block6ded16b2010-05-10 14:33:55 +01002147THREADED_TEST(ConversionNumber) {
2148 v8::HandleScope scope;
2149 LocalContext env;
2150 // Very large number.
2151 CompileRun("var obj = Math.pow(2,32) * 1237;");
2152 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2153 CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
2154 CHECK_EQ(0, obj->ToInt32()->Value());
2155 CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned.
2156 // Large number.
2157 CompileRun("var obj = -1234567890123;");
2158 obj = env->Global()->Get(v8_str("obj"));
2159 CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
2160 CHECK_EQ(-1912276171, obj->ToInt32()->Value());
2161 CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT
2162 // Small positive integer.
2163 CompileRun("var obj = 42;");
2164 obj = env->Global()->Get(v8_str("obj"));
2165 CHECK_EQ(42.0, obj->ToNumber()->Value());
2166 CHECK_EQ(42, obj->ToInt32()->Value());
2167 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
2168 // Negative integer.
2169 CompileRun("var obj = -37;");
2170 obj = env->Global()->Get(v8_str("obj"));
2171 CHECK_EQ(-37.0, obj->ToNumber()->Value());
2172 CHECK_EQ(-37, obj->ToInt32()->Value());
2173 CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT
2174 // Positive non-int32 integer.
2175 CompileRun("var obj = 0x81234567;");
2176 obj = env->Global()->Get(v8_str("obj"));
2177 CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
2178 CHECK_EQ(-2128394905, obj->ToInt32()->Value());
2179 CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT
2180 // Fraction.
2181 CompileRun("var obj = 42.3;");
2182 obj = env->Global()->Get(v8_str("obj"));
2183 CHECK_EQ(42.3, obj->ToNumber()->Value());
2184 CHECK_EQ(42, obj->ToInt32()->Value());
2185 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
2186 // Large negative fraction.
2187 CompileRun("var obj = -5726623061.75;");
2188 obj = env->Global()->Get(v8_str("obj"));
2189 CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
2190 CHECK_EQ(-1431655765, obj->ToInt32()->Value());
2191 CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT
2192}
2193
2194
2195THREADED_TEST(isNumberType) {
2196 v8::HandleScope scope;
2197 LocalContext env;
2198 // Very large number.
2199 CompileRun("var obj = Math.pow(2,32) * 1237;");
2200 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2201 CHECK(!obj->IsInt32());
2202 CHECK(!obj->IsUint32());
2203 // Large negative number.
2204 CompileRun("var obj = -1234567890123;");
2205 obj = env->Global()->Get(v8_str("obj"));
2206 CHECK(!obj->IsInt32());
2207 CHECK(!obj->IsUint32());
2208 // Small positive integer.
2209 CompileRun("var obj = 42;");
2210 obj = env->Global()->Get(v8_str("obj"));
2211 CHECK(obj->IsInt32());
2212 CHECK(obj->IsUint32());
2213 // Negative integer.
2214 CompileRun("var obj = -37;");
2215 obj = env->Global()->Get(v8_str("obj"));
2216 CHECK(obj->IsInt32());
2217 CHECK(!obj->IsUint32());
2218 // Positive non-int32 integer.
2219 CompileRun("var obj = 0x81234567;");
2220 obj = env->Global()->Get(v8_str("obj"));
2221 CHECK(!obj->IsInt32());
2222 CHECK(obj->IsUint32());
2223 // Fraction.
2224 CompileRun("var obj = 42.3;");
2225 obj = env->Global()->Get(v8_str("obj"));
2226 CHECK(!obj->IsInt32());
2227 CHECK(!obj->IsUint32());
2228 // Large negative fraction.
2229 CompileRun("var obj = -5726623061.75;");
2230 obj = env->Global()->Get(v8_str("obj"));
2231 CHECK(!obj->IsInt32());
2232 CHECK(!obj->IsUint32());
2233}
2234
2235
Steve Blocka7e24c12009-10-30 11:49:00 +00002236THREADED_TEST(ConversionException) {
2237 v8::HandleScope scope;
2238 LocalContext env;
2239 CompileRun(
2240 "function TestClass() { };"
2241 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
2242 "var obj = new TestClass();");
2243 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2244
2245 v8::TryCatch try_catch;
2246
2247 Local<Value> to_string_result = obj->ToString();
2248 CHECK(to_string_result.IsEmpty());
2249 CheckUncle(&try_catch);
2250
2251 Local<Value> to_number_result = obj->ToNumber();
2252 CHECK(to_number_result.IsEmpty());
2253 CheckUncle(&try_catch);
2254
2255 Local<Value> to_integer_result = obj->ToInteger();
2256 CHECK(to_integer_result.IsEmpty());
2257 CheckUncle(&try_catch);
2258
2259 Local<Value> to_uint32_result = obj->ToUint32();
2260 CHECK(to_uint32_result.IsEmpty());
2261 CheckUncle(&try_catch);
2262
2263 Local<Value> to_int32_result = obj->ToInt32();
2264 CHECK(to_int32_result.IsEmpty());
2265 CheckUncle(&try_catch);
2266
2267 Local<Value> to_object_result = v8::Undefined()->ToObject();
2268 CHECK(to_object_result.IsEmpty());
2269 CHECK(try_catch.HasCaught());
2270 try_catch.Reset();
2271
2272 int32_t int32_value = obj->Int32Value();
2273 CHECK_EQ(0, int32_value);
2274 CheckUncle(&try_catch);
2275
2276 uint32_t uint32_value = obj->Uint32Value();
2277 CHECK_EQ(0, uint32_value);
2278 CheckUncle(&try_catch);
2279
2280 double number_value = obj->NumberValue();
2281 CHECK_NE(0, IsNaN(number_value));
2282 CheckUncle(&try_catch);
2283
2284 int64_t integer_value = obj->IntegerValue();
2285 CHECK_EQ(0.0, static_cast<double>(integer_value));
2286 CheckUncle(&try_catch);
2287}
2288
2289
2290v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
2291 ApiTestFuzzer::Fuzz();
2292 return v8::ThrowException(v8_str("konto"));
2293}
2294
2295
2296v8::Handle<Value> CCatcher(const v8::Arguments& args) {
2297 if (args.Length() < 1) return v8::Boolean::New(false);
2298 v8::HandleScope scope;
2299 v8::TryCatch try_catch;
2300 Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
2301 CHECK(!try_catch.HasCaught() || result.IsEmpty());
2302 return v8::Boolean::New(try_catch.HasCaught());
2303}
2304
2305
2306THREADED_TEST(APICatch) {
2307 v8::HandleScope scope;
2308 Local<ObjectTemplate> templ = ObjectTemplate::New();
2309 templ->Set(v8_str("ThrowFromC"),
2310 v8::FunctionTemplate::New(ThrowFromC));
2311 LocalContext context(0, templ);
2312 CompileRun(
2313 "var thrown = false;"
2314 "try {"
2315 " ThrowFromC();"
2316 "} catch (e) {"
2317 " thrown = true;"
2318 "}");
2319 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
2320 CHECK(thrown->BooleanValue());
2321}
2322
2323
2324THREADED_TEST(APIThrowTryCatch) {
2325 v8::HandleScope scope;
2326 Local<ObjectTemplate> templ = ObjectTemplate::New();
2327 templ->Set(v8_str("ThrowFromC"),
2328 v8::FunctionTemplate::New(ThrowFromC));
2329 LocalContext context(0, templ);
2330 v8::TryCatch try_catch;
2331 CompileRun("ThrowFromC();");
2332 CHECK(try_catch.HasCaught());
2333}
2334
2335
2336// Test that a try-finally block doesn't shadow a try-catch block
2337// when setting up an external handler.
2338//
2339// BUG(271): Some of the exception propagation does not work on the
2340// ARM simulator because the simulator separates the C++ stack and the
2341// JS stack. This test therefore fails on the simulator. The test is
2342// not threaded to allow the threading tests to run on the simulator.
2343TEST(TryCatchInTryFinally) {
2344 v8::HandleScope scope;
2345 Local<ObjectTemplate> templ = ObjectTemplate::New();
2346 templ->Set(v8_str("CCatcher"),
2347 v8::FunctionTemplate::New(CCatcher));
2348 LocalContext context(0, templ);
2349 Local<Value> result = CompileRun("try {"
2350 " try {"
2351 " CCatcher('throw 7;');"
2352 " } finally {"
2353 " }"
2354 "} catch (e) {"
2355 "}");
2356 CHECK(result->IsTrue());
2357}
2358
2359
Ben Murdochb8e0da22011-05-16 14:20:40 +01002360static void check_reference_error_message(
2361 v8::Handle<v8::Message> message,
2362 v8::Handle<v8::Value> data) {
2363 const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
2364 CHECK(message->Get()->Equals(v8_str(reference_error)));
2365}
2366
2367
2368// Test that overwritten toString methods are not invoked on uncaught
2369// exception formatting. However, they are invoked when performing
2370// normal error string conversions.
2371TEST(APIThrowMessageOverwrittenToString) {
2372 v8::HandleScope scope;
2373 v8::V8::AddMessageListener(check_reference_error_message);
2374 LocalContext context;
2375 CompileRun("ReferenceError.prototype.toString ="
2376 " function() { return 'Whoops' }");
2377 CompileRun("asdf;");
2378 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
2379 CHECK(string->Equals(v8_str("Whoops")));
2380 v8::V8::RemoveMessageListeners(check_message);
2381}
2382
2383
Steve Blocka7e24c12009-10-30 11:49:00 +00002384static void receive_message(v8::Handle<v8::Message> message,
2385 v8::Handle<v8::Value> data) {
2386 message->Get();
2387 message_received = true;
2388}
2389
2390
2391TEST(APIThrowMessage) {
2392 message_received = false;
2393 v8::HandleScope scope;
2394 v8::V8::AddMessageListener(receive_message);
2395 Local<ObjectTemplate> templ = ObjectTemplate::New();
2396 templ->Set(v8_str("ThrowFromC"),
2397 v8::FunctionTemplate::New(ThrowFromC));
2398 LocalContext context(0, templ);
2399 CompileRun("ThrowFromC();");
2400 CHECK(message_received);
2401 v8::V8::RemoveMessageListeners(check_message);
2402}
2403
2404
2405TEST(APIThrowMessageAndVerboseTryCatch) {
2406 message_received = false;
2407 v8::HandleScope scope;
2408 v8::V8::AddMessageListener(receive_message);
2409 Local<ObjectTemplate> templ = ObjectTemplate::New();
2410 templ->Set(v8_str("ThrowFromC"),
2411 v8::FunctionTemplate::New(ThrowFromC));
2412 LocalContext context(0, templ);
2413 v8::TryCatch try_catch;
2414 try_catch.SetVerbose(true);
2415 Local<Value> result = CompileRun("ThrowFromC();");
2416 CHECK(try_catch.HasCaught());
2417 CHECK(result.IsEmpty());
2418 CHECK(message_received);
2419 v8::V8::RemoveMessageListeners(check_message);
2420}
2421
2422
2423THREADED_TEST(ExternalScriptException) {
2424 v8::HandleScope scope;
2425 Local<ObjectTemplate> templ = ObjectTemplate::New();
2426 templ->Set(v8_str("ThrowFromC"),
2427 v8::FunctionTemplate::New(ThrowFromC));
2428 LocalContext context(0, templ);
2429
2430 v8::TryCatch try_catch;
2431 Local<Script> script
2432 = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
2433 Local<Value> result = script->Run();
2434 CHECK(result.IsEmpty());
2435 CHECK(try_catch.HasCaught());
2436 String::AsciiValue exception_value(try_catch.Exception());
2437 CHECK_EQ("konto", *exception_value);
2438}
2439
2440
2441
2442v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
2443 ApiTestFuzzer::Fuzz();
2444 CHECK_EQ(4, args.Length());
2445 int count = args[0]->Int32Value();
2446 int cInterval = args[2]->Int32Value();
2447 if (count == 0) {
2448 return v8::ThrowException(v8_str("FromC"));
2449 } else {
2450 Local<v8::Object> global = Context::GetCurrent()->Global();
2451 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
2452 v8::Handle<Value> argv[] = { v8_num(count - 1),
2453 args[1],
2454 args[2],
2455 args[3] };
2456 if (count % cInterval == 0) {
2457 v8::TryCatch try_catch;
Steve Block6ded16b2010-05-10 14:33:55 +01002458 Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
Steve Blocka7e24c12009-10-30 11:49:00 +00002459 int expected = args[3]->Int32Value();
2460 if (try_catch.HasCaught()) {
2461 CHECK_EQ(expected, count);
2462 CHECK(result.IsEmpty());
2463 CHECK(!i::Top::has_scheduled_exception());
2464 } else {
2465 CHECK_NE(expected, count);
2466 }
2467 return result;
2468 } else {
Steve Block6ded16b2010-05-10 14:33:55 +01002469 return fun.As<Function>()->Call(global, 4, argv);
Steve Blocka7e24c12009-10-30 11:49:00 +00002470 }
2471 }
2472}
2473
2474
2475v8::Handle<Value> JSCheck(const v8::Arguments& args) {
2476 ApiTestFuzzer::Fuzz();
2477 CHECK_EQ(3, args.Length());
2478 bool equality = args[0]->BooleanValue();
2479 int count = args[1]->Int32Value();
2480 int expected = args[2]->Int32Value();
2481 if (equality) {
2482 CHECK_EQ(count, expected);
2483 } else {
2484 CHECK_NE(count, expected);
2485 }
2486 return v8::Undefined();
2487}
2488
2489
2490THREADED_TEST(EvalInTryFinally) {
2491 v8::HandleScope scope;
2492 LocalContext context;
2493 v8::TryCatch try_catch;
2494 CompileRun("(function() {"
2495 " try {"
2496 " eval('asldkf (*&^&*^');"
2497 " } finally {"
2498 " return;"
2499 " }"
2500 "})()");
2501 CHECK(!try_catch.HasCaught());
2502}
2503
2504
2505// This test works by making a stack of alternating JavaScript and C
2506// activations. These activations set up exception handlers with regular
2507// intervals, one interval for C activations and another for JavaScript
2508// activations. When enough activations have been created an exception is
2509// thrown and we check that the right activation catches the exception and that
2510// no other activations do. The right activation is always the topmost one with
2511// a handler, regardless of whether it is in JavaScript or C.
2512//
2513// The notation used to describe a test case looks like this:
2514//
2515// *JS[4] *C[3] @JS[2] C[1] JS[0]
2516//
2517// Each entry is an activation, either JS or C. The index is the count at that
2518// level. Stars identify activations with exception handlers, the @ identifies
2519// the exception handler that should catch the exception.
2520//
2521// BUG(271): Some of the exception propagation does not work on the
2522// ARM simulator because the simulator separates the C++ stack and the
2523// JS stack. This test therefore fails on the simulator. The test is
2524// not threaded to allow the threading tests to run on the simulator.
2525TEST(ExceptionOrder) {
2526 v8::HandleScope scope;
2527 Local<ObjectTemplate> templ = ObjectTemplate::New();
2528 templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
2529 templ->Set(v8_str("CThrowCountDown"),
2530 v8::FunctionTemplate::New(CThrowCountDown));
2531 LocalContext context(0, templ);
2532 CompileRun(
2533 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
2534 " if (count == 0) throw 'FromJS';"
2535 " if (count % jsInterval == 0) {"
2536 " try {"
2537 " var value = CThrowCountDown(count - 1,"
2538 " jsInterval,"
2539 " cInterval,"
2540 " expected);"
2541 " check(false, count, expected);"
2542 " return value;"
2543 " } catch (e) {"
2544 " check(true, count, expected);"
2545 " }"
2546 " } else {"
2547 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
2548 " }"
2549 "}");
2550 Local<Function> fun =
2551 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
2552
2553 const int argc = 4;
2554 // count jsInterval cInterval expected
2555
2556 // *JS[4] *C[3] @JS[2] C[1] JS[0]
2557 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
2558 fun->Call(fun, argc, a0);
2559
2560 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
2561 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
2562 fun->Call(fun, argc, a1);
2563
2564 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
2565 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
2566 fun->Call(fun, argc, a2);
2567
2568 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
2569 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
2570 fun->Call(fun, argc, a3);
2571
2572 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
2573 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
2574 fun->Call(fun, argc, a4);
2575
2576 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
2577 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
2578 fun->Call(fun, argc, a5);
2579}
2580
2581
2582v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
2583 ApiTestFuzzer::Fuzz();
2584 CHECK_EQ(1, args.Length());
2585 return v8::ThrowException(args[0]);
2586}
2587
2588
2589THREADED_TEST(ThrowValues) {
2590 v8::HandleScope scope;
2591 Local<ObjectTemplate> templ = ObjectTemplate::New();
2592 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
2593 LocalContext context(0, templ);
2594 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
2595 "function Run(obj) {"
2596 " try {"
2597 " Throw(obj);"
2598 " } catch (e) {"
2599 " return e;"
2600 " }"
2601 " return 'no exception';"
2602 "}"
2603 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
2604 CHECK_EQ(5, result->Length());
2605 CHECK(result->Get(v8::Integer::New(0))->IsString());
2606 CHECK(result->Get(v8::Integer::New(1))->IsNumber());
2607 CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
2608 CHECK(result->Get(v8::Integer::New(2))->IsNumber());
2609 CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
2610 CHECK(result->Get(v8::Integer::New(3))->IsNull());
2611 CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
2612}
2613
2614
2615THREADED_TEST(CatchZero) {
2616 v8::HandleScope scope;
2617 LocalContext context;
2618 v8::TryCatch try_catch;
2619 CHECK(!try_catch.HasCaught());
2620 Script::Compile(v8_str("throw 10"))->Run();
2621 CHECK(try_catch.HasCaught());
2622 CHECK_EQ(10, try_catch.Exception()->Int32Value());
2623 try_catch.Reset();
2624 CHECK(!try_catch.HasCaught());
2625 Script::Compile(v8_str("throw 0"))->Run();
2626 CHECK(try_catch.HasCaught());
2627 CHECK_EQ(0, try_catch.Exception()->Int32Value());
2628}
2629
2630
2631THREADED_TEST(CatchExceptionFromWith) {
2632 v8::HandleScope scope;
2633 LocalContext context;
2634 v8::TryCatch try_catch;
2635 CHECK(!try_catch.HasCaught());
2636 Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
2637 CHECK(try_catch.HasCaught());
2638}
2639
2640
2641THREADED_TEST(Equality) {
2642 v8::HandleScope scope;
2643 LocalContext context;
2644 // Check that equality works at all before relying on CHECK_EQ
2645 CHECK(v8_str("a")->Equals(v8_str("a")));
2646 CHECK(!v8_str("a")->Equals(v8_str("b")));
2647
2648 CHECK_EQ(v8_str("a"), v8_str("a"));
2649 CHECK_NE(v8_str("a"), v8_str("b"));
2650 CHECK_EQ(v8_num(1), v8_num(1));
2651 CHECK_EQ(v8_num(1.00), v8_num(1));
2652 CHECK_NE(v8_num(1), v8_num(2));
2653
2654 // Assume String is not symbol.
2655 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
2656 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
2657 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
2658 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
2659 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
2660 CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
2661 Local<Value> not_a_number = v8_num(i::OS::nan_value());
2662 CHECK(!not_a_number->StrictEquals(not_a_number));
2663 CHECK(v8::False()->StrictEquals(v8::False()));
2664 CHECK(!v8::False()->StrictEquals(v8::Undefined()));
2665
2666 v8::Handle<v8::Object> obj = v8::Object::New();
2667 v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
2668 CHECK(alias->StrictEquals(obj));
2669 alias.Dispose();
2670}
2671
2672
2673THREADED_TEST(MultiRun) {
2674 v8::HandleScope scope;
2675 LocalContext context;
2676 Local<Script> script = Script::Compile(v8_str("x"));
2677 for (int i = 0; i < 10; i++)
2678 script->Run();
2679}
2680
2681
2682static v8::Handle<Value> GetXValue(Local<String> name,
2683 const AccessorInfo& info) {
2684 ApiTestFuzzer::Fuzz();
2685 CHECK_EQ(info.Data(), v8_str("donut"));
2686 CHECK_EQ(name, v8_str("x"));
2687 return name;
2688}
2689
2690
2691THREADED_TEST(SimplePropertyRead) {
2692 v8::HandleScope scope;
2693 Local<ObjectTemplate> templ = ObjectTemplate::New();
2694 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2695 LocalContext context;
2696 context->Global()->Set(v8_str("obj"), templ->NewInstance());
2697 Local<Script> script = Script::Compile(v8_str("obj.x"));
2698 for (int i = 0; i < 10; i++) {
2699 Local<Value> result = script->Run();
2700 CHECK_EQ(result, v8_str("x"));
2701 }
2702}
2703
Andrei Popescu31002712010-02-23 13:46:05 +00002704THREADED_TEST(DefinePropertyOnAPIAccessor) {
2705 v8::HandleScope scope;
2706 Local<ObjectTemplate> templ = ObjectTemplate::New();
2707 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2708 LocalContext context;
2709 context->Global()->Set(v8_str("obj"), templ->NewInstance());
2710
2711 // Uses getOwnPropertyDescriptor to check the configurable status
2712 Local<Script> script_desc
Leon Clarkef7060e22010-06-03 12:02:55 +01002713 = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
Andrei Popescu31002712010-02-23 13:46:05 +00002714 "obj, 'x');"
2715 "prop.configurable;"));
2716 Local<Value> result = script_desc->Run();
2717 CHECK_EQ(result->BooleanValue(), true);
2718
2719 // Redefine get - but still configurable
2720 Local<Script> script_define
2721 = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
2722 " configurable: true };"
2723 "Object.defineProperty(obj, 'x', desc);"
2724 "obj.x"));
2725 result = script_define->Run();
2726 CHECK_EQ(result, v8_num(42));
2727
2728 // Check that the accessor is still configurable
2729 result = script_desc->Run();
2730 CHECK_EQ(result->BooleanValue(), true);
2731
2732 // Redefine to a non-configurable
2733 script_define
2734 = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
2735 " configurable: false };"
2736 "Object.defineProperty(obj, 'x', desc);"
2737 "obj.x"));
2738 result = script_define->Run();
2739 CHECK_EQ(result, v8_num(43));
2740 result = script_desc->Run();
2741 CHECK_EQ(result->BooleanValue(), false);
2742
2743 // Make sure that it is not possible to redefine again
2744 v8::TryCatch try_catch;
2745 result = script_define->Run();
2746 CHECK(try_catch.HasCaught());
2747 String::AsciiValue exception_value(try_catch.Exception());
2748 CHECK_EQ(*exception_value,
2749 "TypeError: Cannot redefine property: defineProperty");
2750}
2751
2752THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
2753 v8::HandleScope scope;
2754 Local<ObjectTemplate> templ = ObjectTemplate::New();
2755 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2756 LocalContext context;
2757 context->Global()->Set(v8_str("obj"), templ->NewInstance());
2758
2759 Local<Script> script_desc = Script::Compile(v8_str("var prop ="
2760 "Object.getOwnPropertyDescriptor( "
2761 "obj, 'x');"
2762 "prop.configurable;"));
2763 Local<Value> result = script_desc->Run();
2764 CHECK_EQ(result->BooleanValue(), true);
2765
2766 Local<Script> script_define =
2767 Script::Compile(v8_str("var desc = {get: function(){return 42; },"
2768 " configurable: true };"
2769 "Object.defineProperty(obj, 'x', desc);"
2770 "obj.x"));
2771 result = script_define->Run();
2772 CHECK_EQ(result, v8_num(42));
2773
2774
2775 result = script_desc->Run();
2776 CHECK_EQ(result->BooleanValue(), true);
2777
2778
2779 script_define =
2780 Script::Compile(v8_str("var desc = {get: function(){return 43; },"
2781 " configurable: false };"
2782 "Object.defineProperty(obj, 'x', desc);"
2783 "obj.x"));
2784 result = script_define->Run();
2785 CHECK_EQ(result, v8_num(43));
2786 result = script_desc->Run();
2787
2788 CHECK_EQ(result->BooleanValue(), false);
2789
2790 v8::TryCatch try_catch;
2791 result = script_define->Run();
2792 CHECK(try_catch.HasCaught());
2793 String::AsciiValue exception_value(try_catch.Exception());
2794 CHECK_EQ(*exception_value,
2795 "TypeError: Cannot redefine property: defineProperty");
2796}
2797
2798
Leon Clarkef7060e22010-06-03 12:02:55 +01002799static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
2800 char const* name) {
2801 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
2802}
Andrei Popescu31002712010-02-23 13:46:05 +00002803
2804
Leon Clarkef7060e22010-06-03 12:02:55 +01002805THREADED_TEST(DefineAPIAccessorOnObject) {
2806 v8::HandleScope scope;
2807 Local<ObjectTemplate> templ = ObjectTemplate::New();
2808 LocalContext context;
2809
2810 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
2811 CompileRun("var obj2 = {};");
2812
2813 CHECK(CompileRun("obj1.x")->IsUndefined());
2814 CHECK(CompileRun("obj2.x")->IsUndefined());
2815
2816 CHECK(GetGlobalProperty(&context, "obj1")->
2817 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2818
2819 ExpectString("obj1.x", "x");
2820 CHECK(CompileRun("obj2.x")->IsUndefined());
2821
2822 CHECK(GetGlobalProperty(&context, "obj2")->
2823 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2824
2825 ExpectString("obj1.x", "x");
2826 ExpectString("obj2.x", "x");
2827
2828 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2829 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2830
2831 CompileRun("Object.defineProperty(obj1, 'x',"
2832 "{ get: function() { return 'y'; }, configurable: true })");
2833
2834 ExpectString("obj1.x", "y");
2835 ExpectString("obj2.x", "x");
2836
2837 CompileRun("Object.defineProperty(obj2, 'x',"
2838 "{ get: function() { return 'y'; }, configurable: true })");
2839
2840 ExpectString("obj1.x", "y");
2841 ExpectString("obj2.x", "y");
2842
2843 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2844 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2845
2846 CHECK(GetGlobalProperty(&context, "obj1")->
2847 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2848 CHECK(GetGlobalProperty(&context, "obj2")->
2849 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2850
2851 ExpectString("obj1.x", "x");
2852 ExpectString("obj2.x", "x");
2853
2854 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2855 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2856
2857 // Define getters/setters, but now make them not configurable.
2858 CompileRun("Object.defineProperty(obj1, 'x',"
2859 "{ get: function() { return 'z'; }, configurable: false })");
2860 CompileRun("Object.defineProperty(obj2, 'x',"
2861 "{ get: function() { return 'z'; }, configurable: false })");
2862
2863 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2864 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2865
2866 ExpectString("obj1.x", "z");
2867 ExpectString("obj2.x", "z");
2868
2869 CHECK(!GetGlobalProperty(&context, "obj1")->
2870 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2871 CHECK(!GetGlobalProperty(&context, "obj2")->
2872 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2873
2874 ExpectString("obj1.x", "z");
2875 ExpectString("obj2.x", "z");
2876}
2877
2878
2879THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
2880 v8::HandleScope scope;
2881 Local<ObjectTemplate> templ = ObjectTemplate::New();
2882 LocalContext context;
2883
2884 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
2885 CompileRun("var obj2 = {};");
2886
2887 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
2888 v8_str("x"),
2889 GetXValue, NULL,
2890 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
2891 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
2892 v8_str("x"),
2893 GetXValue, NULL,
2894 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
2895
2896 ExpectString("obj1.x", "x");
2897 ExpectString("obj2.x", "x");
2898
2899 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2900 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2901
2902 CHECK(!GetGlobalProperty(&context, "obj1")->
2903 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2904 CHECK(!GetGlobalProperty(&context, "obj2")->
2905 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2906
2907 {
2908 v8::TryCatch try_catch;
2909 CompileRun("Object.defineProperty(obj1, 'x',"
2910 "{get: function() { return 'func'; }})");
2911 CHECK(try_catch.HasCaught());
2912 String::AsciiValue exception_value(try_catch.Exception());
2913 CHECK_EQ(*exception_value,
2914 "TypeError: Cannot redefine property: defineProperty");
2915 }
2916 {
2917 v8::TryCatch try_catch;
2918 CompileRun("Object.defineProperty(obj2, 'x',"
2919 "{get: function() { return 'func'; }})");
2920 CHECK(try_catch.HasCaught());
2921 String::AsciiValue exception_value(try_catch.Exception());
2922 CHECK_EQ(*exception_value,
2923 "TypeError: Cannot redefine property: defineProperty");
2924 }
2925}
2926
2927
2928static v8::Handle<Value> Get239Value(Local<String> name,
2929 const AccessorInfo& info) {
2930 ApiTestFuzzer::Fuzz();
2931 CHECK_EQ(info.Data(), v8_str("donut"));
2932 CHECK_EQ(name, v8_str("239"));
2933 return name;
2934}
2935
2936
2937THREADED_TEST(ElementAPIAccessor) {
2938 v8::HandleScope scope;
2939 Local<ObjectTemplate> templ = ObjectTemplate::New();
2940 LocalContext context;
2941
2942 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
2943 CompileRun("var obj2 = {};");
2944
2945 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
2946 v8_str("239"),
2947 Get239Value, NULL,
2948 v8_str("donut")));
2949 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
2950 v8_str("239"),
2951 Get239Value, NULL,
2952 v8_str("donut")));
2953
2954 ExpectString("obj1[239]", "239");
2955 ExpectString("obj2[239]", "239");
2956 ExpectString("obj1['239']", "239");
2957 ExpectString("obj2['239']", "239");
2958}
2959
Steve Blocka7e24c12009-10-30 11:49:00 +00002960
2961v8::Persistent<Value> xValue;
2962
2963
2964static void SetXValue(Local<String> name,
2965 Local<Value> value,
2966 const AccessorInfo& info) {
2967 CHECK_EQ(value, v8_num(4));
2968 CHECK_EQ(info.Data(), v8_str("donut"));
2969 CHECK_EQ(name, v8_str("x"));
2970 CHECK(xValue.IsEmpty());
2971 xValue = v8::Persistent<Value>::New(value);
2972}
2973
2974
2975THREADED_TEST(SimplePropertyWrite) {
2976 v8::HandleScope scope;
2977 Local<ObjectTemplate> templ = ObjectTemplate::New();
2978 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
2979 LocalContext context;
2980 context->Global()->Set(v8_str("obj"), templ->NewInstance());
2981 Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
2982 for (int i = 0; i < 10; i++) {
2983 CHECK(xValue.IsEmpty());
2984 script->Run();
2985 CHECK_EQ(v8_num(4), xValue);
2986 xValue.Dispose();
2987 xValue = v8::Persistent<Value>();
2988 }
2989}
2990
2991
2992static v8::Handle<Value> XPropertyGetter(Local<String> property,
2993 const AccessorInfo& info) {
2994 ApiTestFuzzer::Fuzz();
2995 CHECK(info.Data()->IsUndefined());
2996 return property;
2997}
2998
2999
3000THREADED_TEST(NamedInterceptorPropertyRead) {
3001 v8::HandleScope scope;
3002 Local<ObjectTemplate> templ = ObjectTemplate::New();
3003 templ->SetNamedPropertyHandler(XPropertyGetter);
3004 LocalContext context;
3005 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3006 Local<Script> script = Script::Compile(v8_str("obj.x"));
3007 for (int i = 0; i < 10; i++) {
3008 Local<Value> result = script->Run();
3009 CHECK_EQ(result, v8_str("x"));
3010 }
3011}
3012
3013
Steve Block6ded16b2010-05-10 14:33:55 +01003014THREADED_TEST(NamedInterceptorDictionaryIC) {
3015 v8::HandleScope scope;
3016 Local<ObjectTemplate> templ = ObjectTemplate::New();
3017 templ->SetNamedPropertyHandler(XPropertyGetter);
3018 LocalContext context;
3019 // Create an object with a named interceptor.
3020 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
3021 Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
3022 for (int i = 0; i < 10; i++) {
3023 Local<Value> result = script->Run();
3024 CHECK_EQ(result, v8_str("x"));
3025 }
3026 // Create a slow case object and a function accessing a property in
3027 // that slow case object (with dictionary probing in generated
3028 // code). Then force object with a named interceptor into slow-case,
3029 // pass it to the function, and check that the interceptor is called
3030 // instead of accessing the local property.
3031 Local<Value> result =
3032 CompileRun("function get_x(o) { return o.x; };"
3033 "var obj = { x : 42, y : 0 };"
3034 "delete obj.y;"
3035 "for (var i = 0; i < 10; i++) get_x(obj);"
3036 "interceptor_obj.x = 42;"
3037 "interceptor_obj.y = 10;"
3038 "delete interceptor_obj.y;"
3039 "get_x(interceptor_obj)");
3040 CHECK_EQ(result, v8_str("x"));
3041}
3042
3043
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003044THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
3045 v8::HandleScope scope;
3046
3047 v8::Persistent<Context> context1 = Context::New();
3048
3049 context1->Enter();
3050 Local<ObjectTemplate> templ = ObjectTemplate::New();
3051 templ->SetNamedPropertyHandler(XPropertyGetter);
3052 // Create an object with a named interceptor.
3053 v8::Local<v8::Object> object = templ->NewInstance();
3054 context1->Global()->Set(v8_str("interceptor_obj"), object);
3055
3056 // Force the object into the slow case.
3057 CompileRun("interceptor_obj.y = 0;"
3058 "delete interceptor_obj.y;");
3059 context1->Exit();
3060
3061 {
3062 // Introduce the object into a different context.
3063 // Repeat named loads to exercise ICs.
3064 LocalContext context2;
3065 context2->Global()->Set(v8_str("interceptor_obj"), object);
3066 Local<Value> result =
3067 CompileRun("function get_x(o) { return o.x; }"
3068 "interceptor_obj.x = 42;"
3069 "for (var i=0; i != 10; i++) {"
3070 " get_x(interceptor_obj);"
3071 "}"
3072 "get_x(interceptor_obj)");
3073 // Check that the interceptor was actually invoked.
3074 CHECK_EQ(result, v8_str("x"));
3075 }
3076
3077 // Return to the original context and force some object to the slow case
3078 // to cause the NormalizedMapCache to verify.
3079 context1->Enter();
3080 CompileRun("var obj = { x : 0 }; delete obj.x;");
3081 context1->Exit();
3082
3083 context1.Dispose();
3084}
3085
3086
Andrei Popescu402d9372010-02-26 13:31:12 +00003087static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
3088 const AccessorInfo& info) {
3089 // Set x on the prototype object and do not handle the get request.
3090 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
Steve Block6ded16b2010-05-10 14:33:55 +01003091 proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
Andrei Popescu402d9372010-02-26 13:31:12 +00003092 return v8::Handle<Value>();
3093}
3094
3095
3096// This is a regression test for http://crbug.com/20104. Map
3097// transitions should not interfere with post interceptor lookup.
3098THREADED_TEST(NamedInterceptorMapTransitionRead) {
3099 v8::HandleScope scope;
3100 Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
3101 Local<v8::ObjectTemplate> instance_template
3102 = function_template->InstanceTemplate();
3103 instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
3104 LocalContext context;
3105 context->Global()->Set(v8_str("F"), function_template->GetFunction());
3106 // Create an instance of F and introduce a map transition for x.
3107 CompileRun("var o = new F(); o.x = 23;");
3108 // Create an instance of F and invoke the getter. The result should be 23.
3109 Local<Value> result = CompileRun("o = new F(); o.x");
3110 CHECK_EQ(result->Int32Value(), 23);
3111}
3112
3113
Steve Blocka7e24c12009-10-30 11:49:00 +00003114static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
3115 const AccessorInfo& info) {
3116 ApiTestFuzzer::Fuzz();
3117 if (index == 37) {
3118 return v8::Handle<Value>(v8_num(625));
3119 }
3120 return v8::Handle<Value>();
3121}
3122
3123
3124static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
3125 Local<Value> value,
3126 const AccessorInfo& info) {
3127 ApiTestFuzzer::Fuzz();
3128 if (index == 39) {
3129 return value;
3130 }
3131 return v8::Handle<Value>();
3132}
3133
3134
3135THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
3136 v8::HandleScope scope;
3137 Local<ObjectTemplate> templ = ObjectTemplate::New();
3138 templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
3139 IndexedPropertySetter);
3140 LocalContext context;
3141 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3142 Local<Script> getter_script = Script::Compile(v8_str(
3143 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
3144 Local<Script> setter_script = Script::Compile(v8_str(
3145 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
3146 "obj[17] = 23;"
3147 "obj.foo;"));
3148 Local<Script> interceptor_setter_script = Script::Compile(v8_str(
3149 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
3150 "obj[39] = 47;"
3151 "obj.foo;")); // This setter should not run, due to the interceptor.
3152 Local<Script> interceptor_getter_script = Script::Compile(v8_str(
3153 "obj[37];"));
3154 Local<Value> result = getter_script->Run();
3155 CHECK_EQ(v8_num(5), result);
3156 result = setter_script->Run();
3157 CHECK_EQ(v8_num(23), result);
3158 result = interceptor_setter_script->Run();
3159 CHECK_EQ(v8_num(23), result);
3160 result = interceptor_getter_script->Run();
3161 CHECK_EQ(v8_num(625), result);
3162}
3163
3164
Leon Clarked91b9f72010-01-27 17:25:45 +00003165static v8::Handle<Value> IdentityIndexedPropertyGetter(
3166 uint32_t index,
3167 const AccessorInfo& info) {
Ben Murdochf87a2032010-10-22 12:50:53 +01003168 return v8::Integer::NewFromUnsigned(index);
Leon Clarked91b9f72010-01-27 17:25:45 +00003169}
3170
3171
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003172THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
3173 v8::HandleScope scope;
3174 Local<ObjectTemplate> templ = ObjectTemplate::New();
3175 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3176
3177 LocalContext context;
3178 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3179
3180 // Check fast object case.
3181 const char* fast_case_code =
3182 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
3183 ExpectString(fast_case_code, "0");
3184
3185 // Check slow case.
3186 const char* slow_case_code =
3187 "obj.x = 1; delete obj.x;"
3188 "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
3189 ExpectString(slow_case_code, "1");
3190}
3191
3192
Leon Clarked91b9f72010-01-27 17:25:45 +00003193THREADED_TEST(IndexedInterceptorWithNoSetter) {
3194 v8::HandleScope scope;
3195 Local<ObjectTemplate> templ = ObjectTemplate::New();
3196 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3197
3198 LocalContext context;
3199 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3200
3201 const char* code =
3202 "try {"
3203 " obj[0] = 239;"
3204 " for (var i = 0; i < 100; i++) {"
3205 " var v = obj[0];"
3206 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
3207 " }"
3208 " 'PASSED'"
3209 "} catch(e) {"
3210 " e"
3211 "}";
3212 ExpectString(code, "PASSED");
3213}
3214
3215
Andrei Popescu402d9372010-02-26 13:31:12 +00003216THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
3217 v8::HandleScope scope;
3218 Local<ObjectTemplate> templ = ObjectTemplate::New();
3219 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3220
3221 LocalContext context;
3222 Local<v8::Object> obj = templ->NewInstance();
3223 obj->TurnOnAccessCheck();
3224 context->Global()->Set(v8_str("obj"), obj);
3225
3226 const char* code =
3227 "try {"
3228 " for (var i = 0; i < 100; i++) {"
3229 " var v = obj[0];"
3230 " if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
3231 " }"
3232 " 'PASSED'"
3233 "} catch(e) {"
3234 " e"
3235 "}";
3236 ExpectString(code, "PASSED");
3237}
3238
3239
3240THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
3241 i::FLAG_allow_natives_syntax = true;
3242 v8::HandleScope scope;
3243 Local<ObjectTemplate> templ = ObjectTemplate::New();
3244 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3245
3246 LocalContext context;
3247 Local<v8::Object> obj = templ->NewInstance();
3248 context->Global()->Set(v8_str("obj"), obj);
3249
3250 const char* code =
3251 "try {"
3252 " for (var i = 0; i < 100; i++) {"
3253 " var expected = i;"
3254 " if (i == 5) {"
3255 " %EnableAccessChecks(obj);"
3256 " expected = undefined;"
3257 " }"
3258 " var v = obj[i];"
3259 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3260 " if (i == 5) %DisableAccessChecks(obj);"
3261 " }"
3262 " 'PASSED'"
3263 "} catch(e) {"
3264 " e"
3265 "}";
3266 ExpectString(code, "PASSED");
3267}
3268
3269
3270THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
3271 v8::HandleScope scope;
3272 Local<ObjectTemplate> templ = ObjectTemplate::New();
3273 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3274
3275 LocalContext context;
3276 Local<v8::Object> obj = templ->NewInstance();
3277 context->Global()->Set(v8_str("obj"), obj);
3278
3279 const char* code =
3280 "try {"
3281 " for (var i = 0; i < 100; i++) {"
3282 " var v = obj[i];"
3283 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
3284 " }"
3285 " 'PASSED'"
3286 "} catch(e) {"
3287 " e"
3288 "}";
3289 ExpectString(code, "PASSED");
3290}
3291
3292
Ben Murdochf87a2032010-10-22 12:50:53 +01003293THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
3294 v8::HandleScope scope;
3295 Local<ObjectTemplate> templ = ObjectTemplate::New();
3296 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3297
3298 LocalContext context;
3299 Local<v8::Object> obj = templ->NewInstance();
3300 context->Global()->Set(v8_str("obj"), obj);
3301
3302 const char* code =
3303 "try {"
3304 " for (var i = 0; i < 100; i++) {"
3305 " var expected = i;"
3306 " var key = i;"
3307 " if (i == 25) {"
3308 " key = -1;"
3309 " expected = undefined;"
3310 " }"
3311 " if (i == 50) {"
3312 " /* probe minimal Smi number on 32-bit platforms */"
3313 " key = -(1 << 30);"
3314 " expected = undefined;"
3315 " }"
3316 " if (i == 75) {"
3317 " /* probe minimal Smi number on 64-bit platforms */"
3318 " key = 1 << 31;"
3319 " expected = undefined;"
3320 " }"
3321 " var v = obj[key];"
3322 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3323 " }"
3324 " 'PASSED'"
3325 "} catch(e) {"
3326 " e"
3327 "}";
3328 ExpectString(code, "PASSED");
3329}
3330
3331
Andrei Popescu402d9372010-02-26 13:31:12 +00003332THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
3333 v8::HandleScope scope;
3334 Local<ObjectTemplate> templ = ObjectTemplate::New();
3335 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3336
3337 LocalContext context;
3338 Local<v8::Object> obj = templ->NewInstance();
3339 context->Global()->Set(v8_str("obj"), obj);
3340
3341 const char* code =
3342 "try {"
3343 " for (var i = 0; i < 100; i++) {"
3344 " var expected = i;"
Ben Murdochf87a2032010-10-22 12:50:53 +01003345 " var key = i;"
Andrei Popescu402d9372010-02-26 13:31:12 +00003346 " if (i == 50) {"
Ben Murdochf87a2032010-10-22 12:50:53 +01003347 " key = 'foobar';"
Andrei Popescu402d9372010-02-26 13:31:12 +00003348 " expected = undefined;"
3349 " }"
Ben Murdochf87a2032010-10-22 12:50:53 +01003350 " var v = obj[key];"
Andrei Popescu402d9372010-02-26 13:31:12 +00003351 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3352 " }"
3353 " 'PASSED'"
3354 "} catch(e) {"
3355 " e"
3356 "}";
3357 ExpectString(code, "PASSED");
3358}
3359
3360
3361THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
3362 v8::HandleScope scope;
3363 Local<ObjectTemplate> templ = ObjectTemplate::New();
3364 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3365
3366 LocalContext context;
3367 Local<v8::Object> obj = templ->NewInstance();
3368 context->Global()->Set(v8_str("obj"), obj);
3369
3370 const char* code =
3371 "var original = obj;"
3372 "try {"
3373 " for (var i = 0; i < 100; i++) {"
3374 " var expected = i;"
3375 " if (i == 50) {"
3376 " obj = {50: 'foobar'};"
3377 " expected = 'foobar';"
3378 " }"
3379 " var v = obj[i];"
3380 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3381 " if (i == 50) obj = original;"
3382 " }"
3383 " 'PASSED'"
3384 "} catch(e) {"
3385 " e"
3386 "}";
3387 ExpectString(code, "PASSED");
3388}
3389
3390
3391THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
3392 v8::HandleScope scope;
3393 Local<ObjectTemplate> templ = ObjectTemplate::New();
3394 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3395
3396 LocalContext context;
3397 Local<v8::Object> obj = templ->NewInstance();
3398 context->Global()->Set(v8_str("obj"), obj);
3399
3400 const char* code =
3401 "var original = obj;"
3402 "try {"
3403 " for (var i = 0; i < 100; i++) {"
3404 " var expected = i;"
3405 " if (i == 5) {"
3406 " obj = 239;"
3407 " expected = undefined;"
3408 " }"
3409 " var v = obj[i];"
3410 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3411 " if (i == 5) obj = original;"
3412 " }"
3413 " 'PASSED'"
3414 "} catch(e) {"
3415 " e"
3416 "}";
3417 ExpectString(code, "PASSED");
3418}
3419
3420
3421THREADED_TEST(IndexedInterceptorOnProto) {
3422 v8::HandleScope scope;
3423 Local<ObjectTemplate> templ = ObjectTemplate::New();
3424 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3425
3426 LocalContext context;
3427 Local<v8::Object> obj = templ->NewInstance();
3428 context->Global()->Set(v8_str("obj"), obj);
3429
3430 const char* code =
3431 "var o = {__proto__: obj};"
3432 "try {"
3433 " for (var i = 0; i < 100; i++) {"
3434 " var v = o[i];"
3435 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
3436 " }"
3437 " 'PASSED'"
3438 "} catch(e) {"
3439 " e"
3440 "}";
3441 ExpectString(code, "PASSED");
3442}
3443
3444
Steve Blocka7e24c12009-10-30 11:49:00 +00003445THREADED_TEST(MultiContexts) {
3446 v8::HandleScope scope;
3447 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
3448 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
3449
3450 Local<String> password = v8_str("Password");
3451
3452 // Create an environment
3453 LocalContext context0(0, templ);
3454 context0->SetSecurityToken(password);
3455 v8::Handle<v8::Object> global0 = context0->Global();
3456 global0->Set(v8_str("custom"), v8_num(1234));
3457 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
3458
3459 // Create an independent environment
3460 LocalContext context1(0, templ);
3461 context1->SetSecurityToken(password);
3462 v8::Handle<v8::Object> global1 = context1->Global();
3463 global1->Set(v8_str("custom"), v8_num(1234));
3464 CHECK_NE(global0, global1);
3465 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
3466 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
3467
3468 // Now create a new context with the old global
3469 LocalContext context2(0, templ, global1);
3470 context2->SetSecurityToken(password);
3471 v8::Handle<v8::Object> global2 = context2->Global();
3472 CHECK_EQ(global1, global2);
3473 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
3474 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
3475}
3476
3477
3478THREADED_TEST(FunctionPrototypeAcrossContexts) {
3479 // Make sure that functions created by cloning boilerplates cannot
3480 // communicate through their __proto__ field.
3481
3482 v8::HandleScope scope;
3483
3484 LocalContext env0;
3485 v8::Handle<v8::Object> global0 =
3486 env0->Global();
3487 v8::Handle<v8::Object> object0 =
Steve Block6ded16b2010-05-10 14:33:55 +01003488 global0->Get(v8_str("Object")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00003489 v8::Handle<v8::Object> tostring0 =
Steve Block6ded16b2010-05-10 14:33:55 +01003490 object0->Get(v8_str("toString")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00003491 v8::Handle<v8::Object> proto0 =
Steve Block6ded16b2010-05-10 14:33:55 +01003492 tostring0->Get(v8_str("__proto__")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00003493 proto0->Set(v8_str("custom"), v8_num(1234));
3494
3495 LocalContext env1;
3496 v8::Handle<v8::Object> global1 =
3497 env1->Global();
3498 v8::Handle<v8::Object> object1 =
Steve Block6ded16b2010-05-10 14:33:55 +01003499 global1->Get(v8_str("Object")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00003500 v8::Handle<v8::Object> tostring1 =
Steve Block6ded16b2010-05-10 14:33:55 +01003501 object1->Get(v8_str("toString")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00003502 v8::Handle<v8::Object> proto1 =
Steve Block6ded16b2010-05-10 14:33:55 +01003503 tostring1->Get(v8_str("__proto__")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00003504 CHECK(!proto1->Has(v8_str("custom")));
3505}
3506
3507
3508THREADED_TEST(Regress892105) {
3509 // Make sure that object and array literals created by cloning
3510 // boilerplates cannot communicate through their __proto__
3511 // field. This is rather difficult to check, but we try to add stuff
3512 // to Object.prototype and Array.prototype and create a new
3513 // environment. This should succeed.
3514
3515 v8::HandleScope scope;
3516
3517 Local<String> source = v8_str("Object.prototype.obj = 1234;"
3518 "Array.prototype.arr = 4567;"
3519 "8901");
3520
3521 LocalContext env0;
3522 Local<Script> script0 = Script::Compile(source);
3523 CHECK_EQ(8901.0, script0->Run()->NumberValue());
3524
3525 LocalContext env1;
3526 Local<Script> script1 = Script::Compile(source);
3527 CHECK_EQ(8901.0, script1->Run()->NumberValue());
3528}
3529
3530
Steve Blocka7e24c12009-10-30 11:49:00 +00003531THREADED_TEST(UndetectableObject) {
3532 v8::HandleScope scope;
3533 LocalContext env;
3534
3535 Local<v8::FunctionTemplate> desc =
3536 v8::FunctionTemplate::New(0, v8::Handle<Value>());
3537 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
3538
3539 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
3540 env->Global()->Set(v8_str("undetectable"), obj);
3541
3542 ExpectString("undetectable.toString()", "[object Object]");
3543 ExpectString("typeof undetectable", "undefined");
3544 ExpectString("typeof(undetectable)", "undefined");
3545 ExpectBoolean("typeof undetectable == 'undefined'", true);
3546 ExpectBoolean("typeof undetectable == 'object'", false);
3547 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
3548 ExpectBoolean("!undetectable", true);
3549
3550 ExpectObject("true&&undetectable", obj);
3551 ExpectBoolean("false&&undetectable", false);
3552 ExpectBoolean("true||undetectable", true);
3553 ExpectObject("false||undetectable", obj);
3554
3555 ExpectObject("undetectable&&true", obj);
3556 ExpectObject("undetectable&&false", obj);
3557 ExpectBoolean("undetectable||true", true);
3558 ExpectBoolean("undetectable||false", false);
3559
3560 ExpectBoolean("undetectable==null", true);
3561 ExpectBoolean("null==undetectable", true);
3562 ExpectBoolean("undetectable==undefined", true);
3563 ExpectBoolean("undefined==undetectable", true);
3564 ExpectBoolean("undetectable==undetectable", true);
3565
3566
3567 ExpectBoolean("undetectable===null", false);
3568 ExpectBoolean("null===undetectable", false);
3569 ExpectBoolean("undetectable===undefined", false);
3570 ExpectBoolean("undefined===undetectable", false);
3571 ExpectBoolean("undetectable===undetectable", true);
3572}
3573
3574
Steve Block8defd9f2010-07-08 12:39:36 +01003575
3576THREADED_TEST(ExtensibleOnUndetectable) {
3577 v8::HandleScope scope;
3578 LocalContext env;
3579
3580 Local<v8::FunctionTemplate> desc =
3581 v8::FunctionTemplate::New(0, v8::Handle<Value>());
3582 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
3583
3584 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
3585 env->Global()->Set(v8_str("undetectable"), obj);
3586
3587 Local<String> source = v8_str("undetectable.x = 42;"
3588 "undetectable.x");
3589
3590 Local<Script> script = Script::Compile(source);
3591
3592 CHECK_EQ(v8::Integer::New(42), script->Run());
3593
3594 ExpectBoolean("Object.isExtensible(undetectable)", true);
3595
3596 source = v8_str("Object.preventExtensions(undetectable);");
3597 script = Script::Compile(source);
3598 script->Run();
3599 ExpectBoolean("Object.isExtensible(undetectable)", false);
3600
3601 source = v8_str("undetectable.y = 2000;");
3602 script = Script::Compile(source);
3603 v8::TryCatch try_catch;
3604 Local<Value> result = script->Run();
3605 CHECK(result.IsEmpty());
3606 CHECK(try_catch.HasCaught());
3607}
3608
3609
3610
Steve Blocka7e24c12009-10-30 11:49:00 +00003611THREADED_TEST(UndetectableString) {
3612 v8::HandleScope scope;
3613 LocalContext env;
3614
3615 Local<String> obj = String::NewUndetectable("foo");
3616 env->Global()->Set(v8_str("undetectable"), obj);
3617
3618 ExpectString("undetectable", "foo");
3619 ExpectString("typeof undetectable", "undefined");
3620 ExpectString("typeof(undetectable)", "undefined");
3621 ExpectBoolean("typeof undetectable == 'undefined'", true);
3622 ExpectBoolean("typeof undetectable == 'string'", false);
3623 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
3624 ExpectBoolean("!undetectable", true);
3625
3626 ExpectObject("true&&undetectable", obj);
3627 ExpectBoolean("false&&undetectable", false);
3628 ExpectBoolean("true||undetectable", true);
3629 ExpectObject("false||undetectable", obj);
3630
3631 ExpectObject("undetectable&&true", obj);
3632 ExpectObject("undetectable&&false", obj);
3633 ExpectBoolean("undetectable||true", true);
3634 ExpectBoolean("undetectable||false", false);
3635
3636 ExpectBoolean("undetectable==null", true);
3637 ExpectBoolean("null==undetectable", true);
3638 ExpectBoolean("undetectable==undefined", true);
3639 ExpectBoolean("undefined==undetectable", true);
3640 ExpectBoolean("undetectable==undetectable", true);
3641
3642
3643 ExpectBoolean("undetectable===null", false);
3644 ExpectBoolean("null===undetectable", false);
3645 ExpectBoolean("undetectable===undefined", false);
3646 ExpectBoolean("undefined===undetectable", false);
3647 ExpectBoolean("undetectable===undetectable", true);
3648}
3649
3650
3651template <typename T> static void USE(T) { }
3652
3653
3654// This test is not intended to be run, just type checked.
3655static void PersistentHandles() {
3656 USE(PersistentHandles);
3657 Local<String> str = v8_str("foo");
3658 v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
3659 USE(p_str);
3660 Local<Script> scr = Script::Compile(v8_str(""));
3661 v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
3662 USE(p_scr);
3663 Local<ObjectTemplate> templ = ObjectTemplate::New();
3664 v8::Persistent<ObjectTemplate> p_templ =
3665 v8::Persistent<ObjectTemplate>::New(templ);
3666 USE(p_templ);
3667}
3668
3669
3670static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
3671 ApiTestFuzzer::Fuzz();
3672 return v8::Undefined();
3673}
3674
3675
3676THREADED_TEST(GlobalObjectTemplate) {
3677 v8::HandleScope handle_scope;
3678 Local<ObjectTemplate> global_template = ObjectTemplate::New();
3679 global_template->Set(v8_str("JSNI_Log"),
3680 v8::FunctionTemplate::New(HandleLogDelegator));
3681 v8::Persistent<Context> context = Context::New(0, global_template);
3682 Context::Scope context_scope(context);
3683 Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
3684 context.Dispose();
3685}
3686
3687
3688static const char* kSimpleExtensionSource =
3689 "function Foo() {"
3690 " return 4;"
3691 "}";
3692
3693
3694THREADED_TEST(SimpleExtensions) {
3695 v8::HandleScope handle_scope;
3696 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
3697 const char* extension_names[] = { "simpletest" };
3698 v8::ExtensionConfiguration extensions(1, extension_names);
3699 v8::Handle<Context> context = Context::New(&extensions);
3700 Context::Scope lock(context);
3701 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
3702 CHECK_EQ(result, v8::Integer::New(4));
3703}
3704
3705
3706static const char* kEvalExtensionSource1 =
3707 "function UseEval1() {"
3708 " var x = 42;"
3709 " return eval('x');"
3710 "}";
3711
3712
3713static const char* kEvalExtensionSource2 =
3714 "(function() {"
3715 " var x = 42;"
3716 " function e() {"
3717 " return eval('x');"
3718 " }"
3719 " this.UseEval2 = e;"
3720 "})()";
3721
3722
3723THREADED_TEST(UseEvalFromExtension) {
3724 v8::HandleScope handle_scope;
3725 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
3726 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
3727 const char* extension_names[] = { "evaltest1", "evaltest2" };
3728 v8::ExtensionConfiguration extensions(2, extension_names);
3729 v8::Handle<Context> context = Context::New(&extensions);
3730 Context::Scope lock(context);
3731 v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
3732 CHECK_EQ(result, v8::Integer::New(42));
3733 result = Script::Compile(v8_str("UseEval2()"))->Run();
3734 CHECK_EQ(result, v8::Integer::New(42));
3735}
3736
3737
3738static const char* kWithExtensionSource1 =
3739 "function UseWith1() {"
3740 " var x = 42;"
3741 " with({x:87}) { return x; }"
3742 "}";
3743
3744
3745
3746static const char* kWithExtensionSource2 =
3747 "(function() {"
3748 " var x = 42;"
3749 " function e() {"
3750 " with ({x:87}) { return x; }"
3751 " }"
3752 " this.UseWith2 = e;"
3753 "})()";
3754
3755
3756THREADED_TEST(UseWithFromExtension) {
3757 v8::HandleScope handle_scope;
3758 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
3759 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
3760 const char* extension_names[] = { "withtest1", "withtest2" };
3761 v8::ExtensionConfiguration extensions(2, extension_names);
3762 v8::Handle<Context> context = Context::New(&extensions);
3763 Context::Scope lock(context);
3764 v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
3765 CHECK_EQ(result, v8::Integer::New(87));
3766 result = Script::Compile(v8_str("UseWith2()"))->Run();
3767 CHECK_EQ(result, v8::Integer::New(87));
3768}
3769
3770
3771THREADED_TEST(AutoExtensions) {
3772 v8::HandleScope handle_scope;
3773 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
3774 extension->set_auto_enable(true);
3775 v8::RegisterExtension(extension);
3776 v8::Handle<Context> context = Context::New();
3777 Context::Scope lock(context);
3778 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
3779 CHECK_EQ(result, v8::Integer::New(4));
3780}
3781
3782
Steve Blockd0582a62009-12-15 09:54:21 +00003783static const char* kSyntaxErrorInExtensionSource =
3784 "[";
3785
3786
3787// Test that a syntax error in an extension does not cause a fatal
3788// error but results in an empty context.
3789THREADED_TEST(SyntaxErrorExtensions) {
3790 v8::HandleScope handle_scope;
3791 v8::RegisterExtension(new Extension("syntaxerror",
3792 kSyntaxErrorInExtensionSource));
3793 const char* extension_names[] = { "syntaxerror" };
3794 v8::ExtensionConfiguration extensions(1, extension_names);
3795 v8::Handle<Context> context = Context::New(&extensions);
3796 CHECK(context.IsEmpty());
3797}
3798
3799
3800static const char* kExceptionInExtensionSource =
3801 "throw 42";
3802
3803
3804// Test that an exception when installing an extension does not cause
3805// a fatal error but results in an empty context.
3806THREADED_TEST(ExceptionExtensions) {
3807 v8::HandleScope handle_scope;
3808 v8::RegisterExtension(new Extension("exception",
3809 kExceptionInExtensionSource));
3810 const char* extension_names[] = { "exception" };
3811 v8::ExtensionConfiguration extensions(1, extension_names);
3812 v8::Handle<Context> context = Context::New(&extensions);
3813 CHECK(context.IsEmpty());
3814}
3815
3816
Iain Merrick9ac36c92010-09-13 15:29:50 +01003817static const char* kNativeCallInExtensionSource =
3818 "function call_runtime_last_index_of(x) {"
3819 " return %StringLastIndexOf(x, 'bob', 10);"
3820 "}";
3821
3822
3823static const char* kNativeCallTest =
3824 "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
3825
3826// Test that a native runtime calls are supported in extensions.
3827THREADED_TEST(NativeCallInExtensions) {
3828 v8::HandleScope handle_scope;
3829 v8::RegisterExtension(new Extension("nativecall",
3830 kNativeCallInExtensionSource));
3831 const char* extension_names[] = { "nativecall" };
3832 v8::ExtensionConfiguration extensions(1, extension_names);
3833 v8::Handle<Context> context = Context::New(&extensions);
3834 Context::Scope lock(context);
3835 v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run();
3836 CHECK_EQ(result, v8::Integer::New(3));
3837}
3838
3839
Steve Blocka7e24c12009-10-30 11:49:00 +00003840static void CheckDependencies(const char* name, const char* expected) {
3841 v8::HandleScope handle_scope;
3842 v8::ExtensionConfiguration config(1, &name);
3843 LocalContext context(&config);
3844 CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
3845}
3846
3847
3848/*
3849 * Configuration:
3850 *
3851 * /-- B <--\
3852 * A <- -- D <-- E
3853 * \-- C <--/
3854 */
3855THREADED_TEST(ExtensionDependency) {
3856 static const char* kEDeps[] = { "D" };
3857 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
3858 static const char* kDDeps[] = { "B", "C" };
3859 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
3860 static const char* kBCDeps[] = { "A" };
3861 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
3862 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
3863 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
3864 CheckDependencies("A", "undefinedA");
3865 CheckDependencies("B", "undefinedAB");
3866 CheckDependencies("C", "undefinedAC");
3867 CheckDependencies("D", "undefinedABCD");
3868 CheckDependencies("E", "undefinedABCDE");
3869 v8::HandleScope handle_scope;
3870 static const char* exts[2] = { "C", "E" };
3871 v8::ExtensionConfiguration config(2, exts);
3872 LocalContext context(&config);
3873 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
3874}
3875
3876
3877static const char* kExtensionTestScript =
3878 "native function A();"
3879 "native function B();"
3880 "native function C();"
3881 "function Foo(i) {"
3882 " if (i == 0) return A();"
3883 " if (i == 1) return B();"
3884 " if (i == 2) return C();"
3885 "}";
3886
3887
3888static v8::Handle<Value> CallFun(const v8::Arguments& args) {
3889 ApiTestFuzzer::Fuzz();
Leon Clarkee46be812010-01-19 14:06:41 +00003890 if (args.IsConstructCall()) {
3891 args.This()->Set(v8_str("data"), args.Data());
3892 return v8::Null();
3893 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003894 return args.Data();
3895}
3896
3897
3898class FunctionExtension : public Extension {
3899 public:
3900 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
3901 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
3902 v8::Handle<String> name);
3903};
3904
3905
3906static int lookup_count = 0;
3907v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
3908 v8::Handle<String> name) {
3909 lookup_count++;
3910 if (name->Equals(v8_str("A"))) {
3911 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
3912 } else if (name->Equals(v8_str("B"))) {
3913 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
3914 } else if (name->Equals(v8_str("C"))) {
3915 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
3916 } else {
3917 return v8::Handle<v8::FunctionTemplate>();
3918 }
3919}
3920
3921
3922THREADED_TEST(FunctionLookup) {
3923 v8::RegisterExtension(new FunctionExtension());
3924 v8::HandleScope handle_scope;
3925 static const char* exts[1] = { "functiontest" };
3926 v8::ExtensionConfiguration config(1, exts);
3927 LocalContext context(&config);
3928 CHECK_EQ(3, lookup_count);
3929 CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
3930 CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
3931 CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
3932}
3933
3934
Leon Clarkee46be812010-01-19 14:06:41 +00003935THREADED_TEST(NativeFunctionConstructCall) {
3936 v8::RegisterExtension(new FunctionExtension());
3937 v8::HandleScope handle_scope;
3938 static const char* exts[1] = { "functiontest" };
3939 v8::ExtensionConfiguration config(1, exts);
3940 LocalContext context(&config);
Leon Clarked91b9f72010-01-27 17:25:45 +00003941 for (int i = 0; i < 10; i++) {
3942 // Run a few times to ensure that allocation of objects doesn't
3943 // change behavior of a constructor function.
3944 CHECK_EQ(v8::Integer::New(8),
3945 Script::Compile(v8_str("(new A()).data"))->Run());
3946 CHECK_EQ(v8::Integer::New(7),
3947 Script::Compile(v8_str("(new B()).data"))->Run());
3948 CHECK_EQ(v8::Integer::New(6),
3949 Script::Compile(v8_str("(new C()).data"))->Run());
3950 }
Leon Clarkee46be812010-01-19 14:06:41 +00003951}
3952
3953
Steve Blocka7e24c12009-10-30 11:49:00 +00003954static const char* last_location;
3955static const char* last_message;
3956void StoringErrorCallback(const char* location, const char* message) {
3957 if (last_location == NULL) {
3958 last_location = location;
3959 last_message = message;
3960 }
3961}
3962
3963
3964// ErrorReporting creates a circular extensions configuration and
3965// tests that the fatal error handler gets called. This renders V8
3966// unusable and therefore this test cannot be run in parallel.
3967TEST(ErrorReporting) {
3968 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
3969 static const char* aDeps[] = { "B" };
3970 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
3971 static const char* bDeps[] = { "A" };
3972 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
3973 last_location = NULL;
3974 v8::ExtensionConfiguration config(1, bDeps);
3975 v8::Handle<Context> context = Context::New(&config);
3976 CHECK(context.IsEmpty());
3977 CHECK_NE(last_location, NULL);
3978}
3979
3980
3981static const char* js_code_causing_huge_string_flattening =
3982 "var str = 'X';"
3983 "for (var i = 0; i < 30; i++) {"
3984 " str = str + str;"
3985 "}"
3986 "str.match(/X/);";
3987
3988
3989void OOMCallback(const char* location, const char* message) {
3990 exit(0);
3991}
3992
3993
3994TEST(RegexpOutOfMemory) {
3995 // Execute a script that causes out of memory when flattening a string.
3996 v8::HandleScope scope;
3997 v8::V8::SetFatalErrorHandler(OOMCallback);
3998 LocalContext context;
3999 Local<Script> script =
4000 Script::Compile(String::New(js_code_causing_huge_string_flattening));
4001 last_location = NULL;
4002 Local<Value> result = script->Run();
4003
4004 CHECK(false); // Should not return.
4005}
4006
4007
4008static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
4009 v8::Handle<Value> data) {
4010 CHECK_EQ(v8::Undefined(), data);
4011 CHECK(message->GetScriptResourceName()->IsUndefined());
4012 CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
4013 message->GetLineNumber();
4014 message->GetSourceLine();
4015}
4016
4017
4018THREADED_TEST(ErrorWithMissingScriptInfo) {
4019 v8::HandleScope scope;
4020 LocalContext context;
4021 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
4022 Script::Compile(v8_str("throw Error()"))->Run();
4023 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
4024}
4025
4026
4027int global_index = 0;
4028
4029class Snorkel {
4030 public:
4031 Snorkel() { index_ = global_index++; }
4032 int index_;
4033};
4034
4035class Whammy {
4036 public:
4037 Whammy() {
4038 cursor_ = 0;
4039 }
4040 ~Whammy() {
4041 script_.Dispose();
4042 }
4043 v8::Handle<Script> getScript() {
4044 if (script_.IsEmpty())
4045 script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
4046 return Local<Script>(*script_);
4047 }
4048
4049 public:
4050 static const int kObjectCount = 256;
4051 int cursor_;
4052 v8::Persistent<v8::Object> objects_[kObjectCount];
4053 v8::Persistent<Script> script_;
4054};
4055
4056static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
4057 Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
4058 delete snorkel;
4059 obj.ClearWeak();
4060}
4061
4062v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
4063 const AccessorInfo& info) {
4064 Whammy* whammy =
4065 static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
4066
4067 v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
4068
4069 v8::Handle<v8::Object> obj = v8::Object::New();
4070 v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
4071 if (!prev.IsEmpty()) {
4072 prev->Set(v8_str("next"), obj);
4073 prev.MakeWeak(new Snorkel(), &HandleWeakReference);
4074 whammy->objects_[whammy->cursor_].Clear();
4075 }
4076 whammy->objects_[whammy->cursor_] = global;
4077 whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
4078 return whammy->getScript()->Run();
4079}
4080
4081THREADED_TEST(WeakReference) {
4082 v8::HandleScope handle_scope;
4083 v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
Ben Murdoch3bec4d22010-07-22 14:51:16 +01004084 Whammy* whammy = new Whammy();
Steve Blocka7e24c12009-10-30 11:49:00 +00004085 templ->SetNamedPropertyHandler(WhammyPropertyGetter,
4086 0, 0, 0, 0,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01004087 v8::External::New(whammy));
Steve Blocka7e24c12009-10-30 11:49:00 +00004088 const char* extension_list[] = { "v8/gc" };
4089 v8::ExtensionConfiguration extensions(1, extension_list);
4090 v8::Persistent<Context> context = Context::New(&extensions);
4091 Context::Scope context_scope(context);
4092
4093 v8::Handle<v8::Object> interceptor = templ->NewInstance();
4094 context->Global()->Set(v8_str("whammy"), interceptor);
4095 const char* code =
4096 "var last;"
4097 "for (var i = 0; i < 10000; i++) {"
4098 " var obj = whammy.length;"
4099 " if (last) last.next = obj;"
4100 " last = obj;"
4101 "}"
4102 "gc();"
4103 "4";
4104 v8::Handle<Value> result = CompileRun(code);
4105 CHECK_EQ(4.0, result->NumberValue());
Ben Murdoch3bec4d22010-07-22 14:51:16 +01004106 delete whammy;
Steve Blocka7e24c12009-10-30 11:49:00 +00004107 context.Dispose();
4108}
4109
4110
Steve Blockd0582a62009-12-15 09:54:21 +00004111static bool in_scavenge = false;
4112static int last = -1;
4113
4114static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
4115 CHECK_EQ(-1, last);
4116 last = 0;
4117 obj.Dispose();
4118 obj.Clear();
4119 in_scavenge = true;
4120 i::Heap::PerformScavenge();
4121 in_scavenge = false;
4122 *(reinterpret_cast<bool*>(data)) = true;
4123}
4124
4125static void CheckIsNotInvokedInScavenge(v8::Persistent<v8::Value> obj,
4126 void* data) {
4127 CHECK_EQ(0, last);
4128 last = 1;
4129 *(reinterpret_cast<bool*>(data)) = in_scavenge;
4130 obj.Dispose();
4131 obj.Clear();
4132}
4133
4134THREADED_TEST(NoWeakRefCallbacksInScavenge) {
4135 // Test verifies that scavenge cannot invoke WeakReferenceCallbacks.
4136 // Calling callbacks from scavenges is unsafe as objects held by those
4137 // handlers might have become strongly reachable, but scavenge doesn't
4138 // check that.
4139 v8::Persistent<Context> context = Context::New();
4140 Context::Scope context_scope(context);
4141
4142 v8::Persistent<v8::Object> object_a;
4143 v8::Persistent<v8::Object> object_b;
4144
4145 {
4146 v8::HandleScope handle_scope;
4147 object_b = v8::Persistent<v8::Object>::New(v8::Object::New());
4148 object_a = v8::Persistent<v8::Object>::New(v8::Object::New());
4149 }
4150
4151 bool object_a_disposed = false;
4152 object_a.MakeWeak(&object_a_disposed, &ForceScavenge);
4153 bool released_in_scavenge = false;
4154 object_b.MakeWeak(&released_in_scavenge, &CheckIsNotInvokedInScavenge);
4155
4156 while (!object_a_disposed) {
4157 i::Heap::CollectAllGarbage(false);
4158 }
4159 CHECK(!released_in_scavenge);
4160}
4161
4162
Steve Blocka7e24c12009-10-30 11:49:00 +00004163v8::Handle<Function> args_fun;
4164
4165
4166static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
4167 ApiTestFuzzer::Fuzz();
4168 CHECK_EQ(args_fun, args.Callee());
4169 CHECK_EQ(3, args.Length());
4170 CHECK_EQ(v8::Integer::New(1), args[0]);
4171 CHECK_EQ(v8::Integer::New(2), args[1]);
4172 CHECK_EQ(v8::Integer::New(3), args[2]);
4173 CHECK_EQ(v8::Undefined(), args[3]);
4174 v8::HandleScope scope;
4175 i::Heap::CollectAllGarbage(false);
4176 return v8::Undefined();
4177}
4178
4179
4180THREADED_TEST(Arguments) {
4181 v8::HandleScope scope;
4182 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
4183 global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
4184 LocalContext context(NULL, global);
Steve Block6ded16b2010-05-10 14:33:55 +01004185 args_fun = context->Global()->Get(v8_str("f")).As<Function>();
Steve Blocka7e24c12009-10-30 11:49:00 +00004186 v8_compile("f(1, 2, 3)")->Run();
4187}
4188
4189
Steve Blocka7e24c12009-10-30 11:49:00 +00004190static v8::Handle<Value> NoBlockGetterX(Local<String> name,
4191 const AccessorInfo&) {
4192 return v8::Handle<Value>();
4193}
4194
4195
4196static v8::Handle<Value> NoBlockGetterI(uint32_t index,
4197 const AccessorInfo&) {
4198 return v8::Handle<Value>();
4199}
4200
4201
4202static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
4203 const AccessorInfo&) {
4204 if (!name->Equals(v8_str("foo"))) {
4205 return v8::Handle<v8::Boolean>(); // not intercepted
4206 }
4207
4208 return v8::False(); // intercepted, and don't delete the property
4209}
4210
4211
4212static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
4213 if (index != 2) {
4214 return v8::Handle<v8::Boolean>(); // not intercepted
4215 }
4216
4217 return v8::False(); // intercepted, and don't delete the property
4218}
4219
4220
4221THREADED_TEST(Deleter) {
4222 v8::HandleScope scope;
4223 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4224 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
4225 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
4226 LocalContext context;
4227 context->Global()->Set(v8_str("k"), obj->NewInstance());
4228 CompileRun(
4229 "k.foo = 'foo';"
4230 "k.bar = 'bar';"
4231 "k[2] = 2;"
4232 "k[4] = 4;");
4233 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
4234 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
4235
4236 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
4237 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
4238
4239 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
4240 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
4241
4242 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
4243 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
4244}
4245
4246
4247static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
4248 ApiTestFuzzer::Fuzz();
4249 if (name->Equals(v8_str("foo")) ||
4250 name->Equals(v8_str("bar")) ||
4251 name->Equals(v8_str("baz"))) {
4252 return v8::Undefined();
4253 }
4254 return v8::Handle<Value>();
4255}
4256
4257
4258static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
4259 ApiTestFuzzer::Fuzz();
4260 if (index == 0 || index == 1) return v8::Undefined();
4261 return v8::Handle<Value>();
4262}
4263
4264
4265static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
4266 ApiTestFuzzer::Fuzz();
4267 v8::Handle<v8::Array> result = v8::Array::New(3);
4268 result->Set(v8::Integer::New(0), v8_str("foo"));
4269 result->Set(v8::Integer::New(1), v8_str("bar"));
4270 result->Set(v8::Integer::New(2), v8_str("baz"));
4271 return result;
4272}
4273
4274
4275static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
4276 ApiTestFuzzer::Fuzz();
4277 v8::Handle<v8::Array> result = v8::Array::New(2);
4278 result->Set(v8::Integer::New(0), v8_str("0"));
4279 result->Set(v8::Integer::New(1), v8_str("1"));
4280 return result;
4281}
4282
4283
4284THREADED_TEST(Enumerators) {
4285 v8::HandleScope scope;
4286 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4287 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
4288 obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
4289 LocalContext context;
4290 context->Global()->Set(v8_str("k"), obj->NewInstance());
4291 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
4292 "k[10] = 0;"
4293 "k.a = 0;"
4294 "k[5] = 0;"
4295 "k.b = 0;"
4296 "k[4294967295] = 0;"
4297 "k.c = 0;"
4298 "k[4294967296] = 0;"
4299 "k.d = 0;"
4300 "k[140000] = 0;"
4301 "k.e = 0;"
4302 "k[30000000000] = 0;"
4303 "k.f = 0;"
4304 "var result = [];"
4305 "for (var prop in k) {"
4306 " result.push(prop);"
4307 "}"
4308 "result"));
4309 // Check that we get all the property names returned including the
4310 // ones from the enumerators in the right order: indexed properties
4311 // in numerical order, indexed interceptor properties, named
4312 // properties in insertion order, named interceptor properties.
4313 // This order is not mandated by the spec, so this test is just
4314 // documenting our behavior.
4315 CHECK_EQ(17, result->Length());
4316 // Indexed properties in numerical order.
4317 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
4318 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
4319 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
4320 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
4321 // Indexed interceptor properties in the order they are returned
4322 // from the enumerator interceptor.
4323 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
4324 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
4325 // Named properties in insertion order.
4326 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
4327 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
4328 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
4329 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
4330 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
4331 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
4332 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
4333 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
4334 // Named interceptor properties.
4335 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
4336 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
4337 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
4338}
4339
4340
4341int p_getter_count;
4342int p_getter_count2;
4343
4344
4345static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
4346 ApiTestFuzzer::Fuzz();
4347 p_getter_count++;
4348 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
4349 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
4350 if (name->Equals(v8_str("p1"))) {
4351 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
4352 } else if (name->Equals(v8_str("p2"))) {
4353 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
4354 } else if (name->Equals(v8_str("p3"))) {
4355 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
4356 } else if (name->Equals(v8_str("p4"))) {
4357 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
4358 }
4359 return v8::Undefined();
4360}
4361
4362
4363static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
4364 ApiTestFuzzer::Fuzz();
4365 LocalContext context;
4366 context->Global()->Set(v8_str("o1"), obj->NewInstance());
4367 CompileRun(
4368 "o1.__proto__ = { };"
4369 "var o2 = { __proto__: o1 };"
4370 "var o3 = { __proto__: o2 };"
4371 "var o4 = { __proto__: o3 };"
4372 "for (var i = 0; i < 10; i++) o4.p4;"
4373 "for (var i = 0; i < 10; i++) o3.p3;"
4374 "for (var i = 0; i < 10; i++) o2.p2;"
4375 "for (var i = 0; i < 10; i++) o1.p1;");
4376}
4377
4378
4379static v8::Handle<Value> PGetter2(Local<String> name,
4380 const AccessorInfo& info) {
4381 ApiTestFuzzer::Fuzz();
4382 p_getter_count2++;
4383 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
4384 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
4385 if (name->Equals(v8_str("p1"))) {
4386 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
4387 } else if (name->Equals(v8_str("p2"))) {
4388 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
4389 } else if (name->Equals(v8_str("p3"))) {
4390 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
4391 } else if (name->Equals(v8_str("p4"))) {
4392 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
4393 }
4394 return v8::Undefined();
4395}
4396
4397
4398THREADED_TEST(GetterHolders) {
4399 v8::HandleScope scope;
4400 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4401 obj->SetAccessor(v8_str("p1"), PGetter);
4402 obj->SetAccessor(v8_str("p2"), PGetter);
4403 obj->SetAccessor(v8_str("p3"), PGetter);
4404 obj->SetAccessor(v8_str("p4"), PGetter);
4405 p_getter_count = 0;
4406 RunHolderTest(obj);
4407 CHECK_EQ(40, p_getter_count);
4408}
4409
4410
4411THREADED_TEST(PreInterceptorHolders) {
4412 v8::HandleScope scope;
4413 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4414 obj->SetNamedPropertyHandler(PGetter2);
4415 p_getter_count2 = 0;
4416 RunHolderTest(obj);
4417 CHECK_EQ(40, p_getter_count2);
4418}
4419
4420
4421THREADED_TEST(ObjectInstantiation) {
4422 v8::HandleScope scope;
4423 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
4424 templ->SetAccessor(v8_str("t"), PGetter2);
4425 LocalContext context;
4426 context->Global()->Set(v8_str("o"), templ->NewInstance());
4427 for (int i = 0; i < 100; i++) {
4428 v8::HandleScope inner_scope;
4429 v8::Handle<v8::Object> obj = templ->NewInstance();
4430 CHECK_NE(obj, context->Global()->Get(v8_str("o")));
4431 context->Global()->Set(v8_str("o2"), obj);
4432 v8::Handle<Value> value =
4433 Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
4434 CHECK_EQ(v8::True(), value);
4435 context->Global()->Set(v8_str("o"), obj);
4436 }
4437}
4438
4439
Ben Murdochb0fe1622011-05-05 13:52:32 +01004440static int StrCmp16(uint16_t* a, uint16_t* b) {
4441 while (true) {
4442 if (*a == 0 && *b == 0) return 0;
4443 if (*a != *b) return 0 + *a - *b;
4444 a++;
4445 b++;
4446 }
4447}
4448
4449
4450static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
4451 while (true) {
4452 if (n-- == 0) return 0;
4453 if (*a == 0 && *b == 0) return 0;
4454 if (*a != *b) return 0 + *a - *b;
4455 a++;
4456 b++;
4457 }
4458}
4459
4460
Steve Blocka7e24c12009-10-30 11:49:00 +00004461THREADED_TEST(StringWrite) {
4462 v8::HandleScope scope;
4463 v8::Handle<String> str = v8_str("abcde");
Ben Murdochb0fe1622011-05-05 13:52:32 +01004464 // abc<Icelandic eth><Unicode snowman>.
4465 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
4466
4467 CHECK_EQ(5, str2->Length());
Steve Blocka7e24c12009-10-30 11:49:00 +00004468
4469 char buf[100];
Ben Murdochb0fe1622011-05-05 13:52:32 +01004470 char utf8buf[100];
4471 uint16_t wbuf[100];
Steve Blocka7e24c12009-10-30 11:49:00 +00004472 int len;
Ben Murdochb0fe1622011-05-05 13:52:32 +01004473 int charlen;
4474
4475 memset(utf8buf, 0x1, sizeof(utf8buf));
4476 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
4477 CHECK_EQ(len, 9);
4478 CHECK_EQ(charlen, 5);
4479 CHECK_EQ(strcmp(utf8buf, "abc\303\260\342\230\203"), 0);
4480
4481 memset(utf8buf, 0x1, sizeof(utf8buf));
4482 len = str2->WriteUtf8(utf8buf, 8, &charlen);
4483 CHECK_EQ(len, 8);
4484 CHECK_EQ(charlen, 5);
4485 CHECK_EQ(strncmp(utf8buf, "abc\303\260\342\230\203\1", 9), 0);
4486
4487 memset(utf8buf, 0x1, sizeof(utf8buf));
4488 len = str2->WriteUtf8(utf8buf, 7, &charlen);
4489 CHECK_EQ(len, 5);
4490 CHECK_EQ(charlen, 4);
4491 CHECK_EQ(strncmp(utf8buf, "abc\303\260\1", 5), 0);
4492
4493 memset(utf8buf, 0x1, sizeof(utf8buf));
4494 len = str2->WriteUtf8(utf8buf, 6, &charlen);
4495 CHECK_EQ(len, 5);
4496 CHECK_EQ(charlen, 4);
4497 CHECK_EQ(strncmp(utf8buf, "abc\303\260\1", 5), 0);
4498
4499 memset(utf8buf, 0x1, sizeof(utf8buf));
4500 len = str2->WriteUtf8(utf8buf, 5, &charlen);
4501 CHECK_EQ(len, 5);
4502 CHECK_EQ(charlen, 4);
4503 CHECK_EQ(strncmp(utf8buf, "abc\303\260\1", 5), 0);
4504
4505 memset(utf8buf, 0x1, sizeof(utf8buf));
4506 len = str2->WriteUtf8(utf8buf, 4, &charlen);
4507 CHECK_EQ(len, 3);
4508 CHECK_EQ(charlen, 3);
4509 CHECK_EQ(strncmp(utf8buf, "abc\1", 4), 0);
4510
4511 memset(utf8buf, 0x1, sizeof(utf8buf));
4512 len = str2->WriteUtf8(utf8buf, 3, &charlen);
4513 CHECK_EQ(len, 3);
4514 CHECK_EQ(charlen, 3);
4515 CHECK_EQ(strncmp(utf8buf, "abc\1", 4), 0);
4516
4517 memset(utf8buf, 0x1, sizeof(utf8buf));
4518 len = str2->WriteUtf8(utf8buf, 2, &charlen);
4519 CHECK_EQ(len, 2);
4520 CHECK_EQ(charlen, 2);
4521 CHECK_EQ(strncmp(utf8buf, "ab\1", 3), 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00004522
4523 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01004524 memset(wbuf, 0x1, sizeof(wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00004525 len = str->WriteAscii(buf);
4526 CHECK_EQ(len, 5);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004527 len = str->Write(wbuf);
4528 CHECK_EQ(len, 5);
4529 CHECK_EQ(strcmp("abcde", buf), 0);
4530 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
4531 CHECK_EQ(StrCmp16(answer1, wbuf), 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00004532
4533 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01004534 memset(wbuf, 0x1, sizeof(wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00004535 len = str->WriteAscii(buf, 0, 4);
4536 CHECK_EQ(len, 4);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004537 len = str->Write(wbuf, 0, 4);
4538 CHECK_EQ(len, 4);
Steve Blocka7e24c12009-10-30 11:49:00 +00004539 CHECK_EQ(strncmp("abcd\1", buf, 5), 0);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004540 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
4541 CHECK_EQ(StrNCmp16(answer2, wbuf, 5), 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00004542
4543 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01004544 memset(wbuf, 0x1, sizeof(wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00004545 len = str->WriteAscii(buf, 0, 5);
4546 CHECK_EQ(len, 5);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004547 len = str->Write(wbuf, 0, 5);
4548 CHECK_EQ(len, 5);
Steve Blocka7e24c12009-10-30 11:49:00 +00004549 CHECK_EQ(strncmp("abcde\1", buf, 6), 0);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004550 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
4551 CHECK_EQ(StrNCmp16(answer3, wbuf, 6), 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00004552
4553 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01004554 memset(wbuf, 0x1, sizeof(wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00004555 len = str->WriteAscii(buf, 0, 6);
4556 CHECK_EQ(len, 5);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004557 len = str->Write(wbuf, 0, 6);
4558 CHECK_EQ(len, 5);
4559 CHECK_EQ(strcmp("abcde", buf), 0);
4560 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
4561 CHECK_EQ(StrCmp16(answer4, wbuf), 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00004562
4563 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01004564 memset(wbuf, 0x1, sizeof(wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00004565 len = str->WriteAscii(buf, 4, -1);
4566 CHECK_EQ(len, 1);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004567 len = str->Write(wbuf, 4, -1);
4568 CHECK_EQ(len, 1);
4569 CHECK_EQ(strcmp("e", buf), 0);
4570 uint16_t answer5[] = {'e', '\0'};
4571 CHECK_EQ(StrCmp16(answer5, wbuf), 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00004572
4573 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01004574 memset(wbuf, 0x1, sizeof(wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00004575 len = str->WriteAscii(buf, 4, 6);
4576 CHECK_EQ(len, 1);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004577 len = str->Write(wbuf, 4, 6);
4578 CHECK_EQ(len, 1);
4579 CHECK_EQ(strcmp("e", buf), 0);
4580 CHECK_EQ(StrCmp16(answer5, wbuf), 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00004581
4582 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01004583 memset(wbuf, 0x1, sizeof(wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00004584 len = str->WriteAscii(buf, 4, 1);
4585 CHECK_EQ(len, 1);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004586 len = str->Write(wbuf, 4, 1);
4587 CHECK_EQ(len, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00004588 CHECK_EQ(strncmp("e\1", buf, 2), 0);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004589 uint16_t answer6[] = {'e', 0x101};
4590 CHECK_EQ(StrNCmp16(answer6, wbuf, 2), 0);
4591
4592 memset(buf, 0x1, sizeof(buf));
4593 memset(wbuf, 0x1, sizeof(wbuf));
4594 len = str->WriteAscii(buf, 3, 1);
4595 CHECK_EQ(len, 1);
4596 len = str->Write(wbuf, 3, 1);
4597 CHECK_EQ(len, 1);
4598 CHECK_EQ(strncmp("d\1", buf, 2), 0);
4599 uint16_t answer7[] = {'d', 0x101};
4600 CHECK_EQ(StrNCmp16(answer7, wbuf, 2), 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00004601}
4602
4603
4604THREADED_TEST(ToArrayIndex) {
4605 v8::HandleScope scope;
4606 LocalContext context;
4607
4608 v8::Handle<String> str = v8_str("42");
4609 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
4610 CHECK(!index.IsEmpty());
4611 CHECK_EQ(42.0, index->Uint32Value());
4612 str = v8_str("42asdf");
4613 index = str->ToArrayIndex();
4614 CHECK(index.IsEmpty());
4615 str = v8_str("-42");
4616 index = str->ToArrayIndex();
4617 CHECK(index.IsEmpty());
4618 str = v8_str("4294967295");
4619 index = str->ToArrayIndex();
4620 CHECK(!index.IsEmpty());
4621 CHECK_EQ(4294967295.0, index->Uint32Value());
4622 v8::Handle<v8::Number> num = v8::Number::New(1);
4623 index = num->ToArrayIndex();
4624 CHECK(!index.IsEmpty());
4625 CHECK_EQ(1.0, index->Uint32Value());
4626 num = v8::Number::New(-1);
4627 index = num->ToArrayIndex();
4628 CHECK(index.IsEmpty());
4629 v8::Handle<v8::Object> obj = v8::Object::New();
4630 index = obj->ToArrayIndex();
4631 CHECK(index.IsEmpty());
4632}
4633
4634
4635THREADED_TEST(ErrorConstruction) {
4636 v8::HandleScope scope;
4637 LocalContext context;
4638
4639 v8::Handle<String> foo = v8_str("foo");
4640 v8::Handle<String> message = v8_str("message");
4641 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
4642 CHECK(range_error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01004643 v8::Handle<v8::Object> range_obj = range_error.As<v8::Object>();
4644 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00004645 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
4646 CHECK(reference_error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01004647 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00004648 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
4649 CHECK(syntax_error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01004650 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00004651 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
4652 CHECK(type_error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01004653 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00004654 v8::Handle<Value> error = v8::Exception::Error(foo);
4655 CHECK(error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01004656 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00004657}
4658
4659
4660static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
4661 ApiTestFuzzer::Fuzz();
4662 return v8_num(10);
4663}
4664
4665
4666static void YSetter(Local<String> name,
4667 Local<Value> value,
4668 const AccessorInfo& info) {
4669 if (info.This()->Has(name)) {
4670 info.This()->Delete(name);
4671 }
4672 info.This()->Set(name, value);
4673}
4674
4675
4676THREADED_TEST(DeleteAccessor) {
4677 v8::HandleScope scope;
4678 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4679 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
4680 LocalContext context;
4681 v8::Handle<v8::Object> holder = obj->NewInstance();
4682 context->Global()->Set(v8_str("holder"), holder);
4683 v8::Handle<Value> result = CompileRun(
4684 "holder.y = 11; holder.y = 12; holder.y");
4685 CHECK_EQ(12, result->Uint32Value());
4686}
4687
4688
4689THREADED_TEST(TypeSwitch) {
4690 v8::HandleScope scope;
4691 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
4692 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
4693 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
4694 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
4695 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
4696 LocalContext context;
4697 v8::Handle<v8::Object> obj0 = v8::Object::New();
4698 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
4699 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
4700 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
4701 for (int i = 0; i < 10; i++) {
4702 CHECK_EQ(0, type_switch->match(obj0));
4703 CHECK_EQ(1, type_switch->match(obj1));
4704 CHECK_EQ(2, type_switch->match(obj2));
4705 CHECK_EQ(3, type_switch->match(obj3));
4706 CHECK_EQ(3, type_switch->match(obj3));
4707 CHECK_EQ(2, type_switch->match(obj2));
4708 CHECK_EQ(1, type_switch->match(obj1));
4709 CHECK_EQ(0, type_switch->match(obj0));
4710 }
4711}
4712
4713
4714// For use within the TestSecurityHandler() test.
4715static bool g_security_callback_result = false;
4716static bool NamedSecurityTestCallback(Local<v8::Object> global,
4717 Local<Value> name,
4718 v8::AccessType type,
4719 Local<Value> data) {
4720 // Always allow read access.
4721 if (type == v8::ACCESS_GET)
4722 return true;
4723
4724 // Sometimes allow other access.
4725 return g_security_callback_result;
4726}
4727
4728
4729static bool IndexedSecurityTestCallback(Local<v8::Object> global,
4730 uint32_t key,
4731 v8::AccessType type,
4732 Local<Value> data) {
4733 // Always allow read access.
4734 if (type == v8::ACCESS_GET)
4735 return true;
4736
4737 // Sometimes allow other access.
4738 return g_security_callback_result;
4739}
4740
4741
4742static int trouble_nesting = 0;
4743static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
4744 ApiTestFuzzer::Fuzz();
4745 trouble_nesting++;
4746
4747 // Call a JS function that throws an uncaught exception.
4748 Local<v8::Object> arg_this = Context::GetCurrent()->Global();
4749 Local<Value> trouble_callee = (trouble_nesting == 3) ?
4750 arg_this->Get(v8_str("trouble_callee")) :
4751 arg_this->Get(v8_str("trouble_caller"));
4752 CHECK(trouble_callee->IsFunction());
4753 return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
4754}
4755
4756
4757static int report_count = 0;
4758static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
4759 v8::Handle<Value>) {
4760 report_count++;
4761}
4762
4763
4764// Counts uncaught exceptions, but other tests running in parallel
4765// also have uncaught exceptions.
4766TEST(ApiUncaughtException) {
4767 report_count = 0;
4768 v8::HandleScope scope;
4769 LocalContext env;
4770 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
4771
4772 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
4773 v8::Local<v8::Object> global = env->Global();
4774 global->Set(v8_str("trouble"), fun->GetFunction());
4775
4776 Script::Compile(v8_str("function trouble_callee() {"
4777 " var x = null;"
4778 " return x.foo;"
4779 "};"
4780 "function trouble_caller() {"
4781 " trouble();"
4782 "};"))->Run();
4783 Local<Value> trouble = global->Get(v8_str("trouble"));
4784 CHECK(trouble->IsFunction());
4785 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
4786 CHECK(trouble_callee->IsFunction());
4787 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
4788 CHECK(trouble_caller->IsFunction());
4789 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
4790 CHECK_EQ(1, report_count);
4791 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
4792}
4793
Leon Clarke4515c472010-02-03 11:58:03 +00004794static const char* script_resource_name = "ExceptionInNativeScript.js";
4795static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
4796 v8::Handle<Value>) {
4797 v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
4798 CHECK(!name_val.IsEmpty() && name_val->IsString());
4799 v8::String::AsciiValue name(message->GetScriptResourceName());
4800 CHECK_EQ(script_resource_name, *name);
4801 CHECK_EQ(3, message->GetLineNumber());
4802 v8::String::AsciiValue source_line(message->GetSourceLine());
4803 CHECK_EQ(" new o.foo();", *source_line);
4804}
4805
4806TEST(ExceptionInNativeScript) {
4807 v8::HandleScope scope;
4808 LocalContext env;
4809 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
4810
4811 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
4812 v8::Local<v8::Object> global = env->Global();
4813 global->Set(v8_str("trouble"), fun->GetFunction());
4814
4815 Script::Compile(v8_str("function trouble() {\n"
4816 " var o = {};\n"
4817 " new o.foo();\n"
4818 "};"), v8::String::New(script_resource_name))->Run();
4819 Local<Value> trouble = global->Get(v8_str("trouble"));
4820 CHECK(trouble->IsFunction());
4821 Function::Cast(*trouble)->Call(global, 0, NULL);
4822 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
4823}
4824
Steve Blocka7e24c12009-10-30 11:49:00 +00004825
4826TEST(CompilationErrorUsingTryCatchHandler) {
4827 v8::HandleScope scope;
4828 LocalContext env;
4829 v8::TryCatch try_catch;
4830 Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
4831 CHECK_NE(NULL, *try_catch.Exception());
4832 CHECK(try_catch.HasCaught());
4833}
4834
4835
4836TEST(TryCatchFinallyUsingTryCatchHandler) {
4837 v8::HandleScope scope;
4838 LocalContext env;
4839 v8::TryCatch try_catch;
4840 Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
4841 CHECK(!try_catch.HasCaught());
4842 Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
4843 CHECK(try_catch.HasCaught());
4844 try_catch.Reset();
4845 Script::Compile(v8_str("(function() {"
4846 "try { throw ''; } finally { return; }"
4847 "})()"))->Run();
4848 CHECK(!try_catch.HasCaught());
4849 Script::Compile(v8_str("(function()"
4850 " { try { throw ''; } finally { throw 0; }"
4851 "})()"))->Run();
4852 CHECK(try_catch.HasCaught());
4853}
4854
4855
4856// SecurityHandler can't be run twice
4857TEST(SecurityHandler) {
4858 v8::HandleScope scope0;
4859 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
4860 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
4861 IndexedSecurityTestCallback);
4862 // Create an environment
4863 v8::Persistent<Context> context0 =
4864 Context::New(NULL, global_template);
4865 context0->Enter();
4866
4867 v8::Handle<v8::Object> global0 = context0->Global();
4868 v8::Handle<Script> script0 = v8_compile("foo = 111");
4869 script0->Run();
4870 global0->Set(v8_str("0"), v8_num(999));
4871 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
4872 CHECK_EQ(111, foo0->Int32Value());
4873 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
4874 CHECK_EQ(999, z0->Int32Value());
4875
4876 // Create another environment, should fail security checks.
4877 v8::HandleScope scope1;
4878
4879 v8::Persistent<Context> context1 =
4880 Context::New(NULL, global_template);
4881 context1->Enter();
4882
4883 v8::Handle<v8::Object> global1 = context1->Global();
4884 global1->Set(v8_str("othercontext"), global0);
4885 // This set will fail the security check.
4886 v8::Handle<Script> script1 =
4887 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
4888 script1->Run();
4889 // This read will pass the security check.
4890 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
4891 CHECK_EQ(111, foo1->Int32Value());
4892 // This read will pass the security check.
4893 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
4894 CHECK_EQ(999, z1->Int32Value());
4895
4896 // Create another environment, should pass security checks.
4897 { g_security_callback_result = true; // allow security handler to pass.
4898 v8::HandleScope scope2;
4899 LocalContext context2;
4900 v8::Handle<v8::Object> global2 = context2->Global();
4901 global2->Set(v8_str("othercontext"), global0);
4902 v8::Handle<Script> script2 =
4903 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
4904 script2->Run();
4905 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
4906 CHECK_EQ(333, foo2->Int32Value());
4907 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
4908 CHECK_EQ(888, z2->Int32Value());
4909 }
4910
4911 context1->Exit();
4912 context1.Dispose();
4913
4914 context0->Exit();
4915 context0.Dispose();
4916}
4917
4918
4919THREADED_TEST(SecurityChecks) {
4920 v8::HandleScope handle_scope;
4921 LocalContext env1;
4922 v8::Persistent<Context> env2 = Context::New();
4923
4924 Local<Value> foo = v8_str("foo");
4925 Local<Value> bar = v8_str("bar");
4926
4927 // Set to the same domain.
4928 env1->SetSecurityToken(foo);
4929
4930 // Create a function in env1.
4931 Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
4932 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
4933 CHECK(spy->IsFunction());
4934
4935 // Create another function accessing global objects.
4936 Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
4937 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
4938 CHECK(spy2->IsFunction());
4939
4940 // Switch to env2 in the same domain and invoke spy on env2.
4941 {
4942 env2->SetSecurityToken(foo);
4943 // Enter env2
4944 Context::Scope scope_env2(env2);
4945 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
4946 CHECK(result->IsFunction());
4947 }
4948
4949 {
4950 env2->SetSecurityToken(bar);
4951 Context::Scope scope_env2(env2);
4952
4953 // Call cross_domain_call, it should throw an exception
4954 v8::TryCatch try_catch;
4955 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
4956 CHECK(try_catch.HasCaught());
4957 }
4958
4959 env2.Dispose();
4960}
4961
4962
4963// Regression test case for issue 1183439.
4964THREADED_TEST(SecurityChecksForPrototypeChain) {
4965 v8::HandleScope scope;
4966 LocalContext current;
4967 v8::Persistent<Context> other = Context::New();
4968
4969 // Change context to be able to get to the Object function in the
4970 // other context without hitting the security checks.
4971 v8::Local<Value> other_object;
4972 { Context::Scope scope(other);
4973 other_object = other->Global()->Get(v8_str("Object"));
4974 other->Global()->Set(v8_num(42), v8_num(87));
4975 }
4976
4977 current->Global()->Set(v8_str("other"), other->Global());
4978 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
4979
4980 // Make sure the security check fails here and we get an undefined
4981 // result instead of getting the Object function. Repeat in a loop
4982 // to make sure to exercise the IC code.
4983 v8::Local<Script> access_other0 = v8_compile("other.Object");
4984 v8::Local<Script> access_other1 = v8_compile("other[42]");
4985 for (int i = 0; i < 5; i++) {
4986 CHECK(!access_other0->Run()->Equals(other_object));
4987 CHECK(access_other0->Run()->IsUndefined());
4988 CHECK(!access_other1->Run()->Equals(v8_num(87)));
4989 CHECK(access_other1->Run()->IsUndefined());
4990 }
4991
4992 // Create an object that has 'other' in its prototype chain and make
4993 // sure we cannot access the Object function indirectly through
4994 // that. Repeat in a loop to make sure to exercise the IC code.
4995 v8_compile("function F() { };"
4996 "F.prototype = other;"
4997 "var f = new F();")->Run();
4998 v8::Local<Script> access_f0 = v8_compile("f.Object");
4999 v8::Local<Script> access_f1 = v8_compile("f[42]");
5000 for (int j = 0; j < 5; j++) {
5001 CHECK(!access_f0->Run()->Equals(other_object));
5002 CHECK(access_f0->Run()->IsUndefined());
5003 CHECK(!access_f1->Run()->Equals(v8_num(87)));
5004 CHECK(access_f1->Run()->IsUndefined());
5005 }
5006
5007 // Now it gets hairy: Set the prototype for the other global object
5008 // to be the current global object. The prototype chain for 'f' now
5009 // goes through 'other' but ends up in the current global object.
5010 { Context::Scope scope(other);
5011 other->Global()->Set(v8_str("__proto__"), current->Global());
5012 }
5013 // Set a named and an index property on the current global
5014 // object. To force the lookup to go through the other global object,
5015 // the properties must not exist in the other global object.
5016 current->Global()->Set(v8_str("foo"), v8_num(100));
5017 current->Global()->Set(v8_num(99), v8_num(101));
5018 // Try to read the properties from f and make sure that the access
5019 // gets stopped by the security checks on the other global object.
5020 Local<Script> access_f2 = v8_compile("f.foo");
5021 Local<Script> access_f3 = v8_compile("f[99]");
5022 for (int k = 0; k < 5; k++) {
5023 CHECK(!access_f2->Run()->Equals(v8_num(100)));
5024 CHECK(access_f2->Run()->IsUndefined());
5025 CHECK(!access_f3->Run()->Equals(v8_num(101)));
5026 CHECK(access_f3->Run()->IsUndefined());
5027 }
5028 other.Dispose();
5029}
5030
5031
5032THREADED_TEST(CrossDomainDelete) {
5033 v8::HandleScope handle_scope;
5034 LocalContext env1;
5035 v8::Persistent<Context> env2 = Context::New();
5036
5037 Local<Value> foo = v8_str("foo");
5038 Local<Value> bar = v8_str("bar");
5039
5040 // Set to the same domain.
5041 env1->SetSecurityToken(foo);
5042 env2->SetSecurityToken(foo);
5043
5044 env1->Global()->Set(v8_str("prop"), v8_num(3));
5045 env2->Global()->Set(v8_str("env1"), env1->Global());
5046
5047 // Change env2 to a different domain and delete env1.prop.
5048 env2->SetSecurityToken(bar);
5049 {
5050 Context::Scope scope_env2(env2);
5051 Local<Value> result =
5052 Script::Compile(v8_str("delete env1.prop"))->Run();
5053 CHECK(result->IsFalse());
5054 }
5055
5056 // Check that env1.prop still exists.
5057 Local<Value> v = env1->Global()->Get(v8_str("prop"));
5058 CHECK(v->IsNumber());
5059 CHECK_EQ(3, v->Int32Value());
5060
5061 env2.Dispose();
5062}
5063
5064
5065THREADED_TEST(CrossDomainIsPropertyEnumerable) {
5066 v8::HandleScope handle_scope;
5067 LocalContext env1;
5068 v8::Persistent<Context> env2 = Context::New();
5069
5070 Local<Value> foo = v8_str("foo");
5071 Local<Value> bar = v8_str("bar");
5072
5073 // Set to the same domain.
5074 env1->SetSecurityToken(foo);
5075 env2->SetSecurityToken(foo);
5076
5077 env1->Global()->Set(v8_str("prop"), v8_num(3));
5078 env2->Global()->Set(v8_str("env1"), env1->Global());
5079
5080 // env1.prop is enumerable in env2.
5081 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
5082 {
5083 Context::Scope scope_env2(env2);
5084 Local<Value> result = Script::Compile(test)->Run();
5085 CHECK(result->IsTrue());
5086 }
5087
5088 // Change env2 to a different domain and test again.
5089 env2->SetSecurityToken(bar);
5090 {
5091 Context::Scope scope_env2(env2);
5092 Local<Value> result = Script::Compile(test)->Run();
5093 CHECK(result->IsFalse());
5094 }
5095
5096 env2.Dispose();
5097}
5098
5099
5100THREADED_TEST(CrossDomainForIn) {
5101 v8::HandleScope handle_scope;
5102 LocalContext env1;
5103 v8::Persistent<Context> env2 = Context::New();
5104
5105 Local<Value> foo = v8_str("foo");
5106 Local<Value> bar = v8_str("bar");
5107
5108 // Set to the same domain.
5109 env1->SetSecurityToken(foo);
5110 env2->SetSecurityToken(foo);
5111
5112 env1->Global()->Set(v8_str("prop"), v8_num(3));
5113 env2->Global()->Set(v8_str("env1"), env1->Global());
5114
5115 // Change env2 to a different domain and set env1's global object
5116 // as the __proto__ of an object in env2 and enumerate properties
5117 // in for-in. It shouldn't enumerate properties on env1's global
5118 // object.
5119 env2->SetSecurityToken(bar);
5120 {
5121 Context::Scope scope_env2(env2);
5122 Local<Value> result =
5123 CompileRun("(function(){var obj = {'__proto__':env1};"
5124 "for (var p in obj)"
5125 " if (p == 'prop') return false;"
5126 "return true;})()");
5127 CHECK(result->IsTrue());
5128 }
5129 env2.Dispose();
5130}
5131
5132
5133TEST(ContextDetachGlobal) {
5134 v8::HandleScope handle_scope;
5135 LocalContext env1;
5136 v8::Persistent<Context> env2 = Context::New();
5137
5138 Local<v8::Object> global1 = env1->Global();
5139
5140 Local<Value> foo = v8_str("foo");
5141
5142 // Set to the same domain.
5143 env1->SetSecurityToken(foo);
5144 env2->SetSecurityToken(foo);
5145
5146 // Enter env2
5147 env2->Enter();
5148
Andrei Popescu74b3c142010-03-29 12:03:09 +01005149 // Create a function in env2 and add a reference to it in env1.
Steve Blocka7e24c12009-10-30 11:49:00 +00005150 Local<v8::Object> global2 = env2->Global();
5151 global2->Set(v8_str("prop"), v8::Integer::New(1));
5152 CompileRun("function getProp() {return prop;}");
5153
5154 env1->Global()->Set(v8_str("getProp"),
5155 global2->Get(v8_str("getProp")));
5156
Andrei Popescu74b3c142010-03-29 12:03:09 +01005157 // Detach env2's global, and reuse the global object of env2
Steve Blocka7e24c12009-10-30 11:49:00 +00005158 env2->Exit();
5159 env2->DetachGlobal();
5160 // env2 has a new global object.
5161 CHECK(!env2->Global()->Equals(global2));
5162
5163 v8::Persistent<Context> env3 =
5164 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
5165 env3->SetSecurityToken(v8_str("bar"));
5166 env3->Enter();
5167
5168 Local<v8::Object> global3 = env3->Global();
5169 CHECK_EQ(global2, global3);
5170 CHECK(global3->Get(v8_str("prop"))->IsUndefined());
5171 CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
5172 global3->Set(v8_str("prop"), v8::Integer::New(-1));
5173 global3->Set(v8_str("prop2"), v8::Integer::New(2));
5174 env3->Exit();
5175
5176 // Call getProp in env1, and it should return the value 1
5177 {
5178 Local<Value> get_prop = global1->Get(v8_str("getProp"));
5179 CHECK(get_prop->IsFunction());
5180 v8::TryCatch try_catch;
5181 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
5182 CHECK(!try_catch.HasCaught());
5183 CHECK_EQ(1, r->Int32Value());
5184 }
5185
5186 // Check that env3 is not accessible from env1
5187 {
5188 Local<Value> r = global3->Get(v8_str("prop2"));
5189 CHECK(r->IsUndefined());
5190 }
5191
5192 env2.Dispose();
5193 env3.Dispose();
5194}
5195
5196
Andrei Popescu74b3c142010-03-29 12:03:09 +01005197TEST(DetachAndReattachGlobal) {
5198 v8::HandleScope scope;
5199 LocalContext env1;
5200
5201 // Create second environment.
5202 v8::Persistent<Context> env2 = Context::New();
5203
5204 Local<Value> foo = v8_str("foo");
5205
5206 // Set same security token for env1 and env2.
5207 env1->SetSecurityToken(foo);
5208 env2->SetSecurityToken(foo);
5209
5210 // Create a property on the global object in env2.
5211 {
5212 v8::Context::Scope scope(env2);
5213 env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
5214 }
5215
5216 // Create a reference to env2 global from env1 global.
5217 env1->Global()->Set(v8_str("other"), env2->Global());
5218
5219 // Check that we have access to other.p in env2 from env1.
5220 Local<Value> result = CompileRun("other.p");
5221 CHECK(result->IsInt32());
5222 CHECK_EQ(42, result->Int32Value());
5223
5224 // Hold on to global from env2 and detach global from env2.
5225 Local<v8::Object> global2 = env2->Global();
5226 env2->DetachGlobal();
5227
5228 // Check that the global has been detached. No other.p property can
5229 // be found.
5230 result = CompileRun("other.p");
5231 CHECK(result->IsUndefined());
5232
5233 // Reuse global2 for env3.
5234 v8::Persistent<Context> env3 =
5235 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
5236 CHECK_EQ(global2, env3->Global());
5237
5238 // Start by using the same security token for env3 as for env1 and env2.
5239 env3->SetSecurityToken(foo);
5240
5241 // Create a property on the global object in env3.
5242 {
5243 v8::Context::Scope scope(env3);
5244 env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
5245 }
5246
5247 // Check that other.p is now the property in env3 and that we have access.
5248 result = CompileRun("other.p");
5249 CHECK(result->IsInt32());
5250 CHECK_EQ(24, result->Int32Value());
5251
5252 // Change security token for env3 to something different from env1 and env2.
5253 env3->SetSecurityToken(v8_str("bar"));
5254
5255 // Check that we do not have access to other.p in env1. |other| is now
5256 // the global object for env3 which has a different security token,
5257 // so access should be blocked.
5258 result = CompileRun("other.p");
5259 CHECK(result->IsUndefined());
5260
5261 // Detach the global for env3 and reattach it to env2.
5262 env3->DetachGlobal();
5263 env2->ReattachGlobal(global2);
5264
5265 // Check that we have access to other.p again in env1. |other| is now
5266 // the global object for env2 which has the same security token as env1.
5267 result = CompileRun("other.p");
5268 CHECK(result->IsInt32());
5269 CHECK_EQ(42, result->Int32Value());
5270
5271 env2.Dispose();
5272 env3.Dispose();
5273}
5274
5275
Steve Blocka7e24c12009-10-30 11:49:00 +00005276static bool NamedAccessBlocker(Local<v8::Object> global,
5277 Local<Value> name,
5278 v8::AccessType type,
5279 Local<Value> data) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01005280 return Context::GetCurrent()->Global()->Equals(global);
Steve Blocka7e24c12009-10-30 11:49:00 +00005281}
5282
5283
5284static bool IndexedAccessBlocker(Local<v8::Object> global,
5285 uint32_t key,
5286 v8::AccessType type,
5287 Local<Value> data) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01005288 return Context::GetCurrent()->Global()->Equals(global);
Steve Blocka7e24c12009-10-30 11:49:00 +00005289}
5290
5291
5292static int g_echo_value = -1;
5293static v8::Handle<Value> EchoGetter(Local<String> name,
5294 const AccessorInfo& info) {
5295 return v8_num(g_echo_value);
5296}
5297
5298
5299static void EchoSetter(Local<String> name,
5300 Local<Value> value,
5301 const AccessorInfo&) {
5302 if (value->IsNumber())
5303 g_echo_value = value->Int32Value();
5304}
5305
5306
5307static v8::Handle<Value> UnreachableGetter(Local<String> name,
5308 const AccessorInfo& info) {
5309 CHECK(false); // This function should not be called..
5310 return v8::Undefined();
5311}
5312
5313
5314static void UnreachableSetter(Local<String>, Local<Value>,
5315 const AccessorInfo&) {
5316 CHECK(false); // This function should nto be called.
5317}
5318
5319
Ben Murdochb0fe1622011-05-05 13:52:32 +01005320THREADED_TEST(AccessControl) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005321 v8::HandleScope handle_scope;
5322 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
5323
5324 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
5325 IndexedAccessBlocker);
5326
5327 // Add an accessor accessible by cross-domain JS code.
5328 global_template->SetAccessor(
5329 v8_str("accessible_prop"),
5330 EchoGetter, EchoSetter,
5331 v8::Handle<Value>(),
5332 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
5333
5334 // Add an accessor that is not accessible by cross-domain JS code.
5335 global_template->SetAccessor(v8_str("blocked_prop"),
5336 UnreachableGetter, UnreachableSetter,
5337 v8::Handle<Value>(),
5338 v8::DEFAULT);
5339
5340 // Create an environment
5341 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
5342 context0->Enter();
5343
5344 v8::Handle<v8::Object> global0 = context0->Global();
5345
5346 v8::HandleScope scope1;
5347
5348 v8::Persistent<Context> context1 = Context::New();
5349 context1->Enter();
5350
5351 v8::Handle<v8::Object> global1 = context1->Global();
5352 global1->Set(v8_str("other"), global0);
5353
5354 v8::Handle<Value> value;
5355
Ben Murdochb0fe1622011-05-05 13:52:32 +01005356 // Access blocked property
5357 value = v8_compile("other.blocked_prop = 1")->Run();
5358 value = v8_compile("other.blocked_prop")->Run();
5359 CHECK(value->IsUndefined());
5360
5361 value = v8_compile("propertyIsEnumerable.call(other, 'blocked_prop')")->Run();
5362 CHECK(value->IsFalse());
5363
Steve Blocka7e24c12009-10-30 11:49:00 +00005364 // Access accessible property
Ben Murdochb0fe1622011-05-05 13:52:32 +01005365 value = v8_compile("other.accessible_prop = 3")->Run();
Steve Blocka7e24c12009-10-30 11:49:00 +00005366 CHECK(value->IsNumber());
5367 CHECK_EQ(3, value->Int32Value());
Andrei Popescu31002712010-02-23 13:46:05 +00005368 CHECK_EQ(3, g_echo_value);
Steve Blocka7e24c12009-10-30 11:49:00 +00005369
Ben Murdochb0fe1622011-05-05 13:52:32 +01005370 value = v8_compile("other.accessible_prop")->Run();
Steve Blocka7e24c12009-10-30 11:49:00 +00005371 CHECK(value->IsNumber());
5372 CHECK_EQ(3, value->Int32Value());
5373
Ben Murdochb0fe1622011-05-05 13:52:32 +01005374 value =
5375 v8_compile("propertyIsEnumerable.call(other, 'accessible_prop')")->Run();
Steve Blocka7e24c12009-10-30 11:49:00 +00005376 CHECK(value->IsTrue());
5377
5378 // Enumeration doesn't enumerate accessors from inaccessible objects in
5379 // the prototype chain even if the accessors are in themselves accessible.
Ben Murdochb0fe1622011-05-05 13:52:32 +01005380 Local<Value> result =
Steve Blocka7e24c12009-10-30 11:49:00 +00005381 CompileRun("(function(){var obj = {'__proto__':other};"
5382 "for (var p in obj)"
5383 " if (p == 'accessible_prop' || p == 'blocked_prop') {"
5384 " return false;"
5385 " }"
5386 "return true;})()");
Ben Murdochb0fe1622011-05-05 13:52:32 +01005387 CHECK(result->IsTrue());
Steve Blocka7e24c12009-10-30 11:49:00 +00005388
5389 context1->Exit();
5390 context0->Exit();
5391 context1.Dispose();
5392 context0.Dispose();
5393}
5394
5395
Leon Clarke4515c472010-02-03 11:58:03 +00005396static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
5397 Local<Value> name,
5398 v8::AccessType type,
5399 Local<Value> data) {
5400 return false;
5401}
5402
5403
5404static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
5405 uint32_t key,
5406 v8::AccessType type,
5407 Local<Value> data) {
5408 return false;
5409}
5410
5411
5412THREADED_TEST(AccessControlGetOwnPropertyNames) {
5413 v8::HandleScope handle_scope;
5414 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
5415
5416 obj_template->Set(v8_str("x"), v8::Integer::New(42));
5417 obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
5418 GetOwnPropertyNamesIndexedBlocker);
5419
5420 // Create an environment
5421 v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
5422 context0->Enter();
5423
5424 v8::Handle<v8::Object> global0 = context0->Global();
5425
5426 v8::HandleScope scope1;
5427
5428 v8::Persistent<Context> context1 = Context::New();
5429 context1->Enter();
5430
5431 v8::Handle<v8::Object> global1 = context1->Global();
5432 global1->Set(v8_str("other"), global0);
5433 global1->Set(v8_str("object"), obj_template->NewInstance());
5434
5435 v8::Handle<Value> value;
5436
5437 // Attempt to get the property names of the other global object and
5438 // of an object that requires access checks. Accessing the other
5439 // global object should be blocked by access checks on the global
5440 // proxy object. Accessing the object that requires access checks
5441 // is blocked by the access checks on the object itself.
5442 value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
5443 CHECK(value->IsTrue());
5444
5445 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
5446 CHECK(value->IsTrue());
5447
5448 context1->Exit();
5449 context0->Exit();
5450 context1.Dispose();
5451 context0.Dispose();
5452}
5453
5454
Steve Block8defd9f2010-07-08 12:39:36 +01005455static v8::Handle<v8::Array> NamedPropertyEnumerator(const AccessorInfo& info) {
5456 v8::Handle<v8::Array> result = v8::Array::New(1);
5457 result->Set(0, v8_str("x"));
5458 return result;
5459}
5460
5461
5462THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
5463 v8::HandleScope handle_scope;
5464 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
5465
5466 obj_template->Set(v8_str("x"), v8::Integer::New(42));
5467 obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
5468 NamedPropertyEnumerator);
5469
5470 LocalContext context;
5471 v8::Handle<v8::Object> global = context->Global();
5472 global->Set(v8_str("object"), obj_template->NewInstance());
5473
5474 v8::Handle<Value> value =
5475 CompileRun("Object.getOwnPropertyNames(object).join(',')");
5476 CHECK_EQ(v8_str("x"), value);
5477}
5478
5479
Steve Blocka7e24c12009-10-30 11:49:00 +00005480static v8::Handle<Value> ConstTenGetter(Local<String> name,
5481 const AccessorInfo& info) {
5482 return v8_num(10);
5483}
5484
5485
5486THREADED_TEST(CrossDomainAccessors) {
5487 v8::HandleScope handle_scope;
5488
5489 v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
5490
5491 v8::Handle<v8::ObjectTemplate> global_template =
5492 func_template->InstanceTemplate();
5493
5494 v8::Handle<v8::ObjectTemplate> proto_template =
5495 func_template->PrototypeTemplate();
5496
5497 // Add an accessor to proto that's accessible by cross-domain JS code.
5498 proto_template->SetAccessor(v8_str("accessible"),
5499 ConstTenGetter, 0,
5500 v8::Handle<Value>(),
5501 v8::ALL_CAN_READ);
5502
5503 // Add an accessor that is not accessible by cross-domain JS code.
5504 global_template->SetAccessor(v8_str("unreachable"),
5505 UnreachableGetter, 0,
5506 v8::Handle<Value>(),
5507 v8::DEFAULT);
5508
5509 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
5510 context0->Enter();
5511
5512 Local<v8::Object> global = context0->Global();
5513 // Add a normal property that shadows 'accessible'
5514 global->Set(v8_str("accessible"), v8_num(11));
5515
5516 // Enter a new context.
5517 v8::HandleScope scope1;
5518 v8::Persistent<Context> context1 = Context::New();
5519 context1->Enter();
5520
5521 v8::Handle<v8::Object> global1 = context1->Global();
5522 global1->Set(v8_str("other"), global);
5523
5524 // Should return 10, instead of 11
5525 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
5526 CHECK(value->IsNumber());
5527 CHECK_EQ(10, value->Int32Value());
5528
5529 value = v8_compile("other.unreachable")->Run();
5530 CHECK(value->IsUndefined());
5531
5532 context1->Exit();
5533 context0->Exit();
5534 context1.Dispose();
5535 context0.Dispose();
5536}
5537
5538
5539static int named_access_count = 0;
5540static int indexed_access_count = 0;
5541
5542static bool NamedAccessCounter(Local<v8::Object> global,
5543 Local<Value> name,
5544 v8::AccessType type,
5545 Local<Value> data) {
5546 named_access_count++;
5547 return true;
5548}
5549
5550
5551static bool IndexedAccessCounter(Local<v8::Object> global,
5552 uint32_t key,
5553 v8::AccessType type,
5554 Local<Value> data) {
5555 indexed_access_count++;
5556 return true;
5557}
5558
5559
5560// This one is too easily disturbed by other tests.
5561TEST(AccessControlIC) {
5562 named_access_count = 0;
5563 indexed_access_count = 0;
5564
5565 v8::HandleScope handle_scope;
5566
5567 // Create an environment.
5568 v8::Persistent<Context> context0 = Context::New();
5569 context0->Enter();
5570
5571 // Create an object that requires access-check functions to be
5572 // called for cross-domain access.
5573 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
5574 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
5575 IndexedAccessCounter);
5576 Local<v8::Object> object = object_template->NewInstance();
5577
5578 v8::HandleScope scope1;
5579
5580 // Create another environment.
5581 v8::Persistent<Context> context1 = Context::New();
5582 context1->Enter();
5583
5584 // Make easy access to the object from the other environment.
5585 v8::Handle<v8::Object> global1 = context1->Global();
5586 global1->Set(v8_str("obj"), object);
5587
5588 v8::Handle<Value> value;
5589
5590 // Check that the named access-control function is called every time.
5591 CompileRun("function testProp(obj) {"
5592 " for (var i = 0; i < 10; i++) obj.prop = 1;"
5593 " for (var j = 0; j < 10; j++) obj.prop;"
5594 " return obj.prop"
5595 "}");
5596 value = CompileRun("testProp(obj)");
5597 CHECK(value->IsNumber());
5598 CHECK_EQ(1, value->Int32Value());
5599 CHECK_EQ(21, named_access_count);
5600
5601 // Check that the named access-control function is called every time.
5602 CompileRun("var p = 'prop';"
5603 "function testKeyed(obj) {"
5604 " for (var i = 0; i < 10; i++) obj[p] = 1;"
5605 " for (var j = 0; j < 10; j++) obj[p];"
5606 " return obj[p];"
5607 "}");
5608 // Use obj which requires access checks. No inline caching is used
5609 // in that case.
5610 value = CompileRun("testKeyed(obj)");
5611 CHECK(value->IsNumber());
5612 CHECK_EQ(1, value->Int32Value());
5613 CHECK_EQ(42, named_access_count);
5614 // Force the inline caches into generic state and try again.
5615 CompileRun("testKeyed({ a: 0 })");
5616 CompileRun("testKeyed({ b: 0 })");
5617 value = CompileRun("testKeyed(obj)");
5618 CHECK(value->IsNumber());
5619 CHECK_EQ(1, value->Int32Value());
5620 CHECK_EQ(63, named_access_count);
5621
5622 // Check that the indexed access-control function is called every time.
5623 CompileRun("function testIndexed(obj) {"
5624 " for (var i = 0; i < 10; i++) obj[0] = 1;"
5625 " for (var j = 0; j < 10; j++) obj[0];"
5626 " return obj[0]"
5627 "}");
5628 value = CompileRun("testIndexed(obj)");
5629 CHECK(value->IsNumber());
5630 CHECK_EQ(1, value->Int32Value());
5631 CHECK_EQ(21, indexed_access_count);
5632 // Force the inline caches into generic state.
5633 CompileRun("testIndexed(new Array(1))");
5634 // Test that the indexed access check is called.
5635 value = CompileRun("testIndexed(obj)");
5636 CHECK(value->IsNumber());
5637 CHECK_EQ(1, value->Int32Value());
5638 CHECK_EQ(42, indexed_access_count);
5639
5640 // Check that the named access check is called when invoking
5641 // functions on an object that requires access checks.
5642 CompileRun("obj.f = function() {}");
5643 CompileRun("function testCallNormal(obj) {"
5644 " for (var i = 0; i < 10; i++) obj.f();"
5645 "}");
5646 CompileRun("testCallNormal(obj)");
5647 CHECK_EQ(74, named_access_count);
5648
5649 // Force obj into slow case.
5650 value = CompileRun("delete obj.prop");
5651 CHECK(value->BooleanValue());
5652 // Force inline caches into dictionary probing mode.
5653 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
5654 // Test that the named access check is called.
5655 value = CompileRun("testProp(obj);");
5656 CHECK(value->IsNumber());
5657 CHECK_EQ(1, value->Int32Value());
5658 CHECK_EQ(96, named_access_count);
5659
5660 // Force the call inline cache into dictionary probing mode.
5661 CompileRun("o.f = function() {}; testCallNormal(o)");
5662 // Test that the named access check is still called for each
5663 // invocation of the function.
5664 value = CompileRun("testCallNormal(obj)");
5665 CHECK_EQ(106, named_access_count);
5666
5667 context1->Exit();
5668 context0->Exit();
5669 context1.Dispose();
5670 context0.Dispose();
5671}
5672
5673
5674static bool NamedAccessFlatten(Local<v8::Object> global,
5675 Local<Value> name,
5676 v8::AccessType type,
5677 Local<Value> data) {
5678 char buf[100];
5679 int len;
5680
5681 CHECK(name->IsString());
5682
5683 memset(buf, 0x1, sizeof(buf));
Steve Block6ded16b2010-05-10 14:33:55 +01005684 len = name.As<String>()->WriteAscii(buf);
Steve Blocka7e24c12009-10-30 11:49:00 +00005685 CHECK_EQ(4, len);
5686
5687 uint16_t buf2[100];
5688
5689 memset(buf, 0x1, sizeof(buf));
Steve Block6ded16b2010-05-10 14:33:55 +01005690 len = name.As<String>()->Write(buf2);
Steve Blocka7e24c12009-10-30 11:49:00 +00005691 CHECK_EQ(4, len);
5692
5693 return true;
5694}
5695
5696
5697static bool IndexedAccessFlatten(Local<v8::Object> global,
5698 uint32_t key,
5699 v8::AccessType type,
5700 Local<Value> data) {
5701 return true;
5702}
5703
5704
5705// Regression test. In access checks, operations that may cause
5706// garbage collection are not allowed. It used to be the case that
5707// using the Write operation on a string could cause a garbage
5708// collection due to flattening of the string. This is no longer the
5709// case.
5710THREADED_TEST(AccessControlFlatten) {
5711 named_access_count = 0;
5712 indexed_access_count = 0;
5713
5714 v8::HandleScope handle_scope;
5715
5716 // Create an environment.
5717 v8::Persistent<Context> context0 = Context::New();
5718 context0->Enter();
5719
5720 // Create an object that requires access-check functions to be
5721 // called for cross-domain access.
5722 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
5723 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
5724 IndexedAccessFlatten);
5725 Local<v8::Object> object = object_template->NewInstance();
5726
5727 v8::HandleScope scope1;
5728
5729 // Create another environment.
5730 v8::Persistent<Context> context1 = Context::New();
5731 context1->Enter();
5732
5733 // Make easy access to the object from the other environment.
5734 v8::Handle<v8::Object> global1 = context1->Global();
5735 global1->Set(v8_str("obj"), object);
5736
5737 v8::Handle<Value> value;
5738
5739 value = v8_compile("var p = 'as' + 'df';")->Run();
5740 value = v8_compile("obj[p];")->Run();
5741
5742 context1->Exit();
5743 context0->Exit();
5744 context1.Dispose();
5745 context0.Dispose();
5746}
5747
5748
5749static v8::Handle<Value> AccessControlNamedGetter(
5750 Local<String>, const AccessorInfo&) {
5751 return v8::Integer::New(42);
5752}
5753
5754
5755static v8::Handle<Value> AccessControlNamedSetter(
5756 Local<String>, Local<Value> value, const AccessorInfo&) {
5757 return value;
5758}
5759
5760
5761static v8::Handle<Value> AccessControlIndexedGetter(
5762 uint32_t index,
5763 const AccessorInfo& info) {
5764 return v8_num(42);
5765}
5766
5767
5768static v8::Handle<Value> AccessControlIndexedSetter(
5769 uint32_t, Local<Value> value, const AccessorInfo&) {
5770 return value;
5771}
5772
5773
5774THREADED_TEST(AccessControlInterceptorIC) {
5775 named_access_count = 0;
5776 indexed_access_count = 0;
5777
5778 v8::HandleScope handle_scope;
5779
5780 // Create an environment.
5781 v8::Persistent<Context> context0 = Context::New();
5782 context0->Enter();
5783
5784 // Create an object that requires access-check functions to be
5785 // called for cross-domain access. The object also has interceptors
5786 // interceptor.
5787 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
5788 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
5789 IndexedAccessCounter);
5790 object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
5791 AccessControlNamedSetter);
5792 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
5793 AccessControlIndexedSetter);
5794 Local<v8::Object> object = object_template->NewInstance();
5795
5796 v8::HandleScope scope1;
5797
5798 // Create another environment.
5799 v8::Persistent<Context> context1 = Context::New();
5800 context1->Enter();
5801
5802 // Make easy access to the object from the other environment.
5803 v8::Handle<v8::Object> global1 = context1->Global();
5804 global1->Set(v8_str("obj"), object);
5805
5806 v8::Handle<Value> value;
5807
5808 // Check that the named access-control function is called every time
5809 // eventhough there is an interceptor on the object.
5810 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
5811 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
5812 "obj.x")->Run();
5813 CHECK(value->IsNumber());
5814 CHECK_EQ(42, value->Int32Value());
5815 CHECK_EQ(21, named_access_count);
5816
5817 value = v8_compile("var p = 'x';")->Run();
5818 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
5819 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
5820 "obj[p]")->Run();
5821 CHECK(value->IsNumber());
5822 CHECK_EQ(42, value->Int32Value());
5823 CHECK_EQ(42, named_access_count);
5824
5825 // Check that the indexed access-control function is called every
5826 // time eventhough there is an interceptor on the object.
5827 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
5828 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
5829 "obj[0]")->Run();
5830 CHECK(value->IsNumber());
5831 CHECK_EQ(42, value->Int32Value());
5832 CHECK_EQ(21, indexed_access_count);
5833
5834 context1->Exit();
5835 context0->Exit();
5836 context1.Dispose();
5837 context0.Dispose();
5838}
5839
5840
5841THREADED_TEST(Version) {
5842 v8::V8::GetVersion();
5843}
5844
5845
5846static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
5847 ApiTestFuzzer::Fuzz();
5848 return v8_num(12);
5849}
5850
5851
5852THREADED_TEST(InstanceProperties) {
5853 v8::HandleScope handle_scope;
5854 LocalContext context;
5855
5856 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5857 Local<ObjectTemplate> instance = t->InstanceTemplate();
5858
5859 instance->Set(v8_str("x"), v8_num(42));
5860 instance->Set(v8_str("f"),
5861 v8::FunctionTemplate::New(InstanceFunctionCallback));
5862
5863 Local<Value> o = t->GetFunction()->NewInstance();
5864
5865 context->Global()->Set(v8_str("i"), o);
5866 Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
5867 CHECK_EQ(42, value->Int32Value());
5868
5869 value = Script::Compile(v8_str("i.f()"))->Run();
5870 CHECK_EQ(12, value->Int32Value());
5871}
5872
5873
5874static v8::Handle<Value>
5875GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
5876 ApiTestFuzzer::Fuzz();
5877 return v8::Handle<Value>();
5878}
5879
5880
5881THREADED_TEST(GlobalObjectInstanceProperties) {
5882 v8::HandleScope handle_scope;
5883
5884 Local<Value> global_object;
5885
5886 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5887 t->InstanceTemplate()->SetNamedPropertyHandler(
5888 GlobalObjectInstancePropertiesGet);
5889 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
5890 instance_template->Set(v8_str("x"), v8_num(42));
5891 instance_template->Set(v8_str("f"),
5892 v8::FunctionTemplate::New(InstanceFunctionCallback));
5893
Ben Murdochb0fe1622011-05-05 13:52:32 +01005894 // The script to check how Crankshaft compiles missing global function
5895 // invocations. function g is not defined and should throw on call.
5896 const char* script =
5897 "function wrapper(call) {"
5898 " var x = 0, y = 1;"
5899 " for (var i = 0; i < 1000; i++) {"
5900 " x += i * 100;"
5901 " y += i * 100;"
5902 " }"
5903 " if (call) g();"
5904 "}"
5905 "for (var i = 0; i < 17; i++) wrapper(false);"
5906 "var thrown = 0;"
5907 "try { wrapper(true); } catch (e) { thrown = 1; };"
5908 "thrown";
5909
Steve Blocka7e24c12009-10-30 11:49:00 +00005910 {
5911 LocalContext env(NULL, instance_template);
5912 // Hold on to the global object so it can be used again in another
5913 // environment initialization.
5914 global_object = env->Global();
5915
5916 Local<Value> value = Script::Compile(v8_str("x"))->Run();
5917 CHECK_EQ(42, value->Int32Value());
5918 value = Script::Compile(v8_str("f()"))->Run();
5919 CHECK_EQ(12, value->Int32Value());
Ben Murdochb0fe1622011-05-05 13:52:32 +01005920 value = Script::Compile(v8_str(script))->Run();
5921 CHECK_EQ(1, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00005922 }
5923
5924 {
5925 // Create new environment reusing the global object.
5926 LocalContext env(NULL, instance_template, global_object);
5927 Local<Value> value = Script::Compile(v8_str("x"))->Run();
5928 CHECK_EQ(42, value->Int32Value());
5929 value = Script::Compile(v8_str("f()"))->Run();
5930 CHECK_EQ(12, value->Int32Value());
Ben Murdochb0fe1622011-05-05 13:52:32 +01005931 value = Script::Compile(v8_str(script))->Run();
5932 CHECK_EQ(1, value->Int32Value());
5933 }
5934}
5935
5936
5937THREADED_TEST(CallKnownGlobalReceiver) {
5938 v8::HandleScope handle_scope;
5939
5940 Local<Value> global_object;
5941
5942 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5943 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
5944
5945 // The script to check that we leave global object not
5946 // global object proxy on stack when we deoptimize from inside
5947 // arguments evaluation.
5948 // To provoke error we need to both force deoptimization
5949 // from arguments evaluation and to force CallIC to take
5950 // CallIC_Miss code path that can't cope with global proxy.
5951 const char* script =
5952 "function bar(x, y) { try { } finally { } }"
5953 "function baz(x) { try { } finally { } }"
5954 "function bom(x) { try { } finally { } }"
5955 "function foo(x) { bar([x], bom(2)); }"
5956 "for (var i = 0; i < 10000; i++) foo(1);"
5957 "foo";
5958
5959 Local<Value> foo;
5960 {
5961 LocalContext env(NULL, instance_template);
5962 // Hold on to the global object so it can be used again in another
5963 // environment initialization.
5964 global_object = env->Global();
5965 foo = Script::Compile(v8_str(script))->Run();
5966 }
5967
5968 {
5969 // Create new environment reusing the global object.
5970 LocalContext env(NULL, instance_template, global_object);
5971 env->Global()->Set(v8_str("foo"), foo);
5972 Local<Value> value = Script::Compile(v8_str("foo()"))->Run();
Steve Blocka7e24c12009-10-30 11:49:00 +00005973 }
5974}
5975
5976
5977static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
5978 ApiTestFuzzer::Fuzz();
5979 return v8_num(42);
5980}
5981
5982
5983static int shadow_y;
5984static int shadow_y_setter_call_count;
5985static int shadow_y_getter_call_count;
5986
5987
5988static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
5989 shadow_y_setter_call_count++;
5990 shadow_y = 42;
5991}
5992
5993
5994static v8::Handle<Value> ShadowYGetter(Local<String> name,
5995 const AccessorInfo& info) {
5996 ApiTestFuzzer::Fuzz();
5997 shadow_y_getter_call_count++;
5998 return v8_num(shadow_y);
5999}
6000
6001
6002static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
6003 const AccessorInfo& info) {
6004 return v8::Handle<Value>();
6005}
6006
6007
6008static v8::Handle<Value> ShadowNamedGet(Local<String> key,
6009 const AccessorInfo&) {
6010 return v8::Handle<Value>();
6011}
6012
6013
6014THREADED_TEST(ShadowObject) {
6015 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
6016 v8::HandleScope handle_scope;
6017
6018 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
6019 LocalContext context(NULL, global_template);
6020
6021 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6022 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
6023 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
6024 Local<ObjectTemplate> proto = t->PrototypeTemplate();
6025 Local<ObjectTemplate> instance = t->InstanceTemplate();
6026
6027 // Only allow calls of f on instances of t.
6028 Local<v8::Signature> signature = v8::Signature::New(t);
6029 proto->Set(v8_str("f"),
6030 v8::FunctionTemplate::New(ShadowFunctionCallback,
6031 Local<Value>(),
6032 signature));
6033 proto->Set(v8_str("x"), v8_num(12));
6034
6035 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
6036
6037 Local<Value> o = t->GetFunction()->NewInstance();
6038 context->Global()->Set(v8_str("__proto__"), o);
6039
6040 Local<Value> value =
6041 Script::Compile(v8_str("propertyIsEnumerable(0)"))->Run();
6042 CHECK(value->IsBoolean());
6043 CHECK(!value->BooleanValue());
6044
6045 value = Script::Compile(v8_str("x"))->Run();
6046 CHECK_EQ(12, value->Int32Value());
6047
6048 value = Script::Compile(v8_str("f()"))->Run();
6049 CHECK_EQ(42, value->Int32Value());
6050
6051 Script::Compile(v8_str("y = 42"))->Run();
6052 CHECK_EQ(1, shadow_y_setter_call_count);
6053 value = Script::Compile(v8_str("y"))->Run();
6054 CHECK_EQ(1, shadow_y_getter_call_count);
6055 CHECK_EQ(42, value->Int32Value());
6056}
6057
6058
6059THREADED_TEST(HiddenPrototype) {
6060 v8::HandleScope handle_scope;
6061 LocalContext context;
6062
6063 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
6064 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
6065 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
6066 t1->SetHiddenPrototype(true);
6067 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
6068 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
6069 t2->SetHiddenPrototype(true);
6070 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
6071 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
6072 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
6073
6074 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
6075 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
6076 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
6077 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
6078
6079 // Setting the prototype on an object skips hidden prototypes.
6080 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6081 o0->Set(v8_str("__proto__"), o1);
6082 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6083 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6084 o0->Set(v8_str("__proto__"), o2);
6085 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6086 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6087 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6088 o0->Set(v8_str("__proto__"), o3);
6089 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6090 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6091 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6092 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
6093
6094 // Getting the prototype of o0 should get the first visible one
6095 // which is o3. Therefore, z should not be defined on the prototype
6096 // object.
6097 Local<Value> proto = o0->Get(v8_str("__proto__"));
6098 CHECK(proto->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01006099 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
Steve Blocka7e24c12009-10-30 11:49:00 +00006100}
6101
6102
Andrei Popescu402d9372010-02-26 13:31:12 +00006103THREADED_TEST(SetPrototype) {
6104 v8::HandleScope handle_scope;
6105 LocalContext context;
6106
6107 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
6108 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
6109 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
6110 t1->SetHiddenPrototype(true);
6111 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
6112 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
6113 t2->SetHiddenPrototype(true);
6114 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
6115 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
6116 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
6117
6118 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
6119 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
6120 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
6121 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
6122
6123 // Setting the prototype on an object does not skip hidden prototypes.
6124 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6125 CHECK(o0->SetPrototype(o1));
6126 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6127 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6128 CHECK(o1->SetPrototype(o2));
6129 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6130 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6131 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6132 CHECK(o2->SetPrototype(o3));
6133 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6134 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6135 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6136 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
6137
6138 // Getting the prototype of o0 should get the first visible one
6139 // which is o3. Therefore, z should not be defined on the prototype
6140 // object.
6141 Local<Value> proto = o0->Get(v8_str("__proto__"));
6142 CHECK(proto->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01006143 CHECK_EQ(proto.As<v8::Object>(), o3);
Andrei Popescu402d9372010-02-26 13:31:12 +00006144
6145 // However, Object::GetPrototype ignores hidden prototype.
6146 Local<Value> proto0 = o0->GetPrototype();
6147 CHECK(proto0->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01006148 CHECK_EQ(proto0.As<v8::Object>(), o1);
Andrei Popescu402d9372010-02-26 13:31:12 +00006149
6150 Local<Value> proto1 = o1->GetPrototype();
6151 CHECK(proto1->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01006152 CHECK_EQ(proto1.As<v8::Object>(), o2);
Andrei Popescu402d9372010-02-26 13:31:12 +00006153
6154 Local<Value> proto2 = o2->GetPrototype();
6155 CHECK(proto2->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01006156 CHECK_EQ(proto2.As<v8::Object>(), o3);
Andrei Popescu402d9372010-02-26 13:31:12 +00006157}
6158
6159
6160THREADED_TEST(SetPrototypeThrows) {
6161 v8::HandleScope handle_scope;
6162 LocalContext context;
6163
6164 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6165
6166 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
6167 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
6168
6169 CHECK(o0->SetPrototype(o1));
6170 // If setting the prototype leads to the cycle, SetPrototype should
6171 // return false and keep VM in sane state.
6172 v8::TryCatch try_catch;
6173 CHECK(!o1->SetPrototype(o0));
6174 CHECK(!try_catch.HasCaught());
6175 ASSERT(!i::Top::has_pending_exception());
6176
6177 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
6178}
6179
6180
Steve Blocka7e24c12009-10-30 11:49:00 +00006181THREADED_TEST(GetterSetterExceptions) {
6182 v8::HandleScope handle_scope;
6183 LocalContext context;
6184 CompileRun(
6185 "function Foo() { };"
6186 "function Throw() { throw 5; };"
6187 "var x = { };"
6188 "x.__defineSetter__('set', Throw);"
6189 "x.__defineGetter__('get', Throw);");
6190 Local<v8::Object> x =
6191 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
6192 v8::TryCatch try_catch;
6193 x->Set(v8_str("set"), v8::Integer::New(8));
6194 x->Get(v8_str("get"));
6195 x->Set(v8_str("set"), v8::Integer::New(8));
6196 x->Get(v8_str("get"));
6197 x->Set(v8_str("set"), v8::Integer::New(8));
6198 x->Get(v8_str("get"));
6199 x->Set(v8_str("set"), v8::Integer::New(8));
6200 x->Get(v8_str("get"));
6201}
6202
6203
6204THREADED_TEST(Constructor) {
6205 v8::HandleScope handle_scope;
6206 LocalContext context;
6207 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
6208 templ->SetClassName(v8_str("Fun"));
6209 Local<Function> cons = templ->GetFunction();
6210 context->Global()->Set(v8_str("Fun"), cons);
6211 Local<v8::Object> inst = cons->NewInstance();
6212 i::Handle<i::JSObject> obj = v8::Utils::OpenHandle(*inst);
6213 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
6214 CHECK(value->BooleanValue());
6215}
6216
6217THREADED_TEST(FunctionDescriptorException) {
6218 v8::HandleScope handle_scope;
6219 LocalContext context;
6220 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
6221 templ->SetClassName(v8_str("Fun"));
6222 Local<Function> cons = templ->GetFunction();
6223 context->Global()->Set(v8_str("Fun"), cons);
6224 Local<Value> value = CompileRun(
6225 "function test() {"
6226 " try {"
6227 " (new Fun()).blah()"
6228 " } catch (e) {"
6229 " var str = String(e);"
6230 " if (str.indexOf('TypeError') == -1) return 1;"
6231 " if (str.indexOf('[object Fun]') != -1) return 2;"
6232 " if (str.indexOf('#<a Fun>') == -1) return 3;"
6233 " return 0;"
6234 " }"
6235 " return 4;"
6236 "}"
6237 "test();");
6238 CHECK_EQ(0, value->Int32Value());
6239}
6240
6241
6242THREADED_TEST(EvalAliasedDynamic) {
6243 v8::HandleScope scope;
6244 LocalContext current;
6245
6246 // Tests where aliased eval can only be resolved dynamically.
6247 Local<Script> script =
6248 Script::Compile(v8_str("function f(x) { "
6249 " var foo = 2;"
6250 " with (x) { return eval('foo'); }"
6251 "}"
6252 "foo = 0;"
6253 "result1 = f(new Object());"
6254 "result2 = f(this);"
6255 "var x = new Object();"
6256 "x.eval = function(x) { return 1; };"
6257 "result3 = f(x);"));
6258 script->Run();
6259 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
6260 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
6261 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
6262
6263 v8::TryCatch try_catch;
6264 script =
6265 Script::Compile(v8_str("function f(x) { "
6266 " var bar = 2;"
6267 " with (x) { return eval('bar'); }"
6268 "}"
6269 "f(this)"));
6270 script->Run();
6271 CHECK(try_catch.HasCaught());
6272 try_catch.Reset();
6273}
6274
6275
6276THREADED_TEST(CrossEval) {
6277 v8::HandleScope scope;
6278 LocalContext other;
6279 LocalContext current;
6280
6281 Local<String> token = v8_str("<security token>");
6282 other->SetSecurityToken(token);
6283 current->SetSecurityToken(token);
6284
6285 // Setup reference from current to other.
6286 current->Global()->Set(v8_str("other"), other->Global());
6287
6288 // Check that new variables are introduced in other context.
6289 Local<Script> script =
6290 Script::Compile(v8_str("other.eval('var foo = 1234')"));
6291 script->Run();
6292 Local<Value> foo = other->Global()->Get(v8_str("foo"));
6293 CHECK_EQ(1234, foo->Int32Value());
6294 CHECK(!current->Global()->Has(v8_str("foo")));
6295
6296 // Check that writing to non-existing properties introduces them in
6297 // the other context.
6298 script =
6299 Script::Compile(v8_str("other.eval('na = 1234')"));
6300 script->Run();
6301 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
6302 CHECK(!current->Global()->Has(v8_str("na")));
6303
6304 // Check that global variables in current context are not visible in other
6305 // context.
6306 v8::TryCatch try_catch;
6307 script =
6308 Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
6309 Local<Value> result = script->Run();
6310 CHECK(try_catch.HasCaught());
6311 try_catch.Reset();
6312
6313 // Check that local variables in current context are not visible in other
6314 // context.
6315 script =
6316 Script::Compile(v8_str("(function() { "
6317 " var baz = 87;"
6318 " return other.eval('baz');"
6319 "})();"));
6320 result = script->Run();
6321 CHECK(try_catch.HasCaught());
6322 try_catch.Reset();
6323
6324 // Check that global variables in the other environment are visible
6325 // when evaluting code.
6326 other->Global()->Set(v8_str("bis"), v8_num(1234));
6327 script = Script::Compile(v8_str("other.eval('bis')"));
6328 CHECK_EQ(1234, script->Run()->Int32Value());
6329 CHECK(!try_catch.HasCaught());
6330
6331 // Check that the 'this' pointer points to the global object evaluating
6332 // code.
6333 other->Global()->Set(v8_str("t"), other->Global());
6334 script = Script::Compile(v8_str("other.eval('this == t')"));
6335 result = script->Run();
6336 CHECK(result->IsTrue());
6337 CHECK(!try_catch.HasCaught());
6338
6339 // Check that variables introduced in with-statement are not visible in
6340 // other context.
6341 script =
6342 Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
6343 result = script->Run();
6344 CHECK(try_catch.HasCaught());
6345 try_catch.Reset();
6346
6347 // Check that you cannot use 'eval.call' with another object than the
6348 // current global object.
6349 script =
6350 Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
6351 result = script->Run();
6352 CHECK(try_catch.HasCaught());
6353}
6354
6355
6356// Test that calling eval in a context which has been detached from
6357// its global throws an exception. This behavior is consistent with
6358// other JavaScript implementations.
6359THREADED_TEST(EvalInDetachedGlobal) {
6360 v8::HandleScope scope;
6361
6362 v8::Persistent<Context> context0 = Context::New();
6363 v8::Persistent<Context> context1 = Context::New();
6364
6365 // Setup function in context0 that uses eval from context0.
6366 context0->Enter();
6367 v8::Handle<v8::Value> fun =
6368 CompileRun("var x = 42;"
6369 "(function() {"
6370 " var e = eval;"
6371 " return function(s) { return e(s); }"
6372 "})()");
6373 context0->Exit();
6374
6375 // Put the function into context1 and call it before and after
6376 // detaching the global. Before detaching, the call succeeds and
6377 // after detaching and exception is thrown.
6378 context1->Enter();
6379 context1->Global()->Set(v8_str("fun"), fun);
6380 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
6381 CHECK_EQ(42, x_value->Int32Value());
6382 context0->DetachGlobal();
6383 v8::TryCatch catcher;
6384 x_value = CompileRun("fun('x')");
6385 CHECK(x_value.IsEmpty());
6386 CHECK(catcher.HasCaught());
6387 context1->Exit();
6388
6389 context1.Dispose();
6390 context0.Dispose();
6391}
6392
6393
6394THREADED_TEST(CrossLazyLoad) {
6395 v8::HandleScope scope;
6396 LocalContext other;
6397 LocalContext current;
6398
6399 Local<String> token = v8_str("<security token>");
6400 other->SetSecurityToken(token);
6401 current->SetSecurityToken(token);
6402
6403 // Setup reference from current to other.
6404 current->Global()->Set(v8_str("other"), other->Global());
6405
6406 // Trigger lazy loading in other context.
6407 Local<Script> script =
6408 Script::Compile(v8_str("other.eval('new Date(42)')"));
6409 Local<Value> value = script->Run();
6410 CHECK_EQ(42.0, value->NumberValue());
6411}
6412
6413
6414static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
Andrei Popescu402d9372010-02-26 13:31:12 +00006415 ApiTestFuzzer::Fuzz();
Steve Blocka7e24c12009-10-30 11:49:00 +00006416 if (args.IsConstructCall()) {
6417 if (args[0]->IsInt32()) {
6418 return v8_num(-args[0]->Int32Value());
6419 }
6420 }
6421
6422 return args[0];
6423}
6424
6425
6426// Test that a call handler can be set for objects which will allow
6427// non-function objects created through the API to be called as
6428// functions.
6429THREADED_TEST(CallAsFunction) {
6430 v8::HandleScope scope;
6431 LocalContext context;
6432
6433 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6434 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
6435 instance_template->SetCallAsFunctionHandler(call_as_function);
6436 Local<v8::Object> instance = t->GetFunction()->NewInstance();
6437 context->Global()->Set(v8_str("obj"), instance);
6438 v8::TryCatch try_catch;
6439 Local<Value> value;
6440 CHECK(!try_catch.HasCaught());
6441
6442 value = CompileRun("obj(42)");
6443 CHECK(!try_catch.HasCaught());
6444 CHECK_EQ(42, value->Int32Value());
6445
6446 value = CompileRun("(function(o){return o(49)})(obj)");
6447 CHECK(!try_catch.HasCaught());
6448 CHECK_EQ(49, value->Int32Value());
6449
6450 // test special case of call as function
6451 value = CompileRun("[obj]['0'](45)");
6452 CHECK(!try_catch.HasCaught());
6453 CHECK_EQ(45, value->Int32Value());
6454
6455 value = CompileRun("obj.call = Function.prototype.call;"
6456 "obj.call(null, 87)");
6457 CHECK(!try_catch.HasCaught());
6458 CHECK_EQ(87, value->Int32Value());
6459
6460 // Regression tests for bug #1116356: Calling call through call/apply
6461 // must work for non-function receivers.
6462 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
6463 value = CompileRun(apply_99);
6464 CHECK(!try_catch.HasCaught());
6465 CHECK_EQ(99, value->Int32Value());
6466
6467 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
6468 value = CompileRun(call_17);
6469 CHECK(!try_catch.HasCaught());
6470 CHECK_EQ(17, value->Int32Value());
6471
6472 // Check that the call-as-function handler can be called through
Leon Clarkee46be812010-01-19 14:06:41 +00006473 // new.
Steve Blocka7e24c12009-10-30 11:49:00 +00006474 value = CompileRun("new obj(43)");
6475 CHECK(!try_catch.HasCaught());
6476 CHECK_EQ(-43, value->Int32Value());
6477}
6478
6479
6480static int CountHandles() {
6481 return v8::HandleScope::NumberOfHandles();
6482}
6483
6484
6485static int Recurse(int depth, int iterations) {
6486 v8::HandleScope scope;
6487 if (depth == 0) return CountHandles();
6488 for (int i = 0; i < iterations; i++) {
6489 Local<v8::Number> n = v8::Integer::New(42);
6490 }
6491 return Recurse(depth - 1, iterations);
6492}
6493
6494
6495THREADED_TEST(HandleIteration) {
6496 static const int kIterations = 500;
6497 static const int kNesting = 200;
6498 CHECK_EQ(0, CountHandles());
6499 {
6500 v8::HandleScope scope1;
6501 CHECK_EQ(0, CountHandles());
6502 for (int i = 0; i < kIterations; i++) {
6503 Local<v8::Number> n = v8::Integer::New(42);
6504 CHECK_EQ(i + 1, CountHandles());
6505 }
6506
6507 CHECK_EQ(kIterations, CountHandles());
6508 {
6509 v8::HandleScope scope2;
6510 for (int j = 0; j < kIterations; j++) {
6511 Local<v8::Number> n = v8::Integer::New(42);
6512 CHECK_EQ(j + 1 + kIterations, CountHandles());
6513 }
6514 }
6515 CHECK_EQ(kIterations, CountHandles());
6516 }
6517 CHECK_EQ(0, CountHandles());
6518 CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
6519}
6520
6521
6522static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
6523 Local<String> name,
6524 const AccessorInfo& info) {
6525 ApiTestFuzzer::Fuzz();
6526 return v8::Handle<Value>();
6527}
6528
6529
6530THREADED_TEST(InterceptorHasOwnProperty) {
6531 v8::HandleScope scope;
6532 LocalContext context;
6533 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6534 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
6535 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
6536 Local<Function> function = fun_templ->GetFunction();
6537 context->Global()->Set(v8_str("constructor"), function);
6538 v8::Handle<Value> value = CompileRun(
6539 "var o = new constructor();"
6540 "o.hasOwnProperty('ostehaps');");
6541 CHECK_EQ(false, value->BooleanValue());
6542 value = CompileRun(
6543 "o.ostehaps = 42;"
6544 "o.hasOwnProperty('ostehaps');");
6545 CHECK_EQ(true, value->BooleanValue());
6546 value = CompileRun(
6547 "var p = new constructor();"
6548 "p.hasOwnProperty('ostehaps');");
6549 CHECK_EQ(false, value->BooleanValue());
6550}
6551
6552
6553static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
6554 Local<String> name,
6555 const AccessorInfo& info) {
6556 ApiTestFuzzer::Fuzz();
6557 i::Heap::CollectAllGarbage(false);
6558 return v8::Handle<Value>();
6559}
6560
6561
6562THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
6563 v8::HandleScope scope;
6564 LocalContext context;
6565 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6566 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
6567 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
6568 Local<Function> function = fun_templ->GetFunction();
6569 context->Global()->Set(v8_str("constructor"), function);
6570 // Let's first make some stuff so we can be sure to get a good GC.
6571 CompileRun(
6572 "function makestr(size) {"
6573 " switch (size) {"
6574 " case 1: return 'f';"
6575 " case 2: return 'fo';"
6576 " case 3: return 'foo';"
6577 " }"
6578 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
6579 "}"
6580 "var x = makestr(12345);"
6581 "x = makestr(31415);"
6582 "x = makestr(23456);");
6583 v8::Handle<Value> value = CompileRun(
6584 "var o = new constructor();"
6585 "o.__proto__ = new String(x);"
6586 "o.hasOwnProperty('ostehaps');");
6587 CHECK_EQ(false, value->BooleanValue());
6588}
6589
6590
6591typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
6592 const AccessorInfo& info);
6593
6594
6595static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
6596 const char* source,
6597 int expected) {
6598 v8::HandleScope scope;
6599 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08006600 templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
Steve Blocka7e24c12009-10-30 11:49:00 +00006601 LocalContext context;
6602 context->Global()->Set(v8_str("o"), templ->NewInstance());
6603 v8::Handle<Value> value = CompileRun(source);
6604 CHECK_EQ(expected, value->Int32Value());
6605}
6606
6607
6608static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
6609 const AccessorInfo& info) {
6610 ApiTestFuzzer::Fuzz();
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08006611 CHECK_EQ(v8_str("data"), info.Data());
6612 CHECK_EQ(v8_str("x"), name);
Steve Blocka7e24c12009-10-30 11:49:00 +00006613 return v8::Integer::New(42);
6614}
6615
6616
6617// This test should hit the load IC for the interceptor case.
6618THREADED_TEST(InterceptorLoadIC) {
6619 CheckInterceptorLoadIC(InterceptorLoadICGetter,
6620 "var result = 0;"
6621 "for (var i = 0; i < 1000; i++) {"
6622 " result = o.x;"
6623 "}",
6624 42);
6625}
6626
6627
6628// Below go several tests which verify that JITing for various
6629// configurations of interceptor and explicit fields works fine
6630// (those cases are special cased to get better performance).
6631
6632static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
6633 const AccessorInfo& info) {
6634 ApiTestFuzzer::Fuzz();
6635 return v8_str("x")->Equals(name)
6636 ? v8::Integer::New(42) : v8::Handle<v8::Value>();
6637}
6638
6639
6640THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
6641 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6642 "var result = 0;"
6643 "o.y = 239;"
6644 "for (var i = 0; i < 1000; i++) {"
6645 " result = o.y;"
6646 "}",
6647 239);
6648}
6649
6650
6651THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
6652 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6653 "var result = 0;"
6654 "o.__proto__ = { 'y': 239 };"
6655 "for (var i = 0; i < 1000; i++) {"
6656 " result = o.y + o.x;"
6657 "}",
6658 239 + 42);
6659}
6660
6661
6662THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
6663 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6664 "var result = 0;"
6665 "o.__proto__.y = 239;"
6666 "for (var i = 0; i < 1000; i++) {"
6667 " result = o.y + o.x;"
6668 "}",
6669 239 + 42);
6670}
6671
6672
6673THREADED_TEST(InterceptorLoadICUndefined) {
6674 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6675 "var result = 0;"
6676 "for (var i = 0; i < 1000; i++) {"
6677 " result = (o.y == undefined) ? 239 : 42;"
6678 "}",
6679 239);
6680}
6681
6682
6683THREADED_TEST(InterceptorLoadICWithOverride) {
6684 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6685 "fst = new Object(); fst.__proto__ = o;"
6686 "snd = new Object(); snd.__proto__ = fst;"
6687 "var result1 = 0;"
6688 "for (var i = 0; i < 1000; i++) {"
6689 " result1 = snd.x;"
6690 "}"
6691 "fst.x = 239;"
6692 "var result = 0;"
6693 "for (var i = 0; i < 1000; i++) {"
6694 " result = snd.x;"
6695 "}"
6696 "result + result1",
6697 239 + 42);
6698}
6699
6700
6701// Test the case when we stored field into
6702// a stub, but interceptor produced value on its own.
6703THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
6704 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6705 "proto = new Object();"
6706 "o.__proto__ = proto;"
6707 "proto.x = 239;"
6708 "for (var i = 0; i < 1000; i++) {"
6709 " o.x;"
6710 // Now it should be ICed and keep a reference to x defined on proto
6711 "}"
6712 "var result = 0;"
6713 "for (var i = 0; i < 1000; i++) {"
6714 " result += o.x;"
6715 "}"
6716 "result;",
6717 42 * 1000);
6718}
6719
6720
6721// Test the case when we stored field into
6722// a stub, but it got invalidated later on.
6723THREADED_TEST(InterceptorLoadICInvalidatedField) {
6724 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6725 "proto1 = new Object();"
6726 "proto2 = new Object();"
6727 "o.__proto__ = proto1;"
6728 "proto1.__proto__ = proto2;"
6729 "proto2.y = 239;"
6730 "for (var i = 0; i < 1000; i++) {"
6731 " o.y;"
6732 // Now it should be ICed and keep a reference to y defined on proto2
6733 "}"
6734 "proto1.y = 42;"
6735 "var result = 0;"
6736 "for (var i = 0; i < 1000; i++) {"
6737 " result += o.y;"
6738 "}"
6739 "result;",
6740 42 * 1000);
6741}
6742
6743
Steve Block6ded16b2010-05-10 14:33:55 +01006744static int interceptor_load_not_handled_calls = 0;
6745static v8::Handle<Value> InterceptorLoadNotHandled(Local<String> name,
6746 const AccessorInfo& info) {
6747 ++interceptor_load_not_handled_calls;
6748 return v8::Handle<v8::Value>();
6749}
6750
6751
6752// Test how post-interceptor lookups are done in the non-cacheable
6753// case: the interceptor should not be invoked during this lookup.
6754THREADED_TEST(InterceptorLoadICPostInterceptor) {
6755 interceptor_load_not_handled_calls = 0;
6756 CheckInterceptorLoadIC(InterceptorLoadNotHandled,
6757 "receiver = new Object();"
6758 "receiver.__proto__ = o;"
6759 "proto = new Object();"
6760 "/* Make proto a slow-case object. */"
6761 "for (var i = 0; i < 1000; i++) {"
6762 " proto[\"xxxxxxxx\" + i] = [];"
6763 "}"
6764 "proto.x = 17;"
6765 "o.__proto__ = proto;"
6766 "var result = 0;"
6767 "for (var i = 0; i < 1000; i++) {"
6768 " result += receiver.x;"
6769 "}"
6770 "result;",
6771 17 * 1000);
6772 CHECK_EQ(1000, interceptor_load_not_handled_calls);
6773}
6774
6775
Steve Blocka7e24c12009-10-30 11:49:00 +00006776// Test the case when we stored field into
6777// a stub, but it got invalidated later on due to override on
6778// global object which is between interceptor and fields' holders.
6779THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
6780 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6781 "o.__proto__ = this;" // set a global to be a proto of o.
6782 "this.__proto__.y = 239;"
6783 "for (var i = 0; i < 10; i++) {"
6784 " if (o.y != 239) throw 'oops: ' + o.y;"
6785 // Now it should be ICed and keep a reference to y defined on field_holder.
6786 "}"
6787 "this.y = 42;" // Assign on a global.
6788 "var result = 0;"
6789 "for (var i = 0; i < 10; i++) {"
6790 " result += o.y;"
6791 "}"
6792 "result;",
6793 42 * 10);
6794}
6795
6796
Steve Blocka7e24c12009-10-30 11:49:00 +00006797static void SetOnThis(Local<String> name,
6798 Local<Value> value,
6799 const AccessorInfo& info) {
6800 info.This()->ForceSet(name, value);
6801}
6802
6803
6804THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
6805 v8::HandleScope scope;
6806 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6807 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6808 templ->SetAccessor(v8_str("y"), Return239);
6809 LocalContext context;
6810 context->Global()->Set(v8_str("o"), templ->NewInstance());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006811
6812 // Check the case when receiver and interceptor's holder
6813 // are the same objects.
Steve Blocka7e24c12009-10-30 11:49:00 +00006814 v8::Handle<Value> value = CompileRun(
6815 "var result = 0;"
6816 "for (var i = 0; i < 7; i++) {"
6817 " result = o.y;"
6818 "}");
6819 CHECK_EQ(239, value->Int32Value());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006820
6821 // Check the case when interceptor's holder is in proto chain
6822 // of receiver.
6823 value = CompileRun(
6824 "r = { __proto__: o };"
6825 "var result = 0;"
6826 "for (var i = 0; i < 7; i++) {"
6827 " result = r.y;"
6828 "}");
6829 CHECK_EQ(239, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00006830}
6831
6832
6833THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
6834 v8::HandleScope scope;
6835 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6836 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6837 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6838 templ_p->SetAccessor(v8_str("y"), Return239);
6839
6840 LocalContext context;
6841 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6842 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6843
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006844 // Check the case when receiver and interceptor's holder
6845 // are the same objects.
Steve Blocka7e24c12009-10-30 11:49:00 +00006846 v8::Handle<Value> value = CompileRun(
6847 "o.__proto__ = p;"
6848 "var result = 0;"
6849 "for (var i = 0; i < 7; i++) {"
6850 " result = o.x + o.y;"
6851 "}");
6852 CHECK_EQ(239 + 42, value->Int32Value());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006853
6854 // Check the case when interceptor's holder is in proto chain
6855 // of receiver.
6856 value = CompileRun(
6857 "r = { __proto__: o };"
6858 "var result = 0;"
6859 "for (var i = 0; i < 7; i++) {"
6860 " result = r.x + r.y;"
6861 "}");
6862 CHECK_EQ(239 + 42, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00006863}
6864
6865
6866THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
6867 v8::HandleScope scope;
6868 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6869 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6870 templ->SetAccessor(v8_str("y"), Return239);
6871
6872 LocalContext context;
6873 context->Global()->Set(v8_str("o"), templ->NewInstance());
6874
6875 v8::Handle<Value> value = CompileRun(
6876 "fst = new Object(); fst.__proto__ = o;"
6877 "snd = new Object(); snd.__proto__ = fst;"
6878 "var result1 = 0;"
6879 "for (var i = 0; i < 7; i++) {"
6880 " result1 = snd.x;"
6881 "}"
6882 "fst.x = 239;"
6883 "var result = 0;"
6884 "for (var i = 0; i < 7; i++) {"
6885 " result = snd.x;"
6886 "}"
6887 "result + result1");
6888 CHECK_EQ(239 + 42, value->Int32Value());
6889}
6890
6891
6892// Test the case when we stored callback into
6893// a stub, but interceptor produced value on its own.
6894THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
6895 v8::HandleScope scope;
6896 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6897 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6898 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6899 templ_p->SetAccessor(v8_str("y"), Return239);
6900
6901 LocalContext context;
6902 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6903 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6904
6905 v8::Handle<Value> value = CompileRun(
6906 "o.__proto__ = p;"
6907 "for (var i = 0; i < 7; i++) {"
6908 " o.x;"
6909 // Now it should be ICed and keep a reference to x defined on p
6910 "}"
6911 "var result = 0;"
6912 "for (var i = 0; i < 7; i++) {"
6913 " result += o.x;"
6914 "}"
6915 "result");
6916 CHECK_EQ(42 * 7, value->Int32Value());
6917}
6918
6919
6920// Test the case when we stored callback into
6921// a stub, but it got invalidated later on.
6922THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
6923 v8::HandleScope scope;
6924 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6925 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6926 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6927 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
6928
6929 LocalContext context;
6930 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6931 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6932
6933 v8::Handle<Value> value = CompileRun(
6934 "inbetween = new Object();"
6935 "o.__proto__ = inbetween;"
6936 "inbetween.__proto__ = p;"
6937 "for (var i = 0; i < 10; i++) {"
6938 " o.y;"
6939 // Now it should be ICed and keep a reference to y defined on p
6940 "}"
6941 "inbetween.y = 42;"
6942 "var result = 0;"
6943 "for (var i = 0; i < 10; i++) {"
6944 " result += o.y;"
6945 "}"
6946 "result");
6947 CHECK_EQ(42 * 10, value->Int32Value());
6948}
6949
6950
6951// Test the case when we stored callback into
6952// a stub, but it got invalidated later on due to override on
6953// global object which is between interceptor and callbacks' holders.
6954THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
6955 v8::HandleScope scope;
6956 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6957 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6958 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6959 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
6960
6961 LocalContext context;
6962 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6963 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6964
6965 v8::Handle<Value> value = CompileRun(
6966 "o.__proto__ = this;"
6967 "this.__proto__ = p;"
6968 "for (var i = 0; i < 10; i++) {"
6969 " if (o.y != 239) throw 'oops: ' + o.y;"
6970 // Now it should be ICed and keep a reference to y defined on p
6971 "}"
6972 "this.y = 42;"
6973 "var result = 0;"
6974 "for (var i = 0; i < 10; i++) {"
6975 " result += o.y;"
6976 "}"
6977 "result");
6978 CHECK_EQ(42 * 10, value->Int32Value());
6979}
6980
6981
6982static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
6983 const AccessorInfo& info) {
6984 ApiTestFuzzer::Fuzz();
6985 CHECK(v8_str("x")->Equals(name));
6986 return v8::Integer::New(0);
6987}
6988
6989
6990THREADED_TEST(InterceptorReturningZero) {
6991 CheckInterceptorLoadIC(InterceptorLoadICGetter0,
6992 "o.x == undefined ? 1 : 0",
6993 0);
6994}
6995
6996
6997static v8::Handle<Value> InterceptorStoreICSetter(
6998 Local<String> key, Local<Value> value, const AccessorInfo&) {
6999 CHECK(v8_str("x")->Equals(key));
7000 CHECK_EQ(42, value->Int32Value());
7001 return value;
7002}
7003
7004
7005// This test should hit the store IC for the interceptor case.
7006THREADED_TEST(InterceptorStoreIC) {
7007 v8::HandleScope scope;
7008 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7009 templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08007010 InterceptorStoreICSetter,
7011 0, 0, 0, v8_str("data"));
Steve Blocka7e24c12009-10-30 11:49:00 +00007012 LocalContext context;
7013 context->Global()->Set(v8_str("o"), templ->NewInstance());
7014 v8::Handle<Value> value = CompileRun(
7015 "for (var i = 0; i < 1000; i++) {"
7016 " o.x = 42;"
7017 "}");
7018}
7019
7020
7021THREADED_TEST(InterceptorStoreICWithNoSetter) {
7022 v8::HandleScope scope;
7023 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7024 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7025 LocalContext context;
7026 context->Global()->Set(v8_str("o"), templ->NewInstance());
7027 v8::Handle<Value> value = CompileRun(
7028 "for (var i = 0; i < 1000; i++) {"
7029 " o.y = 239;"
7030 "}"
7031 "42 + o.y");
7032 CHECK_EQ(239 + 42, value->Int32Value());
7033}
7034
7035
7036
7037
7038v8::Handle<Value> call_ic_function;
7039v8::Handle<Value> call_ic_function2;
7040v8::Handle<Value> call_ic_function3;
7041
7042static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
7043 const AccessorInfo& info) {
7044 ApiTestFuzzer::Fuzz();
7045 CHECK(v8_str("x")->Equals(name));
7046 return call_ic_function;
7047}
7048
7049
7050// This test should hit the call IC for the interceptor case.
7051THREADED_TEST(InterceptorCallIC) {
7052 v8::HandleScope scope;
7053 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7054 templ->SetNamedPropertyHandler(InterceptorCallICGetter);
7055 LocalContext context;
7056 context->Global()->Set(v8_str("o"), templ->NewInstance());
7057 call_ic_function =
7058 v8_compile("function f(x) { return x + 1; }; f")->Run();
7059 v8::Handle<Value> value = CompileRun(
7060 "var result = 0;"
7061 "for (var i = 0; i < 1000; i++) {"
7062 " result = o.x(41);"
7063 "}");
7064 CHECK_EQ(42, value->Int32Value());
7065}
7066
7067
7068// This test checks that if interceptor doesn't provide
7069// a value, we can fetch regular value.
7070THREADED_TEST(InterceptorCallICSeesOthers) {
7071 v8::HandleScope scope;
7072 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7073 templ->SetNamedPropertyHandler(NoBlockGetterX);
7074 LocalContext context;
7075 context->Global()->Set(v8_str("o"), templ->NewInstance());
7076 v8::Handle<Value> value = CompileRun(
7077 "o.x = function f(x) { return x + 1; };"
7078 "var result = 0;"
7079 "for (var i = 0; i < 7; i++) {"
7080 " result = o.x(41);"
7081 "}");
7082 CHECK_EQ(42, value->Int32Value());
7083}
7084
7085
7086static v8::Handle<Value> call_ic_function4;
7087static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
7088 const AccessorInfo& info) {
7089 ApiTestFuzzer::Fuzz();
7090 CHECK(v8_str("x")->Equals(name));
7091 return call_ic_function4;
7092}
7093
7094
7095// This test checks that if interceptor provides a function,
7096// even if we cached shadowed variant, interceptor's function
7097// is invoked
7098THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
7099 v8::HandleScope scope;
7100 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7101 templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
7102 LocalContext context;
7103 context->Global()->Set(v8_str("o"), templ->NewInstance());
7104 call_ic_function4 =
7105 v8_compile("function f(x) { return x - 1; }; f")->Run();
7106 v8::Handle<Value> value = CompileRun(
7107 "o.__proto__.x = function(x) { return x + 1; };"
7108 "var result = 0;"
7109 "for (var i = 0; i < 1000; i++) {"
7110 " result = o.x(42);"
7111 "}");
7112 CHECK_EQ(41, value->Int32Value());
7113}
7114
7115
7116// Test the case when we stored cacheable lookup into
7117// a stub, but it got invalidated later on
7118THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
7119 v8::HandleScope scope;
7120 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7121 templ->SetNamedPropertyHandler(NoBlockGetterX);
7122 LocalContext context;
7123 context->Global()->Set(v8_str("o"), templ->NewInstance());
7124 v8::Handle<Value> value = CompileRun(
7125 "proto1 = new Object();"
7126 "proto2 = new Object();"
7127 "o.__proto__ = proto1;"
7128 "proto1.__proto__ = proto2;"
7129 "proto2.y = function(x) { return x + 1; };"
7130 // Invoke it many times to compile a stub
7131 "for (var i = 0; i < 7; i++) {"
7132 " o.y(42);"
7133 "}"
7134 "proto1.y = function(x) { return x - 1; };"
7135 "var result = 0;"
7136 "for (var i = 0; i < 7; i++) {"
7137 " result += o.y(42);"
7138 "}");
7139 CHECK_EQ(41 * 7, value->Int32Value());
7140}
7141
7142
7143static v8::Handle<Value> call_ic_function5;
7144static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
7145 const AccessorInfo& info) {
7146 ApiTestFuzzer::Fuzz();
7147 if (v8_str("x")->Equals(name))
7148 return call_ic_function5;
7149 else
7150 return Local<Value>();
7151}
7152
7153
7154// This test checks that if interceptor doesn't provide a function,
7155// cached constant function is used
7156THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
7157 v8::HandleScope scope;
7158 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7159 templ->SetNamedPropertyHandler(NoBlockGetterX);
7160 LocalContext context;
7161 context->Global()->Set(v8_str("o"), templ->NewInstance());
7162 v8::Handle<Value> value = CompileRun(
7163 "function inc(x) { return x + 1; };"
7164 "inc(1);"
7165 "o.x = inc;"
7166 "var result = 0;"
7167 "for (var i = 0; i < 1000; i++) {"
7168 " result = o.x(42);"
7169 "}");
7170 CHECK_EQ(43, value->Int32Value());
7171}
7172
7173
7174// This test checks that if interceptor provides a function,
7175// even if we cached constant function, interceptor's function
7176// is invoked
7177THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
7178 v8::HandleScope scope;
7179 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7180 templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
7181 LocalContext context;
7182 context->Global()->Set(v8_str("o"), templ->NewInstance());
7183 call_ic_function5 =
7184 v8_compile("function f(x) { return x - 1; }; f")->Run();
7185 v8::Handle<Value> value = CompileRun(
7186 "function inc(x) { return x + 1; };"
7187 "inc(1);"
7188 "o.x = inc;"
7189 "var result = 0;"
7190 "for (var i = 0; i < 1000; i++) {"
7191 " result = o.x(42);"
7192 "}");
7193 CHECK_EQ(41, value->Int32Value());
7194}
7195
7196
7197// Test the case when we stored constant function into
7198// a stub, but it got invalidated later on
7199THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
7200 v8::HandleScope scope;
7201 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7202 templ->SetNamedPropertyHandler(NoBlockGetterX);
7203 LocalContext context;
7204 context->Global()->Set(v8_str("o"), templ->NewInstance());
7205 v8::Handle<Value> value = CompileRun(
7206 "function inc(x) { return x + 1; };"
7207 "inc(1);"
7208 "proto1 = new Object();"
7209 "proto2 = new Object();"
7210 "o.__proto__ = proto1;"
7211 "proto1.__proto__ = proto2;"
7212 "proto2.y = inc;"
7213 // Invoke it many times to compile a stub
7214 "for (var i = 0; i < 7; i++) {"
7215 " o.y(42);"
7216 "}"
7217 "proto1.y = function(x) { return x - 1; };"
7218 "var result = 0;"
7219 "for (var i = 0; i < 7; i++) {"
7220 " result += o.y(42);"
7221 "}");
7222 CHECK_EQ(41 * 7, value->Int32Value());
7223}
7224
7225
7226// Test the case when we stored constant function into
7227// a stub, but it got invalidated later on due to override on
7228// global object which is between interceptor and constant function' holders.
7229THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
7230 v8::HandleScope scope;
7231 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7232 templ->SetNamedPropertyHandler(NoBlockGetterX);
7233 LocalContext context;
7234 context->Global()->Set(v8_str("o"), templ->NewInstance());
7235 v8::Handle<Value> value = CompileRun(
7236 "function inc(x) { return x + 1; };"
7237 "inc(1);"
7238 "o.__proto__ = this;"
7239 "this.__proto__.y = inc;"
7240 // Invoke it many times to compile a stub
7241 "for (var i = 0; i < 7; i++) {"
7242 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
7243 "}"
7244 "this.y = function(x) { return x - 1; };"
7245 "var result = 0;"
7246 "for (var i = 0; i < 7; i++) {"
7247 " result += o.y(42);"
7248 "}");
7249 CHECK_EQ(41 * 7, value->Int32Value());
7250}
7251
7252
Leon Clarke4515c472010-02-03 11:58:03 +00007253// Test the case when actual function to call sits on global object.
7254THREADED_TEST(InterceptorCallICCachedFromGlobal) {
7255 v8::HandleScope scope;
7256 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7257 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
7258
7259 LocalContext context;
7260 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7261
7262 v8::Handle<Value> value = CompileRun(
7263 "try {"
7264 " o.__proto__ = this;"
7265 " for (var i = 0; i < 10; i++) {"
7266 " var v = o.parseFloat('239');"
7267 " if (v != 239) throw v;"
7268 // Now it should be ICed and keep a reference to parseFloat.
7269 " }"
7270 " var result = 0;"
7271 " for (var i = 0; i < 10; i++) {"
7272 " result += o.parseFloat('239');"
7273 " }"
7274 " result"
7275 "} catch(e) {"
7276 " e"
7277 "};");
7278 CHECK_EQ(239 * 10, value->Int32Value());
7279}
7280
Andrei Popescu402d9372010-02-26 13:31:12 +00007281static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
7282 const AccessorInfo& info) {
7283 ApiTestFuzzer::Fuzz();
7284 int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data()));
7285 ++(*call_count);
7286 if ((*call_count) % 20 == 0) {
Steve Block8defd9f2010-07-08 12:39:36 +01007287 i::Heap::CollectAllGarbage(true);
Andrei Popescu402d9372010-02-26 13:31:12 +00007288 }
7289 return v8::Handle<Value>();
7290}
7291
7292static v8::Handle<Value> FastApiCallback_TrivialSignature(
7293 const v8::Arguments& args) {
7294 ApiTestFuzzer::Fuzz();
7295 CHECK_EQ(args.This(), args.Holder());
7296 CHECK(args.Data()->Equals(v8_str("method_data")));
7297 return v8::Integer::New(args[0]->Int32Value() + 1);
7298}
7299
7300static v8::Handle<Value> FastApiCallback_SimpleSignature(
7301 const v8::Arguments& args) {
7302 ApiTestFuzzer::Fuzz();
7303 CHECK_EQ(args.This()->GetPrototype(), args.Holder());
7304 CHECK(args.Data()->Equals(v8_str("method_data")));
7305 // Note, we're using HasRealNamedProperty instead of Has to avoid
7306 // invoking the interceptor again.
7307 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
7308 return v8::Integer::New(args[0]->Int32Value() + 1);
7309}
7310
7311// Helper to maximize the odds of object moving.
7312static void GenerateSomeGarbage() {
7313 CompileRun(
7314 "var garbage;"
7315 "for (var i = 0; i < 1000; i++) {"
7316 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
7317 "}"
7318 "garbage = undefined;");
7319}
7320
7321THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
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_TrivialSignature,
7327 v8_str("method_data"),
7328 v8::Handle<v8::Signature>());
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 "var result = 0;"
7341 "for (var i = 0; i < 100; i++) {"
7342 " result = o.method(41);"
7343 "}");
7344 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
7345 CHECK_EQ(100, interceptor_call_count);
7346}
7347
7348THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
7349 int interceptor_call_count = 0;
7350 v8::HandleScope scope;
7351 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7352 v8::Handle<v8::FunctionTemplate> method_templ =
7353 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7354 v8_str("method_data"),
7355 v8::Signature::New(fun_templ));
7356 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7357 proto_templ->Set(v8_str("method"), method_templ);
7358 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7359 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7360 NULL, NULL, NULL, NULL,
7361 v8::External::Wrap(&interceptor_call_count));
7362 LocalContext context;
7363 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7364 GenerateSomeGarbage();
7365 context->Global()->Set(v8_str("o"), fun->NewInstance());
7366 v8::Handle<Value> value = CompileRun(
7367 "o.foo = 17;"
7368 "var receiver = {};"
7369 "receiver.__proto__ = o;"
7370 "var result = 0;"
7371 "for (var i = 0; i < 100; i++) {"
7372 " result = receiver.method(41);"
7373 "}");
7374 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
7375 CHECK_EQ(100, interceptor_call_count);
7376}
7377
7378THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
7379 int interceptor_call_count = 0;
7380 v8::HandleScope scope;
7381 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7382 v8::Handle<v8::FunctionTemplate> method_templ =
7383 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7384 v8_str("method_data"),
7385 v8::Signature::New(fun_templ));
7386 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7387 proto_templ->Set(v8_str("method"), method_templ);
7388 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7389 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7390 NULL, NULL, NULL, NULL,
7391 v8::External::Wrap(&interceptor_call_count));
7392 LocalContext context;
7393 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7394 GenerateSomeGarbage();
7395 context->Global()->Set(v8_str("o"), fun->NewInstance());
7396 v8::Handle<Value> value = CompileRun(
7397 "o.foo = 17;"
7398 "var receiver = {};"
7399 "receiver.__proto__ = o;"
7400 "var result = 0;"
7401 "var saved_result = 0;"
7402 "for (var i = 0; i < 100; i++) {"
7403 " result = receiver.method(41);"
7404 " if (i == 50) {"
7405 " saved_result = result;"
7406 " receiver = {method: function(x) { return x - 1 }};"
7407 " }"
7408 "}");
7409 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
7410 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7411 CHECK_GE(interceptor_call_count, 50);
7412}
7413
7414THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
7415 int interceptor_call_count = 0;
7416 v8::HandleScope scope;
7417 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7418 v8::Handle<v8::FunctionTemplate> method_templ =
7419 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7420 v8_str("method_data"),
7421 v8::Signature::New(fun_templ));
7422 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7423 proto_templ->Set(v8_str("method"), method_templ);
7424 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7425 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7426 NULL, NULL, NULL, NULL,
7427 v8::External::Wrap(&interceptor_call_count));
7428 LocalContext context;
7429 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7430 GenerateSomeGarbage();
7431 context->Global()->Set(v8_str("o"), fun->NewInstance());
7432 v8::Handle<Value> value = CompileRun(
7433 "o.foo = 17;"
7434 "var receiver = {};"
7435 "receiver.__proto__ = o;"
7436 "var result = 0;"
7437 "var saved_result = 0;"
7438 "for (var i = 0; i < 100; i++) {"
7439 " result = receiver.method(41);"
7440 " if (i == 50) {"
7441 " saved_result = result;"
7442 " o.method = function(x) { return x - 1 };"
7443 " }"
7444 "}");
7445 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
7446 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7447 CHECK_GE(interceptor_call_count, 50);
7448}
7449
Steve Block6ded16b2010-05-10 14:33:55 +01007450THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
7451 int interceptor_call_count = 0;
7452 v8::HandleScope scope;
7453 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7454 v8::Handle<v8::FunctionTemplate> method_templ =
7455 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7456 v8_str("method_data"),
7457 v8::Signature::New(fun_templ));
7458 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7459 proto_templ->Set(v8_str("method"), method_templ);
7460 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7461 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7462 NULL, NULL, NULL, NULL,
7463 v8::External::Wrap(&interceptor_call_count));
7464 LocalContext context;
7465 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7466 GenerateSomeGarbage();
7467 context->Global()->Set(v8_str("o"), fun->NewInstance());
7468 v8::TryCatch try_catch;
7469 v8::Handle<Value> value = CompileRun(
7470 "o.foo = 17;"
7471 "var receiver = {};"
7472 "receiver.__proto__ = o;"
7473 "var result = 0;"
7474 "var saved_result = 0;"
7475 "for (var i = 0; i < 100; i++) {"
7476 " result = receiver.method(41);"
7477 " if (i == 50) {"
7478 " saved_result = result;"
7479 " receiver = 333;"
7480 " }"
7481 "}");
7482 CHECK(try_catch.HasCaught());
7483 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
7484 try_catch.Exception()->ToString());
7485 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7486 CHECK_GE(interceptor_call_count, 50);
7487}
7488
Andrei Popescu402d9372010-02-26 13:31:12 +00007489THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
7490 int interceptor_call_count = 0;
7491 v8::HandleScope scope;
7492 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7493 v8::Handle<v8::FunctionTemplate> method_templ =
7494 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7495 v8_str("method_data"),
7496 v8::Signature::New(fun_templ));
7497 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7498 proto_templ->Set(v8_str("method"), method_templ);
7499 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7500 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7501 NULL, NULL, NULL, NULL,
7502 v8::External::Wrap(&interceptor_call_count));
7503 LocalContext context;
7504 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7505 GenerateSomeGarbage();
7506 context->Global()->Set(v8_str("o"), fun->NewInstance());
7507 v8::TryCatch try_catch;
7508 v8::Handle<Value> value = CompileRun(
7509 "o.foo = 17;"
7510 "var receiver = {};"
7511 "receiver.__proto__ = o;"
7512 "var result = 0;"
7513 "var saved_result = 0;"
7514 "for (var i = 0; i < 100; i++) {"
7515 " result = receiver.method(41);"
7516 " if (i == 50) {"
7517 " saved_result = result;"
7518 " receiver = {method: receiver.method};"
7519 " }"
7520 "}");
7521 CHECK(try_catch.HasCaught());
7522 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
7523 try_catch.Exception()->ToString());
7524 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7525 CHECK_GE(interceptor_call_count, 50);
7526}
7527
7528THREADED_TEST(CallICFastApi_TrivialSignature) {
7529 v8::HandleScope scope;
7530 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7531 v8::Handle<v8::FunctionTemplate> method_templ =
7532 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
7533 v8_str("method_data"),
7534 v8::Handle<v8::Signature>());
7535 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7536 proto_templ->Set(v8_str("method"), method_templ);
7537 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7538 LocalContext context;
7539 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7540 GenerateSomeGarbage();
7541 context->Global()->Set(v8_str("o"), fun->NewInstance());
7542 v8::Handle<Value> value = CompileRun(
7543 "var result = 0;"
7544 "for (var i = 0; i < 100; i++) {"
7545 " result = o.method(41);"
7546 "}");
7547
7548 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
7549}
7550
7551THREADED_TEST(CallICFastApi_SimpleSignature) {
7552 v8::HandleScope scope;
7553 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7554 v8::Handle<v8::FunctionTemplate> method_templ =
7555 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7556 v8_str("method_data"),
7557 v8::Signature::New(fun_templ));
7558 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7559 proto_templ->Set(v8_str("method"), method_templ);
7560 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7561 LocalContext context;
7562 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7563 GenerateSomeGarbage();
7564 context->Global()->Set(v8_str("o"), fun->NewInstance());
7565 v8::Handle<Value> value = CompileRun(
7566 "o.foo = 17;"
7567 "var receiver = {};"
7568 "receiver.__proto__ = o;"
7569 "var result = 0;"
7570 "for (var i = 0; i < 100; i++) {"
7571 " result = receiver.method(41);"
7572 "}");
7573
7574 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
7575}
7576
Steve Block6ded16b2010-05-10 14:33:55 +01007577THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) {
Andrei Popescu402d9372010-02-26 13:31:12 +00007578 v8::HandleScope scope;
7579 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7580 v8::Handle<v8::FunctionTemplate> method_templ =
7581 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7582 v8_str("method_data"),
7583 v8::Signature::New(fun_templ));
7584 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7585 proto_templ->Set(v8_str("method"), method_templ);
7586 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7587 LocalContext context;
7588 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7589 GenerateSomeGarbage();
7590 context->Global()->Set(v8_str("o"), fun->NewInstance());
7591 v8::Handle<Value> value = CompileRun(
7592 "o.foo = 17;"
7593 "var receiver = {};"
7594 "receiver.__proto__ = o;"
7595 "var result = 0;"
7596 "var saved_result = 0;"
7597 "for (var i = 0; i < 100; i++) {"
7598 " result = receiver.method(41);"
7599 " if (i == 50) {"
7600 " saved_result = result;"
7601 " receiver = {method: function(x) { return x - 1 }};"
7602 " }"
7603 "}");
7604 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
7605 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7606}
7607
Steve Block6ded16b2010-05-10 14:33:55 +01007608THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) {
7609 v8::HandleScope scope;
7610 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7611 v8::Handle<v8::FunctionTemplate> method_templ =
7612 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7613 v8_str("method_data"),
7614 v8::Signature::New(fun_templ));
7615 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7616 proto_templ->Set(v8_str("method"), method_templ);
7617 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7618 LocalContext context;
7619 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7620 GenerateSomeGarbage();
7621 context->Global()->Set(v8_str("o"), fun->NewInstance());
7622 v8::TryCatch try_catch;
7623 v8::Handle<Value> value = CompileRun(
7624 "o.foo = 17;"
7625 "var receiver = {};"
7626 "receiver.__proto__ = o;"
7627 "var result = 0;"
7628 "var saved_result = 0;"
7629 "for (var i = 0; i < 100; i++) {"
7630 " result = receiver.method(41);"
7631 " if (i == 50) {"
7632 " saved_result = result;"
7633 " receiver = 333;"
7634 " }"
7635 "}");
7636 CHECK(try_catch.HasCaught());
7637 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
7638 try_catch.Exception()->ToString());
7639 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7640}
7641
Leon Clarke4515c472010-02-03 11:58:03 +00007642
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01007643v8::Handle<Value> keyed_call_ic_function;
7644
7645static v8::Handle<Value> InterceptorKeyedCallICGetter(
7646 Local<String> name, const AccessorInfo& info) {
7647 ApiTestFuzzer::Fuzz();
7648 if (v8_str("x")->Equals(name)) {
7649 return keyed_call_ic_function;
7650 }
7651 return v8::Handle<Value>();
7652}
7653
7654
7655// Test the case when we stored cacheable lookup into
7656// a stub, but the function name changed (to another cacheable function).
7657THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
7658 v8::HandleScope scope;
7659 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7660 templ->SetNamedPropertyHandler(NoBlockGetterX);
7661 LocalContext context;
7662 context->Global()->Set(v8_str("o"), templ->NewInstance());
7663 v8::Handle<Value> value = CompileRun(
7664 "proto = new Object();"
7665 "proto.y = function(x) { return x + 1; };"
7666 "proto.z = function(x) { return x - 1; };"
7667 "o.__proto__ = proto;"
7668 "var result = 0;"
7669 "var method = 'y';"
7670 "for (var i = 0; i < 10; i++) {"
7671 " if (i == 5) { method = 'z'; };"
7672 " result += o[method](41);"
7673 "}");
7674 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7675}
7676
7677
7678// Test the case when we stored cacheable lookup into
7679// a stub, but the function name changed (and the new function is present
7680// both before and after the interceptor in the prototype chain).
7681THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
7682 v8::HandleScope scope;
7683 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7684 templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
7685 LocalContext context;
7686 context->Global()->Set(v8_str("proto1"), templ->NewInstance());
7687 keyed_call_ic_function =
7688 v8_compile("function f(x) { return x - 1; }; f")->Run();
7689 v8::Handle<Value> value = CompileRun(
7690 "o = new Object();"
7691 "proto2 = new Object();"
7692 "o.y = function(x) { return x + 1; };"
7693 "proto2.y = function(x) { return x + 2; };"
7694 "o.__proto__ = proto1;"
7695 "proto1.__proto__ = proto2;"
7696 "var result = 0;"
7697 "var method = 'x';"
7698 "for (var i = 0; i < 10; i++) {"
7699 " if (i == 5) { method = 'y'; };"
7700 " result += o[method](41);"
7701 "}");
7702 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7703}
7704
7705
7706// Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
7707// on the global object.
7708THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
7709 v8::HandleScope scope;
7710 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7711 templ->SetNamedPropertyHandler(NoBlockGetterX);
7712 LocalContext context;
7713 context->Global()->Set(v8_str("o"), templ->NewInstance());
7714 v8::Handle<Value> value = CompileRun(
7715 "function inc(x) { return x + 1; };"
7716 "inc(1);"
7717 "function dec(x) { return x - 1; };"
7718 "dec(1);"
7719 "o.__proto__ = this;"
7720 "this.__proto__.x = inc;"
7721 "this.__proto__.y = dec;"
7722 "var result = 0;"
7723 "var method = 'x';"
7724 "for (var i = 0; i < 10; i++) {"
7725 " if (i == 5) { method = 'y'; };"
7726 " result += o[method](41);"
7727 "}");
7728 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7729}
7730
7731
7732// Test the case when actual function to call sits on global object.
7733THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
7734 v8::HandleScope scope;
7735 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7736 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
7737 LocalContext context;
7738 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7739
7740 v8::Handle<Value> value = CompileRun(
7741 "function len(x) { return x.length; };"
7742 "o.__proto__ = this;"
7743 "var m = 'parseFloat';"
7744 "var result = 0;"
7745 "for (var i = 0; i < 10; i++) {"
7746 " if (i == 5) {"
7747 " m = 'len';"
7748 " saved_result = result;"
7749 " };"
7750 " result = o[m]('239');"
7751 "}");
7752 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
7753 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7754}
7755
7756// Test the map transition before the interceptor.
7757THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
7758 v8::HandleScope scope;
7759 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7760 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
7761 LocalContext context;
7762 context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
7763
7764 v8::Handle<Value> value = CompileRun(
7765 "var o = new Object();"
7766 "o.__proto__ = proto;"
7767 "o.method = function(x) { return x + 1; };"
7768 "var m = 'method';"
7769 "var result = 0;"
7770 "for (var i = 0; i < 10; i++) {"
7771 " if (i == 5) { o.method = function(x) { return x - 1; }; };"
7772 " result += o[m](41);"
7773 "}");
7774 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7775}
7776
7777
7778// Test the map transition after the interceptor.
7779THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
7780 v8::HandleScope scope;
7781 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7782 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
7783 LocalContext context;
7784 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7785
7786 v8::Handle<Value> value = CompileRun(
7787 "var proto = new Object();"
7788 "o.__proto__ = proto;"
7789 "proto.method = function(x) { return x + 1; };"
7790 "var m = 'method';"
7791 "var result = 0;"
7792 "for (var i = 0; i < 10; i++) {"
7793 " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
7794 " result += o[m](41);"
7795 "}");
7796 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7797}
7798
7799
Steve Blocka7e24c12009-10-30 11:49:00 +00007800static int interceptor_call_count = 0;
7801
7802static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
7803 const AccessorInfo& info) {
7804 ApiTestFuzzer::Fuzz();
7805 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
7806 return call_ic_function2;
7807 }
7808 return v8::Handle<Value>();
7809}
7810
7811
7812// This test should hit load and call ICs for the interceptor case.
7813// Once in a while, the interceptor will reply that a property was not
7814// found in which case we should get a reference error.
7815THREADED_TEST(InterceptorICReferenceErrors) {
7816 v8::HandleScope scope;
7817 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7818 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
7819 LocalContext context(0, templ, v8::Handle<Value>());
7820 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
7821 v8::Handle<Value> value = CompileRun(
7822 "function f() {"
7823 " for (var i = 0; i < 1000; i++) {"
7824 " try { x; } catch(e) { return true; }"
7825 " }"
7826 " return false;"
7827 "};"
7828 "f();");
7829 CHECK_EQ(true, value->BooleanValue());
7830 interceptor_call_count = 0;
7831 value = CompileRun(
7832 "function g() {"
7833 " for (var i = 0; i < 1000; i++) {"
7834 " try { x(42); } catch(e) { return true; }"
7835 " }"
7836 " return false;"
7837 "};"
7838 "g();");
7839 CHECK_EQ(true, value->BooleanValue());
7840}
7841
7842
7843static int interceptor_ic_exception_get_count = 0;
7844
7845static v8::Handle<Value> InterceptorICExceptionGetter(
7846 Local<String> name,
7847 const AccessorInfo& info) {
7848 ApiTestFuzzer::Fuzz();
7849 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
7850 return call_ic_function3;
7851 }
7852 if (interceptor_ic_exception_get_count == 20) {
7853 return v8::ThrowException(v8_num(42));
7854 }
7855 // Do not handle get for properties other than x.
7856 return v8::Handle<Value>();
7857}
7858
7859// Test interceptor load/call IC where the interceptor throws an
7860// exception once in a while.
7861THREADED_TEST(InterceptorICGetterExceptions) {
7862 interceptor_ic_exception_get_count = 0;
7863 v8::HandleScope scope;
7864 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7865 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
7866 LocalContext context(0, templ, v8::Handle<Value>());
7867 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
7868 v8::Handle<Value> value = CompileRun(
7869 "function f() {"
7870 " for (var i = 0; i < 100; i++) {"
7871 " try { x; } catch(e) { return true; }"
7872 " }"
7873 " return false;"
7874 "};"
7875 "f();");
7876 CHECK_EQ(true, value->BooleanValue());
7877 interceptor_ic_exception_get_count = 0;
7878 value = CompileRun(
7879 "function f() {"
7880 " for (var i = 0; i < 100; i++) {"
7881 " try { x(42); } catch(e) { return true; }"
7882 " }"
7883 " return false;"
7884 "};"
7885 "f();");
7886 CHECK_EQ(true, value->BooleanValue());
7887}
7888
7889
7890static int interceptor_ic_exception_set_count = 0;
7891
7892static v8::Handle<Value> InterceptorICExceptionSetter(
7893 Local<String> key, Local<Value> value, const AccessorInfo&) {
7894 ApiTestFuzzer::Fuzz();
7895 if (++interceptor_ic_exception_set_count > 20) {
7896 return v8::ThrowException(v8_num(42));
7897 }
7898 // Do not actually handle setting.
7899 return v8::Handle<Value>();
7900}
7901
7902// Test interceptor store IC where the interceptor throws an exception
7903// once in a while.
7904THREADED_TEST(InterceptorICSetterExceptions) {
7905 interceptor_ic_exception_set_count = 0;
7906 v8::HandleScope scope;
7907 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7908 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
7909 LocalContext context(0, templ, v8::Handle<Value>());
7910 v8::Handle<Value> value = CompileRun(
7911 "function f() {"
7912 " for (var i = 0; i < 100; i++) {"
7913 " try { x = 42; } catch(e) { return true; }"
7914 " }"
7915 " return false;"
7916 "};"
7917 "f();");
7918 CHECK_EQ(true, value->BooleanValue());
7919}
7920
7921
7922// Test that we ignore null interceptors.
7923THREADED_TEST(NullNamedInterceptor) {
7924 v8::HandleScope scope;
7925 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7926 templ->SetNamedPropertyHandler(0);
7927 LocalContext context;
7928 templ->Set("x", v8_num(42));
7929 v8::Handle<v8::Object> obj = templ->NewInstance();
7930 context->Global()->Set(v8_str("obj"), obj);
7931 v8::Handle<Value> value = CompileRun("obj.x");
7932 CHECK(value->IsInt32());
7933 CHECK_EQ(42, value->Int32Value());
7934}
7935
7936
7937// Test that we ignore null interceptors.
7938THREADED_TEST(NullIndexedInterceptor) {
7939 v8::HandleScope scope;
7940 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7941 templ->SetIndexedPropertyHandler(0);
7942 LocalContext context;
7943 templ->Set("42", v8_num(42));
7944 v8::Handle<v8::Object> obj = templ->NewInstance();
7945 context->Global()->Set(v8_str("obj"), obj);
7946 v8::Handle<Value> value = CompileRun("obj[42]");
7947 CHECK(value->IsInt32());
7948 CHECK_EQ(42, value->Int32Value());
7949}
7950
7951
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01007952THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
7953 v8::HandleScope scope;
7954 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7955 templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7956 LocalContext env;
7957 env->Global()->Set(v8_str("obj"),
7958 templ->GetFunction()->NewInstance());
7959 ExpectTrue("obj.x === 42");
7960 ExpectTrue("!obj.propertyIsEnumerable('x')");
7961}
7962
7963
Steve Blocka7e24c12009-10-30 11:49:00 +00007964static v8::Handle<Value> ParentGetter(Local<String> name,
7965 const AccessorInfo& info) {
7966 ApiTestFuzzer::Fuzz();
7967 return v8_num(1);
7968}
7969
7970
7971static v8::Handle<Value> ChildGetter(Local<String> name,
7972 const AccessorInfo& info) {
7973 ApiTestFuzzer::Fuzz();
7974 return v8_num(42);
7975}
7976
7977
7978THREADED_TEST(Overriding) {
7979 v8::HandleScope scope;
7980 LocalContext context;
7981
7982 // Parent template.
7983 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
7984 Local<ObjectTemplate> parent_instance_templ =
7985 parent_templ->InstanceTemplate();
7986 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
7987
7988 // Template that inherits from the parent template.
7989 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
7990 Local<ObjectTemplate> child_instance_templ =
7991 child_templ->InstanceTemplate();
7992 child_templ->Inherit(parent_templ);
7993 // Override 'f'. The child version of 'f' should get called for child
7994 // instances.
7995 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
7996 // Add 'g' twice. The 'g' added last should get called for instances.
7997 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
7998 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
7999
8000 // Add 'h' as an accessor to the proto template with ReadOnly attributes
8001 // so 'h' can be shadowed on the instance object.
8002 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
8003 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
8004 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
8005
8006 // Add 'i' as an accessor to the instance template with ReadOnly attributes
8007 // but the attribute does not have effect because it is duplicated with
8008 // NULL setter.
8009 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
8010 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
8011
8012
8013
8014 // Instantiate the child template.
8015 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
8016
8017 // Check that the child function overrides the parent one.
8018 context->Global()->Set(v8_str("o"), instance);
8019 Local<Value> value = v8_compile("o.f")->Run();
8020 // Check that the 'g' that was added last is hit.
8021 CHECK_EQ(42, value->Int32Value());
8022 value = v8_compile("o.g")->Run();
8023 CHECK_EQ(42, value->Int32Value());
8024
8025 // Check 'h' can be shadowed.
8026 value = v8_compile("o.h = 3; o.h")->Run();
8027 CHECK_EQ(3, value->Int32Value());
8028
8029 // Check 'i' is cannot be shadowed or changed.
8030 value = v8_compile("o.i = 3; o.i")->Run();
8031 CHECK_EQ(42, value->Int32Value());
8032}
8033
8034
8035static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
8036 ApiTestFuzzer::Fuzz();
8037 if (args.IsConstructCall()) {
8038 return v8::Boolean::New(true);
8039 }
8040 return v8::Boolean::New(false);
8041}
8042
8043
8044THREADED_TEST(IsConstructCall) {
8045 v8::HandleScope scope;
8046
8047 // Function template with call handler.
8048 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
8049 templ->SetCallHandler(IsConstructHandler);
8050
8051 LocalContext context;
8052
8053 context->Global()->Set(v8_str("f"), templ->GetFunction());
8054 Local<Value> value = v8_compile("f()")->Run();
8055 CHECK(!value->BooleanValue());
8056 value = v8_compile("new f()")->Run();
8057 CHECK(value->BooleanValue());
8058}
8059
8060
8061THREADED_TEST(ObjectProtoToString) {
8062 v8::HandleScope scope;
8063 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
8064 templ->SetClassName(v8_str("MyClass"));
8065
8066 LocalContext context;
8067
8068 Local<String> customized_tostring = v8_str("customized toString");
8069
8070 // Replace Object.prototype.toString
8071 v8_compile("Object.prototype.toString = function() {"
8072 " return 'customized toString';"
8073 "}")->Run();
8074
8075 // Normal ToString call should call replaced Object.prototype.toString
8076 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
8077 Local<String> value = instance->ToString();
8078 CHECK(value->IsString() && value->Equals(customized_tostring));
8079
8080 // ObjectProtoToString should not call replace toString function.
8081 value = instance->ObjectProtoToString();
8082 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
8083
8084 // Check global
8085 value = context->Global()->ObjectProtoToString();
8086 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
8087
8088 // Check ordinary object
8089 Local<Value> object = v8_compile("new Object()")->Run();
Steve Block6ded16b2010-05-10 14:33:55 +01008090 value = object.As<v8::Object>()->ObjectProtoToString();
Steve Blocka7e24c12009-10-30 11:49:00 +00008091 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
8092}
8093
8094
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08008095THREADED_TEST(ObjectGetConstructorName) {
8096 v8::HandleScope scope;
8097 LocalContext context;
8098 v8_compile("function Parent() {};"
8099 "function Child() {};"
8100 "Child.prototype = new Parent();"
8101 "var outer = { inner: function() { } };"
8102 "var p = new Parent();"
8103 "var c = new Child();"
8104 "var x = new outer.inner();")->Run();
8105
8106 Local<v8::Value> p = context->Global()->Get(v8_str("p"));
8107 CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
8108 v8_str("Parent")));
8109
8110 Local<v8::Value> c = context->Global()->Get(v8_str("c"));
8111 CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
8112 v8_str("Child")));
8113
8114 Local<v8::Value> x = context->Global()->Get(v8_str("x"));
8115 CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
8116 v8_str("outer.inner")));
8117}
8118
8119
Steve Blocka7e24c12009-10-30 11:49:00 +00008120bool ApiTestFuzzer::fuzzing_ = false;
Steve Block8defd9f2010-07-08 12:39:36 +01008121i::Semaphore* ApiTestFuzzer::all_tests_done_=
8122 i::OS::CreateSemaphore(0);
Steve Blocka7e24c12009-10-30 11:49:00 +00008123int ApiTestFuzzer::active_tests_;
8124int ApiTestFuzzer::tests_being_run_;
8125int ApiTestFuzzer::current_;
8126
8127
8128// We are in a callback and want to switch to another thread (if we
8129// are currently running the thread fuzzing test).
8130void ApiTestFuzzer::Fuzz() {
8131 if (!fuzzing_) return;
8132 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
8133 test->ContextSwitch();
8134}
8135
8136
8137// Let the next thread go. Since it is also waiting on the V8 lock it may
8138// not start immediately.
8139bool ApiTestFuzzer::NextThread() {
8140 int test_position = GetNextTestNumber();
Steve Blockd0582a62009-12-15 09:54:21 +00008141 const char* test_name = RegisterThreadedTest::nth(current_)->name();
Steve Blocka7e24c12009-10-30 11:49:00 +00008142 if (test_position == current_) {
Steve Blockd0582a62009-12-15 09:54:21 +00008143 if (kLogThreading)
8144 printf("Stay with %s\n", test_name);
Steve Blocka7e24c12009-10-30 11:49:00 +00008145 return false;
8146 }
Steve Blockd0582a62009-12-15 09:54:21 +00008147 if (kLogThreading) {
8148 printf("Switch from %s to %s\n",
8149 test_name,
8150 RegisterThreadedTest::nth(test_position)->name());
8151 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008152 current_ = test_position;
8153 RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
8154 return true;
8155}
8156
8157
8158void ApiTestFuzzer::Run() {
8159 // When it is our turn...
8160 gate_->Wait();
8161 {
8162 // ... get the V8 lock and start running the test.
8163 v8::Locker locker;
8164 CallTest();
8165 }
8166 // This test finished.
8167 active_ = false;
8168 active_tests_--;
8169 // If it was the last then signal that fact.
8170 if (active_tests_ == 0) {
8171 all_tests_done_->Signal();
8172 } else {
8173 // Otherwise select a new test and start that.
8174 NextThread();
8175 }
8176}
8177
8178
8179static unsigned linear_congruential_generator;
8180
8181
8182void ApiTestFuzzer::Setup(PartOfTest part) {
8183 linear_congruential_generator = i::FLAG_testing_prng_seed;
8184 fuzzing_ = true;
8185 int start = (part == FIRST_PART) ? 0 : (RegisterThreadedTest::count() >> 1);
8186 int end = (part == FIRST_PART)
8187 ? (RegisterThreadedTest::count() >> 1)
8188 : RegisterThreadedTest::count();
8189 active_tests_ = tests_being_run_ = end - start;
8190 for (int i = 0; i < tests_being_run_; i++) {
8191 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
8192 }
8193 for (int i = 0; i < active_tests_; i++) {
8194 RegisterThreadedTest::nth(i)->fuzzer_->Start();
8195 }
8196}
8197
8198
8199static void CallTestNumber(int test_number) {
8200 (RegisterThreadedTest::nth(test_number)->callback())();
8201}
8202
8203
8204void ApiTestFuzzer::RunAllTests() {
8205 // Set off the first test.
8206 current_ = -1;
8207 NextThread();
8208 // Wait till they are all done.
8209 all_tests_done_->Wait();
8210}
8211
8212
8213int ApiTestFuzzer::GetNextTestNumber() {
8214 int next_test;
8215 do {
8216 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
8217 linear_congruential_generator *= 1664525u;
8218 linear_congruential_generator += 1013904223u;
8219 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
8220 return next_test;
8221}
8222
8223
8224void ApiTestFuzzer::ContextSwitch() {
8225 // If the new thread is the same as the current thread there is nothing to do.
8226 if (NextThread()) {
8227 // Now it can start.
8228 v8::Unlocker unlocker;
8229 // Wait till someone starts us again.
8230 gate_->Wait();
8231 // And we're off.
8232 }
8233}
8234
8235
8236void ApiTestFuzzer::TearDown() {
8237 fuzzing_ = false;
8238 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
8239 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
8240 if (fuzzer != NULL) fuzzer->Join();
8241 }
8242}
8243
8244
8245// Lets not be needlessly self-referential.
8246TEST(Threading) {
8247 ApiTestFuzzer::Setup(ApiTestFuzzer::FIRST_PART);
8248 ApiTestFuzzer::RunAllTests();
8249 ApiTestFuzzer::TearDown();
8250}
8251
8252TEST(Threading2) {
8253 ApiTestFuzzer::Setup(ApiTestFuzzer::SECOND_PART);
8254 ApiTestFuzzer::RunAllTests();
8255 ApiTestFuzzer::TearDown();
8256}
8257
8258
8259void ApiTestFuzzer::CallTest() {
Steve Blockd0582a62009-12-15 09:54:21 +00008260 if (kLogThreading)
8261 printf("Start test %d\n", test_number_);
Steve Blocka7e24c12009-10-30 11:49:00 +00008262 CallTestNumber(test_number_);
Steve Blockd0582a62009-12-15 09:54:21 +00008263 if (kLogThreading)
8264 printf("End test %d\n", test_number_);
Steve Blocka7e24c12009-10-30 11:49:00 +00008265}
8266
8267
8268static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
8269 CHECK(v8::Locker::IsLocked());
8270 ApiTestFuzzer::Fuzz();
8271 v8::Unlocker unlocker;
8272 const char* code = "throw 7;";
8273 {
8274 v8::Locker nested_locker;
8275 v8::HandleScope scope;
8276 v8::Handle<Value> exception;
8277 { v8::TryCatch try_catch;
8278 v8::Handle<Value> value = CompileRun(code);
8279 CHECK(value.IsEmpty());
8280 CHECK(try_catch.HasCaught());
8281 // Make sure to wrap the exception in a new handle because
8282 // the handle returned from the TryCatch is destroyed
8283 // when the TryCatch is destroyed.
8284 exception = Local<Value>::New(try_catch.Exception());
8285 }
8286 return v8::ThrowException(exception);
8287 }
8288}
8289
8290
8291static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
8292 CHECK(v8::Locker::IsLocked());
8293 ApiTestFuzzer::Fuzz();
8294 v8::Unlocker unlocker;
8295 const char* code = "throw 7;";
8296 {
8297 v8::Locker nested_locker;
8298 v8::HandleScope scope;
8299 v8::Handle<Value> value = CompileRun(code);
8300 CHECK(value.IsEmpty());
8301 return v8_str("foo");
8302 }
8303}
8304
8305
8306// These are locking tests that don't need to be run again
8307// as part of the locking aggregation tests.
8308TEST(NestedLockers) {
8309 v8::Locker locker;
8310 CHECK(v8::Locker::IsLocked());
8311 v8::HandleScope scope;
8312 LocalContext env;
8313 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
8314 Local<Function> fun = fun_templ->GetFunction();
8315 env->Global()->Set(v8_str("throw_in_js"), fun);
8316 Local<Script> script = v8_compile("(function () {"
8317 " try {"
8318 " throw_in_js();"
8319 " return 42;"
8320 " } catch (e) {"
8321 " return e * 13;"
8322 " }"
8323 "})();");
8324 CHECK_EQ(91, script->Run()->Int32Value());
8325}
8326
8327
8328// These are locking tests that don't need to be run again
8329// as part of the locking aggregation tests.
8330TEST(NestedLockersNoTryCatch) {
8331 v8::Locker locker;
8332 v8::HandleScope scope;
8333 LocalContext env;
8334 Local<v8::FunctionTemplate> fun_templ =
8335 v8::FunctionTemplate::New(ThrowInJSNoCatch);
8336 Local<Function> fun = fun_templ->GetFunction();
8337 env->Global()->Set(v8_str("throw_in_js"), fun);
8338 Local<Script> script = v8_compile("(function () {"
8339 " try {"
8340 " throw_in_js();"
8341 " return 42;"
8342 " } catch (e) {"
8343 " return e * 13;"
8344 " }"
8345 "})();");
8346 CHECK_EQ(91, script->Run()->Int32Value());
8347}
8348
8349
8350THREADED_TEST(RecursiveLocking) {
8351 v8::Locker locker;
8352 {
8353 v8::Locker locker2;
8354 CHECK(v8::Locker::IsLocked());
8355 }
8356}
8357
8358
8359static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
8360 ApiTestFuzzer::Fuzz();
8361 v8::Unlocker unlocker;
8362 return v8::Undefined();
8363}
8364
8365
8366THREADED_TEST(LockUnlockLock) {
8367 {
8368 v8::Locker locker;
8369 v8::HandleScope scope;
8370 LocalContext env;
8371 Local<v8::FunctionTemplate> fun_templ =
8372 v8::FunctionTemplate::New(UnlockForAMoment);
8373 Local<Function> fun = fun_templ->GetFunction();
8374 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
8375 Local<Script> script = v8_compile("(function () {"
8376 " unlock_for_a_moment();"
8377 " return 42;"
8378 "})();");
8379 CHECK_EQ(42, script->Run()->Int32Value());
8380 }
8381 {
8382 v8::Locker locker;
8383 v8::HandleScope scope;
8384 LocalContext env;
8385 Local<v8::FunctionTemplate> fun_templ =
8386 v8::FunctionTemplate::New(UnlockForAMoment);
8387 Local<Function> fun = fun_templ->GetFunction();
8388 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
8389 Local<Script> script = v8_compile("(function () {"
8390 " unlock_for_a_moment();"
8391 " return 42;"
8392 "})();");
8393 CHECK_EQ(42, script->Run()->Int32Value());
8394 }
8395}
8396
8397
Leon Clarked91b9f72010-01-27 17:25:45 +00008398static int GetGlobalObjectsCount() {
Leon Clarkeeab96aa2010-01-27 16:31:12 +00008399 int count = 0;
Steve Block8defd9f2010-07-08 12:39:36 +01008400 i::HeapIterator it;
Leon Clarked91b9f72010-01-27 17:25:45 +00008401 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
8402 if (object->IsJSGlobalObject()) count++;
8403 return count;
8404}
8405
8406
Ben Murdochf87a2032010-10-22 12:50:53 +01008407static void CheckSurvivingGlobalObjectsCount(int expected) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008408 // We need to collect all garbage twice to be sure that everything
8409 // has been collected. This is because inline caches are cleared in
8410 // the first garbage collection but some of the maps have already
8411 // been marked at that point. Therefore some of the maps are not
8412 // collected until the second garbage collection.
Steve Block8defd9f2010-07-08 12:39:36 +01008413 i::Heap::CollectAllGarbage(false);
8414 i::Heap::CollectAllGarbage(false);
Leon Clarked91b9f72010-01-27 17:25:45 +00008415 int count = GetGlobalObjectsCount();
Steve Blocka7e24c12009-10-30 11:49:00 +00008416#ifdef DEBUG
Ben Murdochf87a2032010-10-22 12:50:53 +01008417 if (count != expected) i::Heap::TracePathToGlobal();
Steve Blocka7e24c12009-10-30 11:49:00 +00008418#endif
Ben Murdochf87a2032010-10-22 12:50:53 +01008419 CHECK_EQ(expected, count);
Steve Blocka7e24c12009-10-30 11:49:00 +00008420}
8421
8422
8423TEST(DontLeakGlobalObjects) {
8424 // Regression test for issues 1139850 and 1174891.
8425
8426 v8::V8::Initialize();
8427
Steve Blocka7e24c12009-10-30 11:49:00 +00008428 for (int i = 0; i < 5; i++) {
8429 { v8::HandleScope scope;
8430 LocalContext context;
8431 }
Ben Murdochf87a2032010-10-22 12:50:53 +01008432 CheckSurvivingGlobalObjectsCount(0);
Steve Blocka7e24c12009-10-30 11:49:00 +00008433
8434 { v8::HandleScope scope;
8435 LocalContext context;
8436 v8_compile("Date")->Run();
8437 }
Ben Murdochf87a2032010-10-22 12:50:53 +01008438 CheckSurvivingGlobalObjectsCount(0);
Steve Blocka7e24c12009-10-30 11:49:00 +00008439
8440 { v8::HandleScope scope;
8441 LocalContext context;
8442 v8_compile("/aaa/")->Run();
8443 }
Ben Murdochf87a2032010-10-22 12:50:53 +01008444 CheckSurvivingGlobalObjectsCount(0);
Steve Blocka7e24c12009-10-30 11:49:00 +00008445
8446 { v8::HandleScope scope;
8447 const char* extension_list[] = { "v8/gc" };
8448 v8::ExtensionConfiguration extensions(1, extension_list);
8449 LocalContext context(&extensions);
8450 v8_compile("gc();")->Run();
8451 }
Ben Murdochf87a2032010-10-22 12:50:53 +01008452 CheckSurvivingGlobalObjectsCount(0);
Steve Blocka7e24c12009-10-30 11:49:00 +00008453 }
8454}
8455
8456
8457v8::Persistent<v8::Object> some_object;
8458v8::Persistent<v8::Object> bad_handle;
8459
Kristian Monsen50ef84f2010-07-29 15:18:00 +01008460void NewPersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008461 v8::HandleScope scope;
8462 bad_handle = v8::Persistent<v8::Object>::New(some_object);
Kristian Monsen50ef84f2010-07-29 15:18:00 +01008463 handle.Dispose();
Steve Blocka7e24c12009-10-30 11:49:00 +00008464}
8465
8466
8467THREADED_TEST(NewPersistentHandleFromWeakCallback) {
8468 LocalContext context;
8469
8470 v8::Persistent<v8::Object> handle1, handle2;
8471 {
8472 v8::HandleScope scope;
8473 some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
8474 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
8475 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
8476 }
8477 // Note: order is implementation dependent alas: currently
8478 // global handle nodes are processed by PostGarbageCollectionProcessing
8479 // in reverse allocation order, so if second allocated handle is deleted,
8480 // weak callback of the first handle would be able to 'reallocate' it.
8481 handle1.MakeWeak(NULL, NewPersistentHandleCallback);
8482 handle2.Dispose();
8483 i::Heap::CollectAllGarbage(false);
8484}
8485
8486
8487v8::Persistent<v8::Object> to_be_disposed;
8488
8489void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
8490 to_be_disposed.Dispose();
8491 i::Heap::CollectAllGarbage(false);
Kristian Monsen50ef84f2010-07-29 15:18:00 +01008492 handle.Dispose();
Steve Blocka7e24c12009-10-30 11:49:00 +00008493}
8494
8495
8496THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
8497 LocalContext context;
8498
8499 v8::Persistent<v8::Object> handle1, handle2;
8500 {
8501 v8::HandleScope scope;
8502 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
8503 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
8504 }
8505 handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
8506 to_be_disposed = handle2;
8507 i::Heap::CollectAllGarbage(false);
8508}
8509
Steve Blockd0582a62009-12-15 09:54:21 +00008510void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
8511 handle.Dispose();
8512}
8513
8514void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
8515 v8::HandleScope scope;
8516 v8::Persistent<v8::Object>::New(v8::Object::New());
Kristian Monsen50ef84f2010-07-29 15:18:00 +01008517 handle.Dispose();
Steve Blockd0582a62009-12-15 09:54:21 +00008518}
8519
8520
8521THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
8522 LocalContext context;
8523
8524 v8::Persistent<v8::Object> handle1, handle2, handle3;
8525 {
8526 v8::HandleScope scope;
8527 handle3 = v8::Persistent<v8::Object>::New(v8::Object::New());
8528 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
8529 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
8530 }
8531 handle2.MakeWeak(NULL, DisposingCallback);
8532 handle3.MakeWeak(NULL, HandleCreatingCallback);
8533 i::Heap::CollectAllGarbage(false);
8534}
8535
Steve Blocka7e24c12009-10-30 11:49:00 +00008536
8537THREADED_TEST(CheckForCrossContextObjectLiterals) {
8538 v8::V8::Initialize();
8539
8540 const int nof = 2;
8541 const char* sources[nof] = {
8542 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
8543 "Object()"
8544 };
8545
8546 for (int i = 0; i < nof; i++) {
8547 const char* source = sources[i];
8548 { v8::HandleScope scope;
8549 LocalContext context;
8550 CompileRun(source);
8551 }
8552 { v8::HandleScope scope;
8553 LocalContext context;
8554 CompileRun(source);
8555 }
8556 }
8557}
8558
8559
8560static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
8561 v8::HandleScope inner;
8562 env->Enter();
8563 v8::Handle<Value> three = v8_num(3);
8564 v8::Handle<Value> value = inner.Close(three);
8565 env->Exit();
8566 return value;
8567}
8568
8569
8570THREADED_TEST(NestedHandleScopeAndContexts) {
8571 v8::HandleScope outer;
8572 v8::Persistent<Context> env = Context::New();
8573 env->Enter();
8574 v8::Handle<Value> value = NestedScope(env);
8575 v8::Handle<String> str = value->ToString();
8576 env->Exit();
8577 env.Dispose();
8578}
8579
8580
8581THREADED_TEST(ExternalAllocatedMemory) {
8582 v8::HandleScope outer;
8583 v8::Persistent<Context> env = Context::New();
8584 const int kSize = 1024*1024;
8585 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
8586 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
8587}
8588
8589
8590THREADED_TEST(DisposeEnteredContext) {
8591 v8::HandleScope scope;
8592 LocalContext outer;
8593 { v8::Persistent<v8::Context> inner = v8::Context::New();
8594 inner->Enter();
8595 inner.Dispose();
8596 inner.Clear();
8597 inner->Exit();
8598 }
8599}
8600
8601
8602// Regression test for issue 54, object templates with internal fields
8603// but no accessors or interceptors did not get their internal field
8604// count set on instances.
8605THREADED_TEST(Regress54) {
8606 v8::HandleScope outer;
8607 LocalContext context;
8608 static v8::Persistent<v8::ObjectTemplate> templ;
8609 if (templ.IsEmpty()) {
8610 v8::HandleScope inner;
8611 v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
8612 local->SetInternalFieldCount(1);
8613 templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
8614 }
8615 v8::Handle<v8::Object> result = templ->NewInstance();
8616 CHECK_EQ(1, result->InternalFieldCount());
8617}
8618
8619
8620// If part of the threaded tests, this test makes ThreadingTest fail
8621// on mac.
8622TEST(CatchStackOverflow) {
8623 v8::HandleScope scope;
8624 LocalContext context;
8625 v8::TryCatch try_catch;
8626 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
8627 "function f() {"
8628 " return f();"
8629 "}"
8630 ""
8631 "f();"));
8632 v8::Handle<v8::Value> result = script->Run();
8633 CHECK(result.IsEmpty());
8634}
8635
8636
8637static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
8638 const char* resource_name,
8639 int line_offset) {
8640 v8::HandleScope scope;
8641 v8::TryCatch try_catch;
8642 v8::Handle<v8::Value> result = script->Run();
8643 CHECK(result.IsEmpty());
8644 CHECK(try_catch.HasCaught());
8645 v8::Handle<v8::Message> message = try_catch.Message();
8646 CHECK(!message.IsEmpty());
8647 CHECK_EQ(10 + line_offset, message->GetLineNumber());
8648 CHECK_EQ(91, message->GetStartPosition());
8649 CHECK_EQ(92, message->GetEndPosition());
8650 CHECK_EQ(2, message->GetStartColumn());
8651 CHECK_EQ(3, message->GetEndColumn());
8652 v8::String::AsciiValue line(message->GetSourceLine());
8653 CHECK_EQ(" throw 'nirk';", *line);
8654 v8::String::AsciiValue name(message->GetScriptResourceName());
8655 CHECK_EQ(resource_name, *name);
8656}
8657
8658
8659THREADED_TEST(TryCatchSourceInfo) {
8660 v8::HandleScope scope;
8661 LocalContext context;
8662 v8::Handle<v8::String> source = v8::String::New(
8663 "function Foo() {\n"
8664 " return Bar();\n"
8665 "}\n"
8666 "\n"
8667 "function Bar() {\n"
8668 " return Baz();\n"
8669 "}\n"
8670 "\n"
8671 "function Baz() {\n"
8672 " throw 'nirk';\n"
8673 "}\n"
8674 "\n"
8675 "Foo();\n");
8676
8677 const char* resource_name;
8678 v8::Handle<v8::Script> script;
8679 resource_name = "test.js";
8680 script = v8::Script::Compile(source, v8::String::New(resource_name));
8681 CheckTryCatchSourceInfo(script, resource_name, 0);
8682
8683 resource_name = "test1.js";
8684 v8::ScriptOrigin origin1(v8::String::New(resource_name));
8685 script = v8::Script::Compile(source, &origin1);
8686 CheckTryCatchSourceInfo(script, resource_name, 0);
8687
8688 resource_name = "test2.js";
8689 v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
8690 script = v8::Script::Compile(source, &origin2);
8691 CheckTryCatchSourceInfo(script, resource_name, 7);
8692}
8693
8694
8695THREADED_TEST(CompilationCache) {
8696 v8::HandleScope scope;
8697 LocalContext context;
8698 v8::Handle<v8::String> source0 = v8::String::New("1234");
8699 v8::Handle<v8::String> source1 = v8::String::New("1234");
8700 v8::Handle<v8::Script> script0 =
8701 v8::Script::Compile(source0, v8::String::New("test.js"));
8702 v8::Handle<v8::Script> script1 =
8703 v8::Script::Compile(source1, v8::String::New("test.js"));
8704 v8::Handle<v8::Script> script2 =
8705 v8::Script::Compile(source0); // different origin
8706 CHECK_EQ(1234, script0->Run()->Int32Value());
8707 CHECK_EQ(1234, script1->Run()->Int32Value());
8708 CHECK_EQ(1234, script2->Run()->Int32Value());
8709}
8710
8711
8712static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
8713 ApiTestFuzzer::Fuzz();
8714 return v8_num(42);
8715}
8716
8717
8718THREADED_TEST(CallbackFunctionName) {
8719 v8::HandleScope scope;
8720 LocalContext context;
8721 Local<ObjectTemplate> t = ObjectTemplate::New();
8722 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
8723 context->Global()->Set(v8_str("obj"), t->NewInstance());
8724 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
8725 CHECK(value->IsString());
8726 v8::String::AsciiValue name(value);
8727 CHECK_EQ("asdf", *name);
8728}
8729
8730
8731THREADED_TEST(DateAccess) {
8732 v8::HandleScope scope;
8733 LocalContext context;
8734 v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
8735 CHECK(date->IsDate());
Steve Block6ded16b2010-05-10 14:33:55 +01008736 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue());
Steve Blocka7e24c12009-10-30 11:49:00 +00008737}
8738
8739
8740void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
Steve Block6ded16b2010-05-10 14:33:55 +01008741 v8::Handle<v8::Object> obj = val.As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00008742 v8::Handle<v8::Array> props = obj->GetPropertyNames();
8743 CHECK_EQ(elmc, props->Length());
8744 for (int i = 0; i < elmc; i++) {
8745 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
8746 CHECK_EQ(elmv[i], *elm);
8747 }
8748}
8749
8750
8751THREADED_TEST(PropertyEnumeration) {
8752 v8::HandleScope scope;
8753 LocalContext context;
8754 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
8755 "var result = [];"
8756 "result[0] = {};"
8757 "result[1] = {a: 1, b: 2};"
8758 "result[2] = [1, 2, 3];"
8759 "var proto = {x: 1, y: 2, z: 3};"
8760 "var x = { __proto__: proto, w: 0, z: 1 };"
8761 "result[3] = x;"
8762 "result;"))->Run();
Steve Block6ded16b2010-05-10 14:33:55 +01008763 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00008764 CHECK_EQ(4, elms->Length());
8765 int elmc0 = 0;
8766 const char** elmv0 = NULL;
8767 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
8768 int elmc1 = 2;
8769 const char* elmv1[] = {"a", "b"};
8770 CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
8771 int elmc2 = 3;
8772 const char* elmv2[] = {"0", "1", "2"};
8773 CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
8774 int elmc3 = 4;
8775 const char* elmv3[] = {"w", "z", "x", "y"};
8776 CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
8777}
8778
8779
Steve Blocka7e24c12009-10-30 11:49:00 +00008780static bool NamedSetAccessBlocker(Local<v8::Object> obj,
8781 Local<Value> name,
8782 v8::AccessType type,
8783 Local<Value> data) {
8784 return type != v8::ACCESS_SET;
8785}
8786
8787
8788static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
8789 uint32_t key,
8790 v8::AccessType type,
8791 Local<Value> data) {
8792 return type != v8::ACCESS_SET;
8793}
8794
8795
8796THREADED_TEST(DisableAccessChecksWhileConfiguring) {
8797 v8::HandleScope scope;
8798 LocalContext context;
8799 Local<ObjectTemplate> templ = ObjectTemplate::New();
8800 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
8801 IndexedSetAccessBlocker);
8802 templ->Set(v8_str("x"), v8::True());
8803 Local<v8::Object> instance = templ->NewInstance();
8804 context->Global()->Set(v8_str("obj"), instance);
8805 Local<Value> value = CompileRun("obj.x");
8806 CHECK(value->BooleanValue());
8807}
8808
8809
8810static bool NamedGetAccessBlocker(Local<v8::Object> obj,
8811 Local<Value> name,
8812 v8::AccessType type,
8813 Local<Value> data) {
8814 return false;
8815}
8816
8817
8818static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
8819 uint32_t key,
8820 v8::AccessType type,
8821 Local<Value> data) {
8822 return false;
8823}
8824
8825
8826
8827THREADED_TEST(AccessChecksReenabledCorrectly) {
8828 v8::HandleScope scope;
8829 LocalContext context;
8830 Local<ObjectTemplate> templ = ObjectTemplate::New();
8831 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
8832 IndexedGetAccessBlocker);
8833 templ->Set(v8_str("a"), v8_str("a"));
8834 // Add more than 8 (see kMaxFastProperties) properties
8835 // so that the constructor will force copying map.
8836 // Cannot sprintf, gcc complains unsafety.
8837 char buf[4];
8838 for (char i = '0'; i <= '9' ; i++) {
8839 buf[0] = i;
8840 for (char j = '0'; j <= '9'; j++) {
8841 buf[1] = j;
8842 for (char k = '0'; k <= '9'; k++) {
8843 buf[2] = k;
8844 buf[3] = 0;
8845 templ->Set(v8_str(buf), v8::Number::New(k));
8846 }
8847 }
8848 }
8849
8850 Local<v8::Object> instance_1 = templ->NewInstance();
8851 context->Global()->Set(v8_str("obj_1"), instance_1);
8852
8853 Local<Value> value_1 = CompileRun("obj_1.a");
8854 CHECK(value_1->IsUndefined());
8855
8856 Local<v8::Object> instance_2 = templ->NewInstance();
8857 context->Global()->Set(v8_str("obj_2"), instance_2);
8858
8859 Local<Value> value_2 = CompileRun("obj_2.a");
8860 CHECK(value_2->IsUndefined());
8861}
8862
8863
8864// This tests that access check information remains on the global
8865// object template when creating contexts.
8866THREADED_TEST(AccessControlRepeatedContextCreation) {
8867 v8::HandleScope handle_scope;
8868 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
8869 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
8870 IndexedSetAccessBlocker);
8871 i::Handle<i::ObjectTemplateInfo> internal_template =
8872 v8::Utils::OpenHandle(*global_template);
8873 CHECK(!internal_template->constructor()->IsUndefined());
8874 i::Handle<i::FunctionTemplateInfo> constructor(
8875 i::FunctionTemplateInfo::cast(internal_template->constructor()));
8876 CHECK(!constructor->access_check_info()->IsUndefined());
8877 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
8878 CHECK(!constructor->access_check_info()->IsUndefined());
8879}
8880
8881
8882THREADED_TEST(TurnOnAccessCheck) {
8883 v8::HandleScope handle_scope;
8884
8885 // Create an environment with access check to the global object disabled by
8886 // default.
8887 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
8888 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
8889 IndexedGetAccessBlocker,
8890 v8::Handle<v8::Value>(),
8891 false);
8892 v8::Persistent<Context> context = Context::New(NULL, global_template);
8893 Context::Scope context_scope(context);
8894
8895 // Set up a property and a number of functions.
8896 context->Global()->Set(v8_str("a"), v8_num(1));
8897 CompileRun("function f1() {return a;}"
8898 "function f2() {return a;}"
8899 "function g1() {return h();}"
8900 "function g2() {return h();}"
8901 "function h() {return 1;}");
8902 Local<Function> f1 =
8903 Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
8904 Local<Function> f2 =
8905 Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
8906 Local<Function> g1 =
8907 Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
8908 Local<Function> g2 =
8909 Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
8910 Local<Function> h =
8911 Local<Function>::Cast(context->Global()->Get(v8_str("h")));
8912
8913 // Get the global object.
8914 v8::Handle<v8::Object> global = context->Global();
8915
8916 // Call f1 one time and f2 a number of times. This will ensure that f1 still
8917 // uses the runtime system to retreive property a whereas f2 uses global load
8918 // inline cache.
8919 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
8920 for (int i = 0; i < 4; i++) {
8921 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
8922 }
8923
8924 // Same for g1 and g2.
8925 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
8926 for (int i = 0; i < 4; i++) {
8927 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
8928 }
8929
8930 // Detach the global and turn on access check.
8931 context->DetachGlobal();
8932 context->Global()->TurnOnAccessCheck();
8933
8934 // Failing access check to property get results in undefined.
8935 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
8936 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
8937
8938 // Failing access check to function call results in exception.
8939 CHECK(g1->Call(global, 0, NULL).IsEmpty());
8940 CHECK(g2->Call(global, 0, NULL).IsEmpty());
8941
8942 // No failing access check when just returning a constant.
8943 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
8944}
8945
8946
Ben Murdochb0fe1622011-05-05 13:52:32 +01008947v8::Handle<v8::String> a;
8948v8::Handle<v8::String> h;
8949
8950static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
8951 Local<Value> name,
8952 v8::AccessType type,
8953 Local<Value> data) {
8954 return !(name->Equals(a) || name->Equals(h));
8955}
8956
8957
8958THREADED_TEST(TurnOnAccessCheckAndRecompile) {
8959 v8::HandleScope handle_scope;
8960
8961 // Create an environment with access check to the global object disabled by
8962 // default. When the registered access checker will block access to properties
8963 // a and h
8964 a = v8_str("a");
8965 h = v8_str("h");
8966 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
8967 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
8968 IndexedGetAccessBlocker,
8969 v8::Handle<v8::Value>(),
8970 false);
8971 v8::Persistent<Context> context = Context::New(NULL, global_template);
8972 Context::Scope context_scope(context);
8973
8974 // Set up a property and a number of functions.
8975 context->Global()->Set(v8_str("a"), v8_num(1));
8976 static const char* source = "function f1() {return a;}"
8977 "function f2() {return a;}"
8978 "function g1() {return h();}"
8979 "function g2() {return h();}"
8980 "function h() {return 1;}";
8981
8982 CompileRun(source);
8983 Local<Function> f1;
8984 Local<Function> f2;
8985 Local<Function> g1;
8986 Local<Function> g2;
8987 Local<Function> h;
8988 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
8989 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
8990 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
8991 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
8992 h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
8993
8994 // Get the global object.
8995 v8::Handle<v8::Object> global = context->Global();
8996
8997 // Call f1 one time and f2 a number of times. This will ensure that f1 still
8998 // uses the runtime system to retreive property a whereas f2 uses global load
8999 // inline cache.
9000 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
9001 for (int i = 0; i < 4; i++) {
9002 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
9003 }
9004
9005 // Same for g1 and g2.
9006 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
9007 for (int i = 0; i < 4; i++) {
9008 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
9009 }
9010
9011 // Detach the global and turn on access check now blocking access to property
9012 // a and function h.
9013 context->DetachGlobal();
9014 context->Global()->TurnOnAccessCheck();
9015
9016 // Failing access check to property get results in undefined.
9017 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
9018 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
9019
9020 // Failing access check to function call results in exception.
9021 CHECK(g1->Call(global, 0, NULL).IsEmpty());
9022 CHECK(g2->Call(global, 0, NULL).IsEmpty());
9023
9024 // No failing access check when just returning a constant.
9025 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
9026
9027 // Now compile the source again. And get the newly compiled functions, except
9028 // for h for which access is blocked.
9029 CompileRun(source);
9030 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
9031 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
9032 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
9033 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
9034 CHECK(context->Global()->Get(v8_str("h"))->IsUndefined());
9035
9036 // Failing access check to property get results in undefined.
9037 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
9038 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
9039
9040 // Failing access check to function call results in exception.
9041 CHECK(g1->Call(global, 0, NULL).IsEmpty());
9042 CHECK(g2->Call(global, 0, NULL).IsEmpty());
9043}
9044
9045
Steve Blocka7e24c12009-10-30 11:49:00 +00009046// This test verifies that pre-compilation (aka preparsing) can be called
9047// without initializing the whole VM. Thus we cannot run this test in a
9048// multi-threaded setup.
9049TEST(PreCompile) {
9050 // TODO(155): This test would break without the initialization of V8. This is
9051 // a workaround for now to make this test not fail.
9052 v8::V8::Initialize();
Leon Clarkef7060e22010-06-03 12:02:55 +01009053 const char* script = "function foo(a) { return a+1; }";
9054 v8::ScriptData* sd =
Steve Blockd0582a62009-12-15 09:54:21 +00009055 v8::ScriptData::PreCompile(script, i::StrLength(script));
Steve Blocka7e24c12009-10-30 11:49:00 +00009056 CHECK_NE(sd->Length(), 0);
9057 CHECK_NE(sd->Data(), NULL);
Leon Clarkee46be812010-01-19 14:06:41 +00009058 CHECK(!sd->HasError());
9059 delete sd;
9060}
9061
9062
9063TEST(PreCompileWithError) {
9064 v8::V8::Initialize();
Leon Clarkef7060e22010-06-03 12:02:55 +01009065 const char* script = "function foo(a) { return 1 * * 2; }";
9066 v8::ScriptData* sd =
Leon Clarkee46be812010-01-19 14:06:41 +00009067 v8::ScriptData::PreCompile(script, i::StrLength(script));
9068 CHECK(sd->HasError());
9069 delete sd;
9070}
9071
9072
9073TEST(Regress31661) {
9074 v8::V8::Initialize();
Leon Clarkef7060e22010-06-03 12:02:55 +01009075 const char* script = " The Definintive Guide";
9076 v8::ScriptData* sd =
Leon Clarkee46be812010-01-19 14:06:41 +00009077 v8::ScriptData::PreCompile(script, i::StrLength(script));
9078 CHECK(sd->HasError());
Steve Blocka7e24c12009-10-30 11:49:00 +00009079 delete sd;
9080}
9081
9082
Leon Clarkef7060e22010-06-03 12:02:55 +01009083// Tests that ScriptData can be serialized and deserialized.
9084TEST(PreCompileSerialization) {
9085 v8::V8::Initialize();
9086 const char* script = "function foo(a) { return a+1; }";
9087 v8::ScriptData* sd =
9088 v8::ScriptData::PreCompile(script, i::StrLength(script));
9089
9090 // Serialize.
9091 int serialized_data_length = sd->Length();
9092 char* serialized_data = i::NewArray<char>(serialized_data_length);
9093 memcpy(serialized_data, sd->Data(), serialized_data_length);
9094
9095 // Deserialize.
9096 v8::ScriptData* deserialized_sd =
9097 v8::ScriptData::New(serialized_data, serialized_data_length);
9098
9099 // Verify that the original is the same as the deserialized.
9100 CHECK_EQ(sd->Length(), deserialized_sd->Length());
9101 CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
9102 CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
9103
9104 delete sd;
9105 delete deserialized_sd;
9106}
9107
9108
9109// Attempts to deserialize bad data.
9110TEST(PreCompileDeserializationError) {
9111 v8::V8::Initialize();
9112 const char* data = "DONT CARE";
9113 int invalid_size = 3;
9114 v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
9115
9116 CHECK_EQ(0, sd->Length());
9117
9118 delete sd;
9119}
9120
9121
Leon Clarkeac952652010-07-15 11:15:24 +01009122// Attempts to deserialize bad data.
9123TEST(PreCompileInvalidPreparseDataError) {
9124 v8::V8::Initialize();
9125 v8::HandleScope scope;
9126 LocalContext context;
9127
9128 const char* script = "function foo(){ return 5;}\n"
9129 "function bar(){ return 6 + 7;} foo();";
9130 v8::ScriptData* sd =
9131 v8::ScriptData::PreCompile(script, i::StrLength(script));
9132 CHECK(!sd->HasError());
9133 // ScriptDataImpl private implementation details
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08009134 const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
Iain Merrick9ac36c92010-09-13 15:29:50 +01009135 const int kFunctionEntrySize = i::FunctionEntry::kSize;
Leon Clarkeac952652010-07-15 11:15:24 +01009136 const int kFunctionEntryStartOffset = 0;
9137 const int kFunctionEntryEndOffset = 1;
9138 unsigned* sd_data =
9139 reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
Leon Clarkeac952652010-07-15 11:15:24 +01009140
9141 // Overwrite function bar's end position with 0.
9142 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
9143 v8::TryCatch try_catch;
9144
9145 Local<String> source = String::New(script);
9146 Local<Script> compiled_script = Script::New(source, NULL, sd);
9147 CHECK(try_catch.HasCaught());
9148 String::AsciiValue exception_value(try_catch.Message()->Get());
9149 CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
9150 *exception_value);
9151
9152 try_catch.Reset();
9153 // Overwrite function bar's start position with 200. The function entry
9154 // will not be found when searching for it by position.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01009155 sd = v8::ScriptData::PreCompile(script, i::StrLength(script));
9156 sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
Leon Clarkeac952652010-07-15 11:15:24 +01009157 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
9158 200;
9159 compiled_script = Script::New(source, NULL, sd);
9160 CHECK(try_catch.HasCaught());
9161 String::AsciiValue second_exception_value(try_catch.Message()->Get());
9162 CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
9163 *second_exception_value);
9164
9165 delete sd;
9166}
9167
9168
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009169// Verifies that the Handle<String> and const char* versions of the API produce
9170// the same results (at least for one trivial case).
9171TEST(PreCompileAPIVariationsAreSame) {
9172 v8::V8::Initialize();
9173 v8::HandleScope scope;
9174
9175 const char* cstring = "function foo(a) { return a+1; }";
Ben Murdoch3bec4d22010-07-22 14:51:16 +01009176
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009177 v8::ScriptData* sd_from_cstring =
9178 v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
9179
9180 TestAsciiResource* resource = new TestAsciiResource(cstring);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01009181 v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile(
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009182 v8::String::NewExternal(resource));
9183
Ben Murdoch3bec4d22010-07-22 14:51:16 +01009184 v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile(
9185 v8::String::New(cstring));
9186
9187 CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009188 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
Ben Murdoch3bec4d22010-07-22 14:51:16 +01009189 sd_from_external_string->Data(),
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009190 sd_from_cstring->Length()));
9191
Ben Murdoch3bec4d22010-07-22 14:51:16 +01009192 CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length());
9193 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
9194 sd_from_string->Data(),
9195 sd_from_cstring->Length()));
9196
9197
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009198 delete sd_from_cstring;
Ben Murdoch3bec4d22010-07-22 14:51:16 +01009199 delete sd_from_external_string;
9200 delete sd_from_string;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009201}
9202
9203
Steve Blocka7e24c12009-10-30 11:49:00 +00009204// This tests that we do not allow dictionary load/call inline caches
9205// to use functions that have not yet been compiled. The potential
9206// problem of loading a function that has not yet been compiled can
9207// arise because we share code between contexts via the compilation
9208// cache.
9209THREADED_TEST(DictionaryICLoadedFunction) {
9210 v8::HandleScope scope;
9211 // Test LoadIC.
9212 for (int i = 0; i < 2; i++) {
9213 LocalContext context;
9214 context->Global()->Set(v8_str("tmp"), v8::True());
9215 context->Global()->Delete(v8_str("tmp"));
9216 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
9217 }
9218 // Test CallIC.
9219 for (int i = 0; i < 2; i++) {
9220 LocalContext context;
9221 context->Global()->Set(v8_str("tmp"), v8::True());
9222 context->Global()->Delete(v8_str("tmp"));
9223 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
9224 }
9225}
9226
9227
9228// Test that cross-context new calls use the context of the callee to
9229// create the new JavaScript object.
9230THREADED_TEST(CrossContextNew) {
9231 v8::HandleScope scope;
9232 v8::Persistent<Context> context0 = Context::New();
9233 v8::Persistent<Context> context1 = Context::New();
9234
9235 // Allow cross-domain access.
9236 Local<String> token = v8_str("<security token>");
9237 context0->SetSecurityToken(token);
9238 context1->SetSecurityToken(token);
9239
9240 // Set an 'x' property on the Object prototype and define a
9241 // constructor function in context0.
9242 context0->Enter();
9243 CompileRun("Object.prototype.x = 42; function C() {};");
9244 context0->Exit();
9245
9246 // Call the constructor function from context0 and check that the
9247 // result has the 'x' property.
9248 context1->Enter();
9249 context1->Global()->Set(v8_str("other"), context0->Global());
9250 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
9251 CHECK(value->IsInt32());
9252 CHECK_EQ(42, value->Int32Value());
9253 context1->Exit();
9254
9255 // Dispose the contexts to allow them to be garbage collected.
9256 context0.Dispose();
9257 context1.Dispose();
9258}
9259
9260
9261class RegExpInterruptTest {
9262 public:
9263 RegExpInterruptTest() : block_(NULL) {}
9264 ~RegExpInterruptTest() { delete block_; }
9265 void RunTest() {
9266 block_ = i::OS::CreateSemaphore(0);
9267 gc_count_ = 0;
9268 gc_during_regexp_ = 0;
9269 regexp_success_ = false;
9270 gc_success_ = false;
9271 GCThread gc_thread(this);
9272 gc_thread.Start();
9273 v8::Locker::StartPreemption(1);
9274
9275 LongRunningRegExp();
9276 {
9277 v8::Unlocker unlock;
9278 gc_thread.Join();
9279 }
9280 v8::Locker::StopPreemption();
9281 CHECK(regexp_success_);
9282 CHECK(gc_success_);
9283 }
9284 private:
9285 // Number of garbage collections required.
9286 static const int kRequiredGCs = 5;
9287
9288 class GCThread : public i::Thread {
9289 public:
9290 explicit GCThread(RegExpInterruptTest* test)
9291 : test_(test) {}
9292 virtual void Run() {
9293 test_->CollectGarbage();
9294 }
9295 private:
9296 RegExpInterruptTest* test_;
9297 };
9298
9299 void CollectGarbage() {
9300 block_->Wait();
9301 while (gc_during_regexp_ < kRequiredGCs) {
9302 {
9303 v8::Locker lock;
9304 // TODO(lrn): Perhaps create some garbage before collecting.
9305 i::Heap::CollectAllGarbage(false);
9306 gc_count_++;
9307 }
9308 i::OS::Sleep(1);
9309 }
9310 gc_success_ = true;
9311 }
9312
9313 void LongRunningRegExp() {
9314 block_->Signal(); // Enable garbage collection thread on next preemption.
9315 int rounds = 0;
9316 while (gc_during_regexp_ < kRequiredGCs) {
9317 int gc_before = gc_count_;
9318 {
9319 // Match 15-30 "a"'s against 14 and a "b".
9320 const char* c_source =
9321 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
9322 ".exec('aaaaaaaaaaaaaaab') === null";
9323 Local<String> source = String::New(c_source);
9324 Local<Script> script = Script::Compile(source);
9325 Local<Value> result = script->Run();
9326 if (!result->BooleanValue()) {
9327 gc_during_regexp_ = kRequiredGCs; // Allow gc thread to exit.
9328 return;
9329 }
9330 }
9331 {
9332 // Match 15-30 "a"'s against 15 and a "b".
9333 const char* c_source =
9334 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
9335 ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
9336 Local<String> source = String::New(c_source);
9337 Local<Script> script = Script::Compile(source);
9338 Local<Value> result = script->Run();
9339 if (!result->BooleanValue()) {
9340 gc_during_regexp_ = kRequiredGCs;
9341 return;
9342 }
9343 }
9344 int gc_after = gc_count_;
9345 gc_during_regexp_ += gc_after - gc_before;
9346 rounds++;
9347 i::OS::Sleep(1);
9348 }
9349 regexp_success_ = true;
9350 }
9351
9352 i::Semaphore* block_;
9353 int gc_count_;
9354 int gc_during_regexp_;
9355 bool regexp_success_;
9356 bool gc_success_;
9357};
9358
9359
9360// Test that a regular expression execution can be interrupted and
9361// survive a garbage collection.
9362TEST(RegExpInterruption) {
9363 v8::Locker lock;
9364 v8::V8::Initialize();
9365 v8::HandleScope scope;
9366 Local<Context> local_env;
9367 {
9368 LocalContext env;
9369 local_env = env.local();
9370 }
9371
9372 // Local context should still be live.
9373 CHECK(!local_env.IsEmpty());
9374 local_env->Enter();
9375
9376 // Should complete without problems.
9377 RegExpInterruptTest().RunTest();
9378
9379 local_env->Exit();
9380}
9381
9382
9383class ApplyInterruptTest {
9384 public:
9385 ApplyInterruptTest() : block_(NULL) {}
9386 ~ApplyInterruptTest() { delete block_; }
9387 void RunTest() {
9388 block_ = i::OS::CreateSemaphore(0);
9389 gc_count_ = 0;
9390 gc_during_apply_ = 0;
9391 apply_success_ = false;
9392 gc_success_ = false;
9393 GCThread gc_thread(this);
9394 gc_thread.Start();
9395 v8::Locker::StartPreemption(1);
9396
9397 LongRunningApply();
9398 {
9399 v8::Unlocker unlock;
9400 gc_thread.Join();
9401 }
9402 v8::Locker::StopPreemption();
9403 CHECK(apply_success_);
9404 CHECK(gc_success_);
9405 }
9406 private:
9407 // Number of garbage collections required.
9408 static const int kRequiredGCs = 2;
9409
9410 class GCThread : public i::Thread {
9411 public:
9412 explicit GCThread(ApplyInterruptTest* test)
9413 : test_(test) {}
9414 virtual void Run() {
9415 test_->CollectGarbage();
9416 }
9417 private:
9418 ApplyInterruptTest* test_;
9419 };
9420
9421 void CollectGarbage() {
9422 block_->Wait();
9423 while (gc_during_apply_ < kRequiredGCs) {
9424 {
9425 v8::Locker lock;
9426 i::Heap::CollectAllGarbage(false);
9427 gc_count_++;
9428 }
9429 i::OS::Sleep(1);
9430 }
9431 gc_success_ = true;
9432 }
9433
9434 void LongRunningApply() {
9435 block_->Signal();
9436 int rounds = 0;
9437 while (gc_during_apply_ < kRequiredGCs) {
9438 int gc_before = gc_count_;
9439 {
9440 const char* c_source =
9441 "function do_very_little(bar) {"
9442 " this.foo = bar;"
9443 "}"
9444 "for (var i = 0; i < 100000; i++) {"
9445 " do_very_little.apply(this, ['bar']);"
9446 "}";
9447 Local<String> source = String::New(c_source);
9448 Local<Script> script = Script::Compile(source);
9449 Local<Value> result = script->Run();
9450 // Check that no exception was thrown.
9451 CHECK(!result.IsEmpty());
9452 }
9453 int gc_after = gc_count_;
9454 gc_during_apply_ += gc_after - gc_before;
9455 rounds++;
9456 }
9457 apply_success_ = true;
9458 }
9459
9460 i::Semaphore* block_;
9461 int gc_count_;
9462 int gc_during_apply_;
9463 bool apply_success_;
9464 bool gc_success_;
9465};
9466
9467
9468// Test that nothing bad happens if we get a preemption just when we were
9469// about to do an apply().
9470TEST(ApplyInterruption) {
9471 v8::Locker lock;
9472 v8::V8::Initialize();
9473 v8::HandleScope scope;
9474 Local<Context> local_env;
9475 {
9476 LocalContext env;
9477 local_env = env.local();
9478 }
9479
9480 // Local context should still be live.
9481 CHECK(!local_env.IsEmpty());
9482 local_env->Enter();
9483
9484 // Should complete without problems.
9485 ApplyInterruptTest().RunTest();
9486
9487 local_env->Exit();
9488}
9489
9490
9491// Verify that we can clone an object
9492TEST(ObjectClone) {
9493 v8::HandleScope scope;
9494 LocalContext env;
9495
9496 const char* sample =
9497 "var rv = {};" \
9498 "rv.alpha = 'hello';" \
9499 "rv.beta = 123;" \
9500 "rv;";
9501
9502 // Create an object, verify basics.
9503 Local<Value> val = CompileRun(sample);
9504 CHECK(val->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01009505 Local<v8::Object> obj = val.As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00009506 obj->Set(v8_str("gamma"), v8_str("cloneme"));
9507
9508 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
9509 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
9510 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
9511
9512 // Clone it.
9513 Local<v8::Object> clone = obj->Clone();
9514 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
9515 CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
9516 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
9517
9518 // Set a property on the clone, verify each object.
9519 clone->Set(v8_str("beta"), v8::Integer::New(456));
9520 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
9521 CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
9522}
9523
9524
9525class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
9526 public:
9527 explicit AsciiVectorResource(i::Vector<const char> vector)
9528 : data_(vector) {}
9529 virtual ~AsciiVectorResource() {}
9530 virtual size_t length() const { return data_.length(); }
9531 virtual const char* data() const { return data_.start(); }
9532 private:
9533 i::Vector<const char> data_;
9534};
9535
9536
9537class UC16VectorResource : public v8::String::ExternalStringResource {
9538 public:
9539 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
9540 : data_(vector) {}
9541 virtual ~UC16VectorResource() {}
9542 virtual size_t length() const { return data_.length(); }
9543 virtual const i::uc16* data() const { return data_.start(); }
9544 private:
9545 i::Vector<const i::uc16> data_;
9546};
9547
9548
9549static void MorphAString(i::String* string,
9550 AsciiVectorResource* ascii_resource,
9551 UC16VectorResource* uc16_resource) {
9552 CHECK(i::StringShape(string).IsExternal());
9553 if (string->IsAsciiRepresentation()) {
9554 // Check old map is not symbol or long.
Steve Blockd0582a62009-12-15 09:54:21 +00009555 CHECK(string->map() == i::Heap::external_ascii_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00009556 // Morph external string to be TwoByte string.
Steve Blockd0582a62009-12-15 09:54:21 +00009557 string->set_map(i::Heap::external_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00009558 i::ExternalTwoByteString* morphed =
9559 i::ExternalTwoByteString::cast(string);
9560 morphed->set_resource(uc16_resource);
9561 } else {
9562 // Check old map is not symbol or long.
Steve Blockd0582a62009-12-15 09:54:21 +00009563 CHECK(string->map() == i::Heap::external_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00009564 // Morph external string to be ASCII string.
Steve Blockd0582a62009-12-15 09:54:21 +00009565 string->set_map(i::Heap::external_ascii_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00009566 i::ExternalAsciiString* morphed =
9567 i::ExternalAsciiString::cast(string);
9568 morphed->set_resource(ascii_resource);
9569 }
9570}
9571
9572
9573// Test that we can still flatten a string if the components it is built up
9574// from have been turned into 16 bit strings in the mean time.
9575THREADED_TEST(MorphCompositeStringTest) {
9576 const char* c_string = "Now is the time for all good men"
9577 " to come to the aid of the party";
9578 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
9579 {
9580 v8::HandleScope scope;
9581 LocalContext env;
9582 AsciiVectorResource ascii_resource(
Steve Blockd0582a62009-12-15 09:54:21 +00009583 i::Vector<const char>(c_string, i::StrLength(c_string)));
Steve Blocka7e24c12009-10-30 11:49:00 +00009584 UC16VectorResource uc16_resource(
Steve Blockd0582a62009-12-15 09:54:21 +00009585 i::Vector<const uint16_t>(two_byte_string,
9586 i::StrLength(c_string)));
Steve Blocka7e24c12009-10-30 11:49:00 +00009587
9588 Local<String> lhs(v8::Utils::ToLocal(
9589 i::Factory::NewExternalStringFromAscii(&ascii_resource)));
9590 Local<String> rhs(v8::Utils::ToLocal(
9591 i::Factory::NewExternalStringFromAscii(&ascii_resource)));
9592
9593 env->Global()->Set(v8_str("lhs"), lhs);
9594 env->Global()->Set(v8_str("rhs"), rhs);
9595
9596 CompileRun(
9597 "var cons = lhs + rhs;"
9598 "var slice = lhs.substring(1, lhs.length - 1);"
9599 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
9600
9601 MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
9602 MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
9603
9604 // Now do some stuff to make sure the strings are flattened, etc.
9605 CompileRun(
9606 "/[^a-z]/.test(cons);"
9607 "/[^a-z]/.test(slice);"
9608 "/[^a-z]/.test(slice_on_cons);");
9609 const char* expected_cons =
9610 "Now is the time for all good men to come to the aid of the party"
9611 "Now is the time for all good men to come to the aid of the party";
9612 const char* expected_slice =
9613 "ow is the time for all good men to come to the aid of the part";
9614 const char* expected_slice_on_cons =
9615 "ow is the time for all good men to come to the aid of the party"
9616 "Now is the time for all good men to come to the aid of the part";
9617 CHECK_EQ(String::New(expected_cons),
9618 env->Global()->Get(v8_str("cons")));
9619 CHECK_EQ(String::New(expected_slice),
9620 env->Global()->Get(v8_str("slice")));
9621 CHECK_EQ(String::New(expected_slice_on_cons),
9622 env->Global()->Get(v8_str("slice_on_cons")));
9623 }
Ben Murdoch3bec4d22010-07-22 14:51:16 +01009624 i::DeleteArray(two_byte_string);
Steve Blocka7e24c12009-10-30 11:49:00 +00009625}
9626
9627
9628TEST(CompileExternalTwoByteSource) {
9629 v8::HandleScope scope;
9630 LocalContext context;
9631
9632 // This is a very short list of sources, which currently is to check for a
9633 // regression caused by r2703.
9634 const char* ascii_sources[] = {
9635 "0.5",
9636 "-0.5", // This mainly testes PushBack in the Scanner.
9637 "--0.5", // This mainly testes PushBack in the Scanner.
9638 NULL
9639 };
9640
9641 // Compile the sources as external two byte strings.
9642 for (int i = 0; ascii_sources[i] != NULL; i++) {
9643 uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
9644 UC16VectorResource uc16_resource(
Steve Blockd0582a62009-12-15 09:54:21 +00009645 i::Vector<const uint16_t>(two_byte_string,
9646 i::StrLength(ascii_sources[i])));
Steve Blocka7e24c12009-10-30 11:49:00 +00009647 v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
9648 v8::Script::Compile(source);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01009649 i::DeleteArray(two_byte_string);
Steve Blocka7e24c12009-10-30 11:49:00 +00009650 }
9651}
9652
9653
9654class RegExpStringModificationTest {
9655 public:
9656 RegExpStringModificationTest()
9657 : block_(i::OS::CreateSemaphore(0)),
9658 morphs_(0),
9659 morphs_during_regexp_(0),
9660 ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
9661 uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
9662 ~RegExpStringModificationTest() { delete block_; }
9663 void RunTest() {
9664 regexp_success_ = false;
9665 morph_success_ = false;
9666
9667 // Initialize the contents of two_byte_content_ to be a uc16 representation
9668 // of "aaaaaaaaaaaaaab".
9669 for (int i = 0; i < 14; i++) {
9670 two_byte_content_[i] = 'a';
9671 }
9672 two_byte_content_[14] = 'b';
9673
9674 // Create the input string for the regexp - the one we are going to change
9675 // properties of.
9676 input_ = i::Factory::NewExternalStringFromAscii(&ascii_resource_);
9677
9678 // Inject the input as a global variable.
9679 i::Handle<i::String> input_name =
9680 i::Factory::NewStringFromAscii(i::Vector<const char>("input", 5));
John Reck59135872010-11-02 12:39:01 -07009681 i::Top::global_context()->global()->SetProperty(*input_name,
9682 *input_,
9683 NONE)->ToObjectChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00009684
9685
9686 MorphThread morph_thread(this);
9687 morph_thread.Start();
9688 v8::Locker::StartPreemption(1);
9689 LongRunningRegExp();
9690 {
9691 v8::Unlocker unlock;
9692 morph_thread.Join();
9693 }
9694 v8::Locker::StopPreemption();
9695 CHECK(regexp_success_);
9696 CHECK(morph_success_);
9697 }
9698 private:
9699
9700 // Number of string modifications required.
9701 static const int kRequiredModifications = 5;
9702 static const int kMaxModifications = 100;
9703
9704 class MorphThread : public i::Thread {
9705 public:
9706 explicit MorphThread(RegExpStringModificationTest* test)
9707 : test_(test) {}
9708 virtual void Run() {
9709 test_->MorphString();
9710 }
9711 private:
9712 RegExpStringModificationTest* test_;
9713 };
9714
9715 void MorphString() {
9716 block_->Wait();
9717 while (morphs_during_regexp_ < kRequiredModifications &&
9718 morphs_ < kMaxModifications) {
9719 {
9720 v8::Locker lock;
9721 // Swap string between ascii and two-byte representation.
9722 i::String* string = *input_;
9723 MorphAString(string, &ascii_resource_, &uc16_resource_);
9724 morphs_++;
9725 }
9726 i::OS::Sleep(1);
9727 }
9728 morph_success_ = true;
9729 }
9730
9731 void LongRunningRegExp() {
9732 block_->Signal(); // Enable morphing thread on next preemption.
9733 while (morphs_during_regexp_ < kRequiredModifications &&
9734 morphs_ < kMaxModifications) {
9735 int morphs_before = morphs_;
9736 {
Steve Block791712a2010-08-27 10:21:07 +01009737 v8::HandleScope scope;
Steve Blocka7e24c12009-10-30 11:49:00 +00009738 // Match 15-30 "a"'s against 14 and a "b".
9739 const char* c_source =
9740 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
9741 ".exec(input) === null";
9742 Local<String> source = String::New(c_source);
9743 Local<Script> script = Script::Compile(source);
9744 Local<Value> result = script->Run();
9745 CHECK(result->IsTrue());
9746 }
9747 int morphs_after = morphs_;
9748 morphs_during_regexp_ += morphs_after - morphs_before;
9749 }
9750 regexp_success_ = true;
9751 }
9752
9753 i::uc16 two_byte_content_[15];
9754 i::Semaphore* block_;
9755 int morphs_;
9756 int morphs_during_regexp_;
9757 bool regexp_success_;
9758 bool morph_success_;
9759 i::Handle<i::String> input_;
9760 AsciiVectorResource ascii_resource_;
9761 UC16VectorResource uc16_resource_;
9762};
9763
9764
9765// Test that a regular expression execution can be interrupted and
9766// the string changed without failing.
9767TEST(RegExpStringModification) {
9768 v8::Locker lock;
9769 v8::V8::Initialize();
9770 v8::HandleScope scope;
9771 Local<Context> local_env;
9772 {
9773 LocalContext env;
9774 local_env = env.local();
9775 }
9776
9777 // Local context should still be live.
9778 CHECK(!local_env.IsEmpty());
9779 local_env->Enter();
9780
9781 // Should complete without problems.
9782 RegExpStringModificationTest().RunTest();
9783
9784 local_env->Exit();
9785}
9786
9787
9788// Test that we can set a property on the global object even if there
9789// is a read-only property in the prototype chain.
9790TEST(ReadOnlyPropertyInGlobalProto) {
9791 v8::HandleScope scope;
9792 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9793 LocalContext context(0, templ);
9794 v8::Handle<v8::Object> global = context->Global();
9795 v8::Handle<v8::Object> global_proto =
9796 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
9797 global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
9798 global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
9799 // Check without 'eval' or 'with'.
9800 v8::Handle<v8::Value> res =
9801 CompileRun("function f() { x = 42; return x; }; f()");
9802 // Check with 'eval'.
9803 res = CompileRun("function f() { eval('1'); y = 42; return y; }; f()");
9804 CHECK_EQ(v8::Integer::New(42), res);
9805 // Check with 'with'.
9806 res = CompileRun("function f() { with (this) { y = 42 }; return y; }; f()");
9807 CHECK_EQ(v8::Integer::New(42), res);
9808}
9809
9810static int force_set_set_count = 0;
9811static int force_set_get_count = 0;
9812bool pass_on_get = false;
9813
9814static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
9815 const v8::AccessorInfo& info) {
9816 force_set_get_count++;
9817 if (pass_on_get) {
9818 return v8::Handle<v8::Value>();
9819 } else {
9820 return v8::Int32::New(3);
9821 }
9822}
9823
9824static void ForceSetSetter(v8::Local<v8::String> name,
9825 v8::Local<v8::Value> value,
9826 const v8::AccessorInfo& info) {
9827 force_set_set_count++;
9828}
9829
9830static v8::Handle<v8::Value> ForceSetInterceptSetter(
9831 v8::Local<v8::String> name,
9832 v8::Local<v8::Value> value,
9833 const v8::AccessorInfo& info) {
9834 force_set_set_count++;
9835 return v8::Undefined();
9836}
9837
9838TEST(ForceSet) {
9839 force_set_get_count = 0;
9840 force_set_set_count = 0;
9841 pass_on_get = false;
9842
9843 v8::HandleScope scope;
9844 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9845 v8::Handle<v8::String> access_property = v8::String::New("a");
9846 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
9847 LocalContext context(NULL, templ);
9848 v8::Handle<v8::Object> global = context->Global();
9849
9850 // Ordinary properties
9851 v8::Handle<v8::String> simple_property = v8::String::New("p");
9852 global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
9853 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
9854 // This should fail because the property is read-only
9855 global->Set(simple_property, v8::Int32::New(5));
9856 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
9857 // This should succeed even though the property is read-only
9858 global->ForceSet(simple_property, v8::Int32::New(6));
9859 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
9860
9861 // Accessors
9862 CHECK_EQ(0, force_set_set_count);
9863 CHECK_EQ(0, force_set_get_count);
9864 CHECK_EQ(3, global->Get(access_property)->Int32Value());
9865 // CHECK_EQ the property shouldn't override it, just call the setter
9866 // which in this case does nothing.
9867 global->Set(access_property, v8::Int32::New(7));
9868 CHECK_EQ(3, global->Get(access_property)->Int32Value());
9869 CHECK_EQ(1, force_set_set_count);
9870 CHECK_EQ(2, force_set_get_count);
9871 // Forcing the property to be set should override the accessor without
9872 // calling it
9873 global->ForceSet(access_property, v8::Int32::New(8));
9874 CHECK_EQ(8, global->Get(access_property)->Int32Value());
9875 CHECK_EQ(1, force_set_set_count);
9876 CHECK_EQ(2, force_set_get_count);
9877}
9878
9879TEST(ForceSetWithInterceptor) {
9880 force_set_get_count = 0;
9881 force_set_set_count = 0;
9882 pass_on_get = false;
9883
9884 v8::HandleScope scope;
9885 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9886 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
9887 LocalContext context(NULL, templ);
9888 v8::Handle<v8::Object> global = context->Global();
9889
9890 v8::Handle<v8::String> some_property = v8::String::New("a");
9891 CHECK_EQ(0, force_set_set_count);
9892 CHECK_EQ(0, force_set_get_count);
9893 CHECK_EQ(3, global->Get(some_property)->Int32Value());
9894 // Setting the property shouldn't override it, just call the setter
9895 // which in this case does nothing.
9896 global->Set(some_property, v8::Int32::New(7));
9897 CHECK_EQ(3, global->Get(some_property)->Int32Value());
9898 CHECK_EQ(1, force_set_set_count);
9899 CHECK_EQ(2, force_set_get_count);
9900 // Getting the property when the interceptor returns an empty handle
9901 // should yield undefined, since the property isn't present on the
9902 // object itself yet.
9903 pass_on_get = true;
9904 CHECK(global->Get(some_property)->IsUndefined());
9905 CHECK_EQ(1, force_set_set_count);
9906 CHECK_EQ(3, force_set_get_count);
9907 // Forcing the property to be set should cause the value to be
9908 // set locally without calling the interceptor.
9909 global->ForceSet(some_property, v8::Int32::New(8));
9910 CHECK_EQ(8, global->Get(some_property)->Int32Value());
9911 CHECK_EQ(1, force_set_set_count);
9912 CHECK_EQ(4, force_set_get_count);
9913 // Reenabling the interceptor should cause it to take precedence over
9914 // the property
9915 pass_on_get = false;
9916 CHECK_EQ(3, global->Get(some_property)->Int32Value());
9917 CHECK_EQ(1, force_set_set_count);
9918 CHECK_EQ(5, force_set_get_count);
9919 // The interceptor should also work for other properties
9920 CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
9921 CHECK_EQ(1, force_set_set_count);
9922 CHECK_EQ(6, force_set_get_count);
9923}
9924
9925
9926THREADED_TEST(ForceDelete) {
9927 v8::HandleScope scope;
9928 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9929 LocalContext context(NULL, templ);
9930 v8::Handle<v8::Object> global = context->Global();
9931
9932 // Ordinary properties
9933 v8::Handle<v8::String> simple_property = v8::String::New("p");
9934 global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
9935 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
9936 // This should fail because the property is dont-delete.
9937 CHECK(!global->Delete(simple_property));
9938 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
9939 // This should succeed even though the property is dont-delete.
9940 CHECK(global->ForceDelete(simple_property));
9941 CHECK(global->Get(simple_property)->IsUndefined());
9942}
9943
9944
9945static int force_delete_interceptor_count = 0;
9946static bool pass_on_delete = false;
9947
9948
9949static v8::Handle<v8::Boolean> ForceDeleteDeleter(
9950 v8::Local<v8::String> name,
9951 const v8::AccessorInfo& info) {
9952 force_delete_interceptor_count++;
9953 if (pass_on_delete) {
9954 return v8::Handle<v8::Boolean>();
9955 } else {
9956 return v8::True();
9957 }
9958}
9959
9960
9961THREADED_TEST(ForceDeleteWithInterceptor) {
9962 force_delete_interceptor_count = 0;
9963 pass_on_delete = false;
9964
9965 v8::HandleScope scope;
9966 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9967 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
9968 LocalContext context(NULL, templ);
9969 v8::Handle<v8::Object> global = context->Global();
9970
9971 v8::Handle<v8::String> some_property = v8::String::New("a");
9972 global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
9973
9974 // Deleting a property should get intercepted and nothing should
9975 // happen.
9976 CHECK_EQ(0, force_delete_interceptor_count);
9977 CHECK(global->Delete(some_property));
9978 CHECK_EQ(1, force_delete_interceptor_count);
9979 CHECK_EQ(42, global->Get(some_property)->Int32Value());
9980 // Deleting the property when the interceptor returns an empty
9981 // handle should not delete the property since it is DontDelete.
9982 pass_on_delete = true;
9983 CHECK(!global->Delete(some_property));
9984 CHECK_EQ(2, force_delete_interceptor_count);
9985 CHECK_EQ(42, global->Get(some_property)->Int32Value());
9986 // Forcing the property to be deleted should delete the value
9987 // without calling the interceptor.
9988 CHECK(global->ForceDelete(some_property));
9989 CHECK(global->Get(some_property)->IsUndefined());
9990 CHECK_EQ(2, force_delete_interceptor_count);
9991}
9992
9993
9994// Make sure that forcing a delete invalidates any IC stubs, so we
9995// don't read the hole value.
9996THREADED_TEST(ForceDeleteIC) {
9997 v8::HandleScope scope;
9998 LocalContext context;
9999 // Create a DontDelete variable on the global object.
10000 CompileRun("this.__proto__ = { foo: 'horse' };"
10001 "var foo = 'fish';"
10002 "function f() { return foo.length; }");
10003 // Initialize the IC for foo in f.
10004 CompileRun("for (var i = 0; i < 4; i++) f();");
10005 // Make sure the value of foo is correct before the deletion.
10006 CHECK_EQ(4, CompileRun("f()")->Int32Value());
10007 // Force the deletion of foo.
10008 CHECK(context->Global()->ForceDelete(v8_str("foo")));
10009 // Make sure the value for foo is read from the prototype, and that
10010 // we don't get in trouble with reading the deleted cell value
10011 // sentinel.
10012 CHECK_EQ(5, CompileRun("f()")->Int32Value());
10013}
10014
10015
10016v8::Persistent<Context> calling_context0;
10017v8::Persistent<Context> calling_context1;
10018v8::Persistent<Context> calling_context2;
10019
10020
10021// Check that the call to the callback is initiated in
10022// calling_context2, the directly calling context is calling_context1
10023// and the callback itself is in calling_context0.
10024static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
10025 ApiTestFuzzer::Fuzz();
10026 CHECK(Context::GetCurrent() == calling_context0);
10027 CHECK(Context::GetCalling() == calling_context1);
10028 CHECK(Context::GetEntered() == calling_context2);
10029 return v8::Integer::New(42);
10030}
10031
10032
10033THREADED_TEST(GetCallingContext) {
10034 v8::HandleScope scope;
10035
10036 calling_context0 = Context::New();
10037 calling_context1 = Context::New();
10038 calling_context2 = Context::New();
10039
10040 // Allow cross-domain access.
10041 Local<String> token = v8_str("<security token>");
10042 calling_context0->SetSecurityToken(token);
10043 calling_context1->SetSecurityToken(token);
10044 calling_context2->SetSecurityToken(token);
10045
10046 // Create an object with a C++ callback in context0.
10047 calling_context0->Enter();
10048 Local<v8::FunctionTemplate> callback_templ =
10049 v8::FunctionTemplate::New(GetCallingContextCallback);
10050 calling_context0->Global()->Set(v8_str("callback"),
10051 callback_templ->GetFunction());
10052 calling_context0->Exit();
10053
10054 // Expose context0 in context1 and setup a function that calls the
10055 // callback function.
10056 calling_context1->Enter();
10057 calling_context1->Global()->Set(v8_str("context0"),
10058 calling_context0->Global());
10059 CompileRun("function f() { context0.callback() }");
10060 calling_context1->Exit();
10061
10062 // Expose context1 in context2 and call the callback function in
10063 // context0 indirectly through f in context1.
10064 calling_context2->Enter();
10065 calling_context2->Global()->Set(v8_str("context1"),
10066 calling_context1->Global());
10067 CompileRun("context1.f()");
10068 calling_context2->Exit();
10069
10070 // Dispose the contexts to allow them to be garbage collected.
10071 calling_context0.Dispose();
10072 calling_context1.Dispose();
10073 calling_context2.Dispose();
10074 calling_context0.Clear();
10075 calling_context1.Clear();
10076 calling_context2.Clear();
10077}
10078
10079
10080// Check that a variable declaration with no explicit initialization
10081// value does not shadow an existing property in the prototype chain.
10082//
10083// This is consistent with Firefox and Safari.
10084//
10085// See http://crbug.com/12548.
10086THREADED_TEST(InitGlobalVarInProtoChain) {
10087 v8::HandleScope scope;
10088 LocalContext context;
10089 // Introduce a variable in the prototype chain.
10090 CompileRun("__proto__.x = 42");
10091 v8::Handle<v8::Value> result = CompileRun("var x; x");
10092 CHECK(!result->IsUndefined());
10093 CHECK_EQ(42, result->Int32Value());
10094}
10095
10096
10097// Regression test for issue 398.
10098// If a function is added to an object, creating a constant function
10099// field, and the result is cloned, replacing the constant function on the
10100// original should not affect the clone.
10101// See http://code.google.com/p/v8/issues/detail?id=398
10102THREADED_TEST(ReplaceConstantFunction) {
10103 v8::HandleScope scope;
10104 LocalContext context;
10105 v8::Handle<v8::Object> obj = v8::Object::New();
10106 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
10107 v8::Handle<v8::String> foo_string = v8::String::New("foo");
10108 obj->Set(foo_string, func_templ->GetFunction());
10109 v8::Handle<v8::Object> obj_clone = obj->Clone();
10110 obj_clone->Set(foo_string, v8::String::New("Hello"));
10111 CHECK(!obj->Get(foo_string)->IsUndefined());
10112}
10113
10114
10115// Regression test for http://crbug.com/16276.
10116THREADED_TEST(Regress16276) {
10117 v8::HandleScope scope;
10118 LocalContext context;
10119 // Force the IC in f to be a dictionary load IC.
10120 CompileRun("function f(obj) { return obj.x; }\n"
10121 "var obj = { x: { foo: 42 }, y: 87 };\n"
10122 "var x = obj.x;\n"
10123 "delete obj.y;\n"
10124 "for (var i = 0; i < 5; i++) f(obj);");
10125 // Detach the global object to make 'this' refer directly to the
10126 // global object (not the proxy), and make sure that the dictionary
10127 // load IC doesn't mess up loading directly from the global object.
10128 context->DetachGlobal();
10129 CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
10130}
10131
10132
10133THREADED_TEST(PixelArray) {
10134 v8::HandleScope scope;
10135 LocalContext context;
Steve Blockd0582a62009-12-15 09:54:21 +000010136 const int kElementCount = 260;
Steve Blocka7e24c12009-10-30 11:49:00 +000010137 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
10138 i::Handle<i::PixelArray> pixels = i::Factory::NewPixelArray(kElementCount,
10139 pixel_data);
10140 i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
10141 for (int i = 0; i < kElementCount; i++) {
Steve Blockd0582a62009-12-15 09:54:21 +000010142 pixels->set(i, i % 256);
Steve Blocka7e24c12009-10-30 11:49:00 +000010143 }
10144 i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
10145 for (int i = 0; i < kElementCount; i++) {
Steve Blockd0582a62009-12-15 09:54:21 +000010146 CHECK_EQ(i % 256, pixels->get(i));
10147 CHECK_EQ(i % 256, pixel_data[i]);
Steve Blocka7e24c12009-10-30 11:49:00 +000010148 }
10149
10150 v8::Handle<v8::Object> obj = v8::Object::New();
10151 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
10152 // Set the elements to be the pixels.
10153 // jsobj->set_elements(*pixels);
10154 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
John Reck59135872010-11-02 12:39:01 -070010155 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000010156 obj->Set(v8_str("field"), v8::Int32::New(1503));
10157 context->Global()->Set(v8_str("pixels"), obj);
10158 v8::Handle<v8::Value> result = CompileRun("pixels.field");
10159 CHECK_EQ(1503, result->Int32Value());
10160 result = CompileRun("pixels[1]");
10161 CHECK_EQ(1, result->Int32Value());
10162
10163 result = CompileRun("var sum = 0;"
10164 "for (var i = 0; i < 8; i++) {"
10165 " sum += pixels[i] = pixels[i] = -i;"
10166 "}"
10167 "sum;");
10168 CHECK_EQ(-28, result->Int32Value());
10169
10170 result = CompileRun("var sum = 0;"
10171 "for (var i = 0; i < 8; i++) {"
10172 " sum += pixels[i] = pixels[i] = 0;"
10173 "}"
10174 "sum;");
10175 CHECK_EQ(0, result->Int32Value());
10176
10177 result = CompileRun("var sum = 0;"
10178 "for (var i = 0; i < 8; i++) {"
10179 " sum += pixels[i] = pixels[i] = 255;"
10180 "}"
10181 "sum;");
10182 CHECK_EQ(8 * 255, result->Int32Value());
10183
10184 result = CompileRun("var sum = 0;"
10185 "for (var i = 0; i < 8; i++) {"
10186 " sum += pixels[i] = pixels[i] = 256 + i;"
10187 "}"
10188 "sum;");
10189 CHECK_EQ(2076, result->Int32Value());
10190
10191 result = CompileRun("var sum = 0;"
10192 "for (var i = 0; i < 8; i++) {"
10193 " sum += pixels[i] = pixels[i] = i;"
10194 "}"
10195 "sum;");
10196 CHECK_EQ(28, result->Int32Value());
10197
10198 result = CompileRun("var sum = 0;"
10199 "for (var i = 0; i < 8; i++) {"
10200 " sum += pixels[i];"
10201 "}"
10202 "sum;");
10203 CHECK_EQ(28, result->Int32Value());
10204
10205 i::Handle<i::Smi> value(i::Smi::FromInt(2));
10206 i::SetElement(jsobj, 1, value);
John Reck59135872010-11-02 12:39:01 -070010207 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000010208 *value.location() = i::Smi::FromInt(256);
10209 i::SetElement(jsobj, 1, value);
John Reck59135872010-11-02 12:39:01 -070010210 CHECK_EQ(255,
10211 i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000010212 *value.location() = i::Smi::FromInt(-1);
10213 i::SetElement(jsobj, 1, value);
John Reck59135872010-11-02 12:39:01 -070010214 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000010215
10216 result = CompileRun("for (var i = 0; i < 8; i++) {"
10217 " pixels[i] = (i * 65) - 109;"
10218 "}"
10219 "pixels[1] + pixels[6];");
10220 CHECK_EQ(255, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070010221 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
10222 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
10223 CHECK_EQ(21,
10224 i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
10225 CHECK_EQ(86,
10226 i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
10227 CHECK_EQ(151,
10228 i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
10229 CHECK_EQ(216,
10230 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
10231 CHECK_EQ(255,
10232 i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
10233 CHECK_EQ(255,
10234 i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000010235 result = CompileRun("var sum = 0;"
10236 "for (var i = 0; i < 8; i++) {"
10237 " sum += pixels[i];"
10238 "}"
10239 "sum;");
10240 CHECK_EQ(984, result->Int32Value());
10241
10242 result = CompileRun("for (var i = 0; i < 8; i++) {"
10243 " pixels[i] = (i * 1.1);"
10244 "}"
10245 "pixels[1] + pixels[6];");
10246 CHECK_EQ(8, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070010247 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
10248 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
10249 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
10250 CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
10251 CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
10252 CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
10253 CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
10254 CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000010255
10256 result = CompileRun("for (var i = 0; i < 8; i++) {"
10257 " pixels[7] = undefined;"
10258 "}"
10259 "pixels[7];");
10260 CHECK_EQ(0, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070010261 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000010262
10263 result = CompileRun("for (var i = 0; i < 8; i++) {"
10264 " pixels[6] = '2.3';"
10265 "}"
10266 "pixels[6];");
10267 CHECK_EQ(2, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070010268 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000010269
10270 result = CompileRun("for (var i = 0; i < 8; i++) {"
10271 " pixels[5] = NaN;"
10272 "}"
10273 "pixels[5];");
10274 CHECK_EQ(0, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070010275 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000010276
10277 result = CompileRun("for (var i = 0; i < 8; i++) {"
10278 " pixels[8] = Infinity;"
10279 "}"
10280 "pixels[8];");
10281 CHECK_EQ(255, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070010282 CHECK_EQ(255,
10283 i::Smi::cast(jsobj->GetElement(8)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000010284
10285 result = CompileRun("for (var i = 0; i < 8; i++) {"
10286 " pixels[9] = -Infinity;"
10287 "}"
10288 "pixels[9];");
10289 CHECK_EQ(0, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070010290 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000010291
10292 result = CompileRun("pixels[3] = 33;"
10293 "delete pixels[3];"
10294 "pixels[3];");
10295 CHECK_EQ(33, result->Int32Value());
10296
10297 result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
10298 "pixels[2] = 12; pixels[3] = 13;"
10299 "pixels.__defineGetter__('2',"
10300 "function() { return 120; });"
10301 "pixels[2];");
10302 CHECK_EQ(12, result->Int32Value());
10303
10304 result = CompileRun("var js_array = new Array(40);"
10305 "js_array[0] = 77;"
10306 "js_array;");
10307 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
10308
10309 result = CompileRun("pixels[1] = 23;"
10310 "pixels.__proto__ = [];"
10311 "js_array.__proto__ = pixels;"
10312 "js_array.concat(pixels);");
10313 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
10314 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
10315
10316 result = CompileRun("pixels[1] = 23;");
10317 CHECK_EQ(23, result->Int32Value());
10318
Steve Blockd0582a62009-12-15 09:54:21 +000010319 // Test for index greater than 255. Regression test for:
10320 // http://code.google.com/p/chromium/issues/detail?id=26337.
10321 result = CompileRun("pixels[256] = 255;");
10322 CHECK_EQ(255, result->Int32Value());
10323 result = CompileRun("var i = 0;"
10324 "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
10325 "i");
10326 CHECK_EQ(255, result->Int32Value());
10327
Steve Blocka7e24c12009-10-30 11:49:00 +000010328 free(pixel_data);
10329}
10330
10331
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010010332THREADED_TEST(PixelArrayInfo) {
10333 v8::HandleScope scope;
10334 LocalContext context;
10335 for (int size = 0; size < 100; size += 10) {
10336 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
10337 v8::Handle<v8::Object> obj = v8::Object::New();
10338 obj->SetIndexedPropertiesToPixelData(pixel_data, size);
10339 CHECK(obj->HasIndexedPropertiesInPixelData());
10340 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
10341 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
10342 free(pixel_data);
10343 }
10344}
10345
10346
10347static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
10348 switch (array_type) {
10349 case v8::kExternalByteArray:
10350 case v8::kExternalUnsignedByteArray:
10351 return 1;
10352 break;
10353 case v8::kExternalShortArray:
10354 case v8::kExternalUnsignedShortArray:
10355 return 2;
10356 break;
10357 case v8::kExternalIntArray:
10358 case v8::kExternalUnsignedIntArray:
10359 case v8::kExternalFloatArray:
10360 return 4;
10361 break;
10362 default:
10363 UNREACHABLE();
10364 return -1;
10365 }
10366 UNREACHABLE();
10367 return -1;
10368}
10369
10370
Steve Block3ce2e202009-11-05 08:53:23 +000010371template <class ExternalArrayClass, class ElementType>
10372static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
10373 int64_t low,
10374 int64_t high) {
10375 v8::HandleScope scope;
10376 LocalContext context;
10377 const int kElementCount = 40;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010010378 int element_size = ExternalArrayElementSize(array_type);
Steve Block3ce2e202009-11-05 08:53:23 +000010379 ElementType* array_data =
10380 static_cast<ElementType*>(malloc(kElementCount * element_size));
10381 i::Handle<ExternalArrayClass> array =
10382 i::Handle<ExternalArrayClass>::cast(
10383 i::Factory::NewExternalArray(kElementCount, array_type, array_data));
10384 i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
10385 for (int i = 0; i < kElementCount; i++) {
10386 array->set(i, static_cast<ElementType>(i));
10387 }
10388 i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
10389 for (int i = 0; i < kElementCount; i++) {
10390 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array->get(i)));
10391 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
10392 }
10393
10394 v8::Handle<v8::Object> obj = v8::Object::New();
10395 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
10396 // Set the elements to be the external array.
10397 obj->SetIndexedPropertiesToExternalArrayData(array_data,
10398 array_type,
10399 kElementCount);
John Reck59135872010-11-02 12:39:01 -070010400 CHECK_EQ(
10401 1, static_cast<int>(jsobj->GetElement(1)->ToObjectChecked()->Number()));
Steve Block3ce2e202009-11-05 08:53:23 +000010402 obj->Set(v8_str("field"), v8::Int32::New(1503));
10403 context->Global()->Set(v8_str("ext_array"), obj);
10404 v8::Handle<v8::Value> result = CompileRun("ext_array.field");
10405 CHECK_EQ(1503, result->Int32Value());
10406 result = CompileRun("ext_array[1]");
10407 CHECK_EQ(1, result->Int32Value());
10408
10409 // Check pass through of assigned smis
10410 result = CompileRun("var sum = 0;"
10411 "for (var i = 0; i < 8; i++) {"
10412 " sum += ext_array[i] = ext_array[i] = -i;"
10413 "}"
10414 "sum;");
10415 CHECK_EQ(-28, result->Int32Value());
10416
10417 // Check assigned smis
10418 result = CompileRun("for (var i = 0; i < 8; i++) {"
10419 " ext_array[i] = i;"
10420 "}"
10421 "var sum = 0;"
10422 "for (var i = 0; i < 8; i++) {"
10423 " sum += ext_array[i];"
10424 "}"
10425 "sum;");
10426 CHECK_EQ(28, result->Int32Value());
10427
10428 // Check assigned smis in reverse order
10429 result = CompileRun("for (var i = 8; --i >= 0; ) {"
10430 " ext_array[i] = i;"
10431 "}"
10432 "var sum = 0;"
10433 "for (var i = 0; i < 8; i++) {"
10434 " sum += ext_array[i];"
10435 "}"
10436 "sum;");
10437 CHECK_EQ(28, result->Int32Value());
10438
10439 // Check pass through of assigned HeapNumbers
10440 result = CompileRun("var sum = 0;"
10441 "for (var i = 0; i < 16; i+=2) {"
10442 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
10443 "}"
10444 "sum;");
10445 CHECK_EQ(-28, result->Int32Value());
10446
10447 // Check assigned HeapNumbers
10448 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
10449 " ext_array[i] = (i * 0.5);"
10450 "}"
10451 "var sum = 0;"
10452 "for (var i = 0; i < 16; i+=2) {"
10453 " sum += ext_array[i];"
10454 "}"
10455 "sum;");
10456 CHECK_EQ(28, result->Int32Value());
10457
10458 // Check assigned HeapNumbers in reverse order
10459 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
10460 " ext_array[i] = (i * 0.5);"
10461 "}"
10462 "var sum = 0;"
10463 "for (var i = 0; i < 16; i+=2) {"
10464 " sum += ext_array[i];"
10465 "}"
10466 "sum;");
10467 CHECK_EQ(28, result->Int32Value());
10468
10469 i::ScopedVector<char> test_buf(1024);
10470
10471 // Check legal boundary conditions.
10472 // The repeated loads and stores ensure the ICs are exercised.
10473 const char* boundary_program =
10474 "var res = 0;"
10475 "for (var i = 0; i < 16; i++) {"
10476 " ext_array[i] = %lld;"
10477 " if (i > 8) {"
10478 " res = ext_array[i];"
10479 " }"
10480 "}"
10481 "res;";
10482 i::OS::SNPrintF(test_buf,
10483 boundary_program,
10484 low);
10485 result = CompileRun(test_buf.start());
10486 CHECK_EQ(low, result->IntegerValue());
10487
10488 i::OS::SNPrintF(test_buf,
10489 boundary_program,
10490 high);
10491 result = CompileRun(test_buf.start());
10492 CHECK_EQ(high, result->IntegerValue());
10493
10494 // Check misprediction of type in IC.
10495 result = CompileRun("var tmp_array = ext_array;"
10496 "var sum = 0;"
10497 "for (var i = 0; i < 8; i++) {"
10498 " tmp_array[i] = i;"
10499 " sum += tmp_array[i];"
10500 " if (i == 4) {"
10501 " tmp_array = {};"
10502 " }"
10503 "}"
10504 "sum;");
10505 i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
10506 CHECK_EQ(28, result->Int32Value());
10507
10508 // Make sure out-of-range loads do not throw.
10509 i::OS::SNPrintF(test_buf,
10510 "var caught_exception = false;"
10511 "try {"
10512 " ext_array[%d];"
10513 "} catch (e) {"
10514 " caught_exception = true;"
10515 "}"
10516 "caught_exception;",
10517 kElementCount);
10518 result = CompileRun(test_buf.start());
10519 CHECK_EQ(false, result->BooleanValue());
10520
10521 // Make sure out-of-range stores do not throw.
10522 i::OS::SNPrintF(test_buf,
10523 "var caught_exception = false;"
10524 "try {"
10525 " ext_array[%d] = 1;"
10526 "} catch (e) {"
10527 " caught_exception = true;"
10528 "}"
10529 "caught_exception;",
10530 kElementCount);
10531 result = CompileRun(test_buf.start());
10532 CHECK_EQ(false, result->BooleanValue());
10533
10534 // Check other boundary conditions, values and operations.
10535 result = CompileRun("for (var i = 0; i < 8; i++) {"
10536 " ext_array[7] = undefined;"
10537 "}"
10538 "ext_array[7];");
10539 CHECK_EQ(0, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070010540 CHECK_EQ(
10541 0, static_cast<int>(jsobj->GetElement(7)->ToObjectChecked()->Number()));
Steve Block3ce2e202009-11-05 08:53:23 +000010542
10543 result = CompileRun("for (var i = 0; i < 8; i++) {"
10544 " ext_array[6] = '2.3';"
10545 "}"
10546 "ext_array[6];");
10547 CHECK_EQ(2, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070010548 CHECK_EQ(
10549 2, static_cast<int>(jsobj->GetElement(6)->ToObjectChecked()->Number()));
Steve Block3ce2e202009-11-05 08:53:23 +000010550
10551 if (array_type != v8::kExternalFloatArray) {
10552 // Though the specification doesn't state it, be explicit about
10553 // converting NaNs and +/-Infinity to zero.
10554 result = CompileRun("for (var i = 0; i < 8; i++) {"
10555 " ext_array[i] = 5;"
10556 "}"
10557 "for (var i = 0; i < 8; i++) {"
10558 " ext_array[i] = NaN;"
10559 "}"
10560 "ext_array[5];");
10561 CHECK_EQ(0, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070010562 CHECK_EQ(0,
10563 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
Steve Block3ce2e202009-11-05 08:53:23 +000010564
10565 result = CompileRun("for (var i = 0; i < 8; i++) {"
10566 " ext_array[i] = 5;"
10567 "}"
10568 "for (var i = 0; i < 8; i++) {"
10569 " ext_array[i] = Infinity;"
10570 "}"
10571 "ext_array[5];");
10572 CHECK_EQ(0, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070010573 CHECK_EQ(0,
10574 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
Steve Block3ce2e202009-11-05 08:53:23 +000010575
10576 result = CompileRun("for (var i = 0; i < 8; i++) {"
10577 " ext_array[i] = 5;"
10578 "}"
10579 "for (var i = 0; i < 8; i++) {"
10580 " ext_array[i] = -Infinity;"
10581 "}"
10582 "ext_array[5];");
10583 CHECK_EQ(0, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070010584 CHECK_EQ(0,
10585 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
Steve Block3ce2e202009-11-05 08:53:23 +000010586 }
10587
10588 result = CompileRun("ext_array[3] = 33;"
10589 "delete ext_array[3];"
10590 "ext_array[3];");
10591 CHECK_EQ(33, result->Int32Value());
10592
10593 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
10594 "ext_array[2] = 12; ext_array[3] = 13;"
10595 "ext_array.__defineGetter__('2',"
10596 "function() { return 120; });"
10597 "ext_array[2];");
10598 CHECK_EQ(12, result->Int32Value());
10599
10600 result = CompileRun("var js_array = new Array(40);"
10601 "js_array[0] = 77;"
10602 "js_array;");
10603 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
10604
10605 result = CompileRun("ext_array[1] = 23;"
10606 "ext_array.__proto__ = [];"
10607 "js_array.__proto__ = ext_array;"
10608 "js_array.concat(ext_array);");
10609 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
10610 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
10611
10612 result = CompileRun("ext_array[1] = 23;");
10613 CHECK_EQ(23, result->Int32Value());
10614
Steve Blockd0582a62009-12-15 09:54:21 +000010615 // Test more complex manipulations which cause eax to contain values
10616 // that won't be completely overwritten by loads from the arrays.
10617 // This catches bugs in the instructions used for the KeyedLoadIC
10618 // for byte and word types.
10619 {
10620 const int kXSize = 300;
10621 const int kYSize = 300;
10622 const int kLargeElementCount = kXSize * kYSize * 4;
10623 ElementType* large_array_data =
10624 static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
10625 i::Handle<ExternalArrayClass> large_array =
10626 i::Handle<ExternalArrayClass>::cast(
10627 i::Factory::NewExternalArray(kLargeElementCount,
10628 array_type,
10629 array_data));
10630 v8::Handle<v8::Object> large_obj = v8::Object::New();
10631 // Set the elements to be the external array.
10632 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
10633 array_type,
10634 kLargeElementCount);
10635 context->Global()->Set(v8_str("large_array"), large_obj);
10636 // Initialize contents of a few rows.
10637 for (int x = 0; x < 300; x++) {
10638 int row = 0;
10639 int offset = row * 300 * 4;
10640 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
10641 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
10642 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
10643 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
10644 row = 150;
10645 offset = row * 300 * 4;
10646 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
10647 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
10648 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
10649 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
10650 row = 298;
10651 offset = row * 300 * 4;
10652 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
10653 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
10654 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
10655 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
10656 }
10657 // The goal of the code below is to make "offset" large enough
10658 // that the computation of the index (which goes into eax) has
10659 // high bits set which will not be overwritten by a byte or short
10660 // load.
10661 result = CompileRun("var failed = false;"
10662 "var offset = 0;"
10663 "for (var i = 0; i < 300; i++) {"
10664 " if (large_array[4 * i] != 127 ||"
10665 " large_array[4 * i + 1] != 0 ||"
10666 " large_array[4 * i + 2] != 0 ||"
10667 " large_array[4 * i + 3] != 127) {"
10668 " failed = true;"
10669 " }"
10670 "}"
10671 "offset = 150 * 300 * 4;"
10672 "for (var i = 0; i < 300; i++) {"
10673 " if (large_array[offset + 4 * i] != 127 ||"
10674 " large_array[offset + 4 * i + 1] != 0 ||"
10675 " large_array[offset + 4 * i + 2] != 0 ||"
10676 " large_array[offset + 4 * i + 3] != 127) {"
10677 " failed = true;"
10678 " }"
10679 "}"
10680 "offset = 298 * 300 * 4;"
10681 "for (var i = 0; i < 300; i++) {"
10682 " if (large_array[offset + 4 * i] != 127 ||"
10683 " large_array[offset + 4 * i + 1] != 0 ||"
10684 " large_array[offset + 4 * i + 2] != 0 ||"
10685 " large_array[offset + 4 * i + 3] != 127) {"
10686 " failed = true;"
10687 " }"
10688 "}"
10689 "!failed;");
10690 CHECK_EQ(true, result->BooleanValue());
10691 free(large_array_data);
10692 }
10693
Steve Block3ce2e202009-11-05 08:53:23 +000010694 free(array_data);
10695}
10696
10697
10698THREADED_TEST(ExternalByteArray) {
Steve Block8defd9f2010-07-08 12:39:36 +010010699 ExternalArrayTestHelper<i::ExternalByteArray, int8_t>(
Steve Block3ce2e202009-11-05 08:53:23 +000010700 v8::kExternalByteArray,
10701 -128,
10702 127);
10703}
10704
10705
10706THREADED_TEST(ExternalUnsignedByteArray) {
Steve Block8defd9f2010-07-08 12:39:36 +010010707 ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>(
Steve Block3ce2e202009-11-05 08:53:23 +000010708 v8::kExternalUnsignedByteArray,
10709 0,
10710 255);
10711}
10712
10713
10714THREADED_TEST(ExternalShortArray) {
Steve Block8defd9f2010-07-08 12:39:36 +010010715 ExternalArrayTestHelper<i::ExternalShortArray, int16_t>(
Steve Block3ce2e202009-11-05 08:53:23 +000010716 v8::kExternalShortArray,
10717 -32768,
10718 32767);
10719}
10720
10721
10722THREADED_TEST(ExternalUnsignedShortArray) {
Steve Block8defd9f2010-07-08 12:39:36 +010010723 ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>(
Steve Block3ce2e202009-11-05 08:53:23 +000010724 v8::kExternalUnsignedShortArray,
10725 0,
10726 65535);
10727}
10728
10729
10730THREADED_TEST(ExternalIntArray) {
Steve Block8defd9f2010-07-08 12:39:36 +010010731 ExternalArrayTestHelper<i::ExternalIntArray, int32_t>(
Steve Block3ce2e202009-11-05 08:53:23 +000010732 v8::kExternalIntArray,
10733 INT_MIN, // -2147483648
10734 INT_MAX); // 2147483647
10735}
10736
10737
10738THREADED_TEST(ExternalUnsignedIntArray) {
Steve Block8defd9f2010-07-08 12:39:36 +010010739 ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>(
Steve Block3ce2e202009-11-05 08:53:23 +000010740 v8::kExternalUnsignedIntArray,
10741 0,
10742 UINT_MAX); // 4294967295
10743}
10744
10745
10746THREADED_TEST(ExternalFloatArray) {
Steve Block8defd9f2010-07-08 12:39:36 +010010747 ExternalArrayTestHelper<i::ExternalFloatArray, float>(
Steve Block3ce2e202009-11-05 08:53:23 +000010748 v8::kExternalFloatArray,
10749 -500,
10750 500);
10751}
10752
10753
10754THREADED_TEST(ExternalArrays) {
10755 TestExternalByteArray();
10756 TestExternalUnsignedByteArray();
10757 TestExternalShortArray();
10758 TestExternalUnsignedShortArray();
10759 TestExternalIntArray();
10760 TestExternalUnsignedIntArray();
10761 TestExternalFloatArray();
10762}
10763
10764
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010010765void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
10766 v8::HandleScope scope;
10767 LocalContext context;
10768 for (int size = 0; size < 100; size += 10) {
10769 int element_size = ExternalArrayElementSize(array_type);
10770 void* external_data = malloc(size * element_size);
10771 v8::Handle<v8::Object> obj = v8::Object::New();
10772 obj->SetIndexedPropertiesToExternalArrayData(
10773 external_data, array_type, size);
10774 CHECK(obj->HasIndexedPropertiesInExternalArrayData());
10775 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
10776 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
10777 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
10778 free(external_data);
10779 }
10780}
10781
10782
10783THREADED_TEST(ExternalArrayInfo) {
10784 ExternalArrayInfoTestHelper(v8::kExternalByteArray);
10785 ExternalArrayInfoTestHelper(v8::kExternalUnsignedByteArray);
10786 ExternalArrayInfoTestHelper(v8::kExternalShortArray);
10787 ExternalArrayInfoTestHelper(v8::kExternalUnsignedShortArray);
10788 ExternalArrayInfoTestHelper(v8::kExternalIntArray);
10789 ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray);
10790 ExternalArrayInfoTestHelper(v8::kExternalFloatArray);
10791}
10792
10793
Steve Blocka7e24c12009-10-30 11:49:00 +000010794THREADED_TEST(ScriptContextDependence) {
10795 v8::HandleScope scope;
10796 LocalContext c1;
10797 const char *source = "foo";
10798 v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
10799 v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
10800 c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
10801 CHECK_EQ(dep->Run()->Int32Value(), 100);
10802 CHECK_EQ(indep->Run()->Int32Value(), 100);
10803 LocalContext c2;
10804 c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
10805 CHECK_EQ(dep->Run()->Int32Value(), 100);
10806 CHECK_EQ(indep->Run()->Int32Value(), 101);
10807}
10808
10809
10810THREADED_TEST(StackTrace) {
10811 v8::HandleScope scope;
10812 LocalContext context;
10813 v8::TryCatch try_catch;
10814 const char *source = "function foo() { FAIL.FAIL; }; foo();";
10815 v8::Handle<v8::String> src = v8::String::New(source);
10816 v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
10817 v8::Script::New(src, origin)->Run();
10818 CHECK(try_catch.HasCaught());
10819 v8::String::Utf8Value stack(try_catch.StackTrace());
10820 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
10821}
10822
10823
Kristian Monsen25f61362010-05-21 11:50:48 +010010824// Checks that a StackFrame has certain expected values.
10825void checkStackFrame(const char* expected_script_name,
10826 const char* expected_func_name, int expected_line_number,
10827 int expected_column, bool is_eval, bool is_constructor,
10828 v8::Handle<v8::StackFrame> frame) {
10829 v8::HandleScope scope;
10830 v8::String::Utf8Value func_name(frame->GetFunctionName());
10831 v8::String::Utf8Value script_name(frame->GetScriptName());
10832 if (*script_name == NULL) {
10833 // The situation where there is no associated script, like for evals.
10834 CHECK(expected_script_name == NULL);
10835 } else {
10836 CHECK(strstr(*script_name, expected_script_name) != NULL);
10837 }
10838 CHECK(strstr(*func_name, expected_func_name) != NULL);
10839 CHECK_EQ(expected_line_number, frame->GetLineNumber());
10840 CHECK_EQ(expected_column, frame->GetColumn());
10841 CHECK_EQ(is_eval, frame->IsEval());
10842 CHECK_EQ(is_constructor, frame->IsConstructor());
10843}
10844
10845
10846v8::Handle<Value> AnalyzeStackInNativeCode(const v8::Arguments& args) {
10847 v8::HandleScope scope;
10848 const char* origin = "capture-stack-trace-test";
10849 const int kOverviewTest = 1;
10850 const int kDetailedTest = 2;
10851
10852 ASSERT(args.Length() == 1);
10853
10854 int testGroup = args[0]->Int32Value();
10855 if (testGroup == kOverviewTest) {
10856 v8::Handle<v8::StackTrace> stackTrace =
10857 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
10858 CHECK_EQ(4, stackTrace->GetFrameCount());
10859 checkStackFrame(origin, "bar", 2, 10, false, false,
10860 stackTrace->GetFrame(0));
10861 checkStackFrame(origin, "foo", 6, 3, false, false,
10862 stackTrace->GetFrame(1));
10863 checkStackFrame(NULL, "", 1, 1, false, false,
10864 stackTrace->GetFrame(2));
10865 // The last frame is an anonymous function that has the initial call.
10866 checkStackFrame(origin, "", 8, 7, false, false,
10867 stackTrace->GetFrame(3));
10868
10869 CHECK(stackTrace->AsArray()->IsArray());
10870 } else if (testGroup == kDetailedTest) {
10871 v8::Handle<v8::StackTrace> stackTrace =
10872 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
10873 CHECK_EQ(4, stackTrace->GetFrameCount());
10874 checkStackFrame(origin, "bat", 4, 22, false, false,
10875 stackTrace->GetFrame(0));
10876 checkStackFrame(origin, "baz", 8, 3, false, true,
10877 stackTrace->GetFrame(1));
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010010878#ifdef ENABLE_DEBUGGER_SUPPORT
10879 bool is_eval = true;
10880#else // ENABLE_DEBUGGER_SUPPORT
10881 bool is_eval = false;
10882#endif // ENABLE_DEBUGGER_SUPPORT
10883
10884 checkStackFrame(NULL, "", 1, 1, is_eval, false,
Kristian Monsen25f61362010-05-21 11:50:48 +010010885 stackTrace->GetFrame(2));
10886 // The last frame is an anonymous function that has the initial call to foo.
10887 checkStackFrame(origin, "", 10, 1, false, false,
10888 stackTrace->GetFrame(3));
10889
10890 CHECK(stackTrace->AsArray()->IsArray());
10891 }
10892 return v8::Undefined();
10893}
10894
10895
10896// Tests the C++ StackTrace API.
Ben Murdochb0fe1622011-05-05 13:52:32 +010010897// TODO(3074796): Reenable this as a THREADED_TEST once it passes.
10898// THREADED_TEST(CaptureStackTrace) {
10899TEST(CaptureStackTrace) {
Kristian Monsen25f61362010-05-21 11:50:48 +010010900 v8::HandleScope scope;
10901 v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
10902 Local<ObjectTemplate> templ = ObjectTemplate::New();
10903 templ->Set(v8_str("AnalyzeStackInNativeCode"),
10904 v8::FunctionTemplate::New(AnalyzeStackInNativeCode));
10905 LocalContext context(0, templ);
10906
10907 // Test getting OVERVIEW information. Should ignore information that is not
10908 // script name, function name, line number, and column offset.
10909 const char *overview_source =
10910 "function bar() {\n"
10911 " var y; AnalyzeStackInNativeCode(1);\n"
10912 "}\n"
10913 "function foo() {\n"
10914 "\n"
10915 " bar();\n"
10916 "}\n"
10917 "var x;eval('new foo();');";
10918 v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
10919 v8::Handle<Value> overview_result =
10920 v8::Script::New(overview_src, origin)->Run();
10921 ASSERT(!overview_result.IsEmpty());
10922 ASSERT(overview_result->IsObject());
10923
10924 // Test getting DETAILED information.
10925 const char *detailed_source =
10926 "function bat() {AnalyzeStackInNativeCode(2);\n"
10927 "}\n"
10928 "\n"
10929 "function baz() {\n"
10930 " bat();\n"
10931 "}\n"
10932 "eval('new baz();');";
10933 v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
10934 // Make the script using a non-zero line and column offset.
10935 v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
10936 v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
10937 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
10938 v8::Handle<v8::Script> detailed_script(
10939 v8::Script::New(detailed_src, &detailed_origin));
10940 v8::Handle<Value> detailed_result = detailed_script->Run();
10941 ASSERT(!detailed_result.IsEmpty());
10942 ASSERT(detailed_result->IsObject());
10943}
10944
10945
Ben Murdoch3bec4d22010-07-22 14:51:16 +010010946static void StackTraceForUncaughtExceptionListener(
10947 v8::Handle<v8::Message> message,
10948 v8::Handle<Value>) {
10949 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
10950 CHECK_EQ(2, stack_trace->GetFrameCount());
10951 checkStackFrame("origin", "foo", 2, 3, false, false,
10952 stack_trace->GetFrame(0));
10953 checkStackFrame("origin", "bar", 5, 3, false, false,
10954 stack_trace->GetFrame(1));
10955}
10956
10957TEST(CaptureStackTraceForUncaughtException) {
10958 report_count = 0;
10959 v8::HandleScope scope;
10960 LocalContext env;
10961 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
10962 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
10963
10964 Script::Compile(v8_str("function foo() {\n"
10965 " throw 1;\n"
10966 "};\n"
10967 "function bar() {\n"
10968 " foo();\n"
10969 "};"),
10970 v8_str("origin"))->Run();
10971 v8::Local<v8::Object> global = env->Global();
10972 Local<Value> trouble = global->Get(v8_str("bar"));
10973 CHECK(trouble->IsFunction());
10974 Function::Cast(*trouble)->Call(global, 0, NULL);
10975 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
10976 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
10977}
10978
10979
Ben Murdochf87a2032010-10-22 12:50:53 +010010980v8::Handle<Value> AnalyzeStackOfEvalWithSourceURL(const v8::Arguments& args) {
10981 v8::HandleScope scope;
10982 v8::Handle<v8::StackTrace> stackTrace =
10983 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
10984 CHECK_EQ(5, stackTrace->GetFrameCount());
10985 v8::Handle<v8::String> url = v8_str("eval_url");
10986 for (int i = 0; i < 3; i++) {
10987 v8::Handle<v8::String> name =
10988 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
10989 CHECK(!name.IsEmpty());
10990 CHECK_EQ(url, name);
10991 }
10992 return v8::Undefined();
10993}
10994
10995
10996TEST(SourceURLInStackTrace) {
10997 v8::HandleScope scope;
10998 Local<ObjectTemplate> templ = ObjectTemplate::New();
10999 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
11000 v8::FunctionTemplate::New(AnalyzeStackOfEvalWithSourceURL));
11001 LocalContext context(0, templ);
11002
11003 const char *source =
11004 "function outer() {\n"
11005 "function bar() {\n"
11006 " AnalyzeStackOfEvalWithSourceURL();\n"
11007 "}\n"
11008 "function foo() {\n"
11009 "\n"
11010 " bar();\n"
11011 "}\n"
11012 "foo();\n"
11013 "}\n"
11014 "eval('(' + outer +')()//@ sourceURL=eval_url');";
11015 CHECK(CompileRun(source)->IsUndefined());
11016}
11017
11018
Steve Block3ce2e202009-11-05 08:53:23 +000011019// Test that idle notification can be handled and eventually returns true.
Steve Blocka7e24c12009-10-30 11:49:00 +000011020THREADED_TEST(IdleNotification) {
Steve Block3ce2e202009-11-05 08:53:23 +000011021 bool rv = false;
11022 for (int i = 0; i < 100; i++) {
11023 rv = v8::V8::IdleNotification();
11024 if (rv)
11025 break;
11026 }
11027 CHECK(rv == true);
Steve Blocka7e24c12009-10-30 11:49:00 +000011028}
11029
11030
11031static uint32_t* stack_limit;
11032
11033static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -080011034 stack_limit = reinterpret_cast<uint32_t*>(i::StackGuard::real_climit());
Steve Blocka7e24c12009-10-30 11:49:00 +000011035 return v8::Undefined();
11036}
11037
11038
11039// Uses the address of a local variable to determine the stack top now.
11040// Given a size, returns an address that is that far from the current
11041// top of stack.
11042static uint32_t* ComputeStackLimit(uint32_t size) {
11043 uint32_t* answer = &size - (size / sizeof(size));
11044 // If the size is very large and the stack is very near the bottom of
11045 // memory then the calculation above may wrap around and give an address
11046 // that is above the (downwards-growing) stack. In that case we return
11047 // a very low address.
11048 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
11049 return answer;
11050}
11051
11052
11053TEST(SetResourceConstraints) {
11054 static const int K = 1024;
11055 uint32_t* set_limit = ComputeStackLimit(128 * K);
11056
11057 // Set stack limit.
11058 v8::ResourceConstraints constraints;
11059 constraints.set_stack_limit(set_limit);
11060 CHECK(v8::SetResourceConstraints(&constraints));
11061
11062 // Execute a script.
11063 v8::HandleScope scope;
11064 LocalContext env;
11065 Local<v8::FunctionTemplate> fun_templ =
11066 v8::FunctionTemplate::New(GetStackLimitCallback);
11067 Local<Function> fun = fun_templ->GetFunction();
11068 env->Global()->Set(v8_str("get_stack_limit"), fun);
11069 CompileRun("get_stack_limit();");
11070
11071 CHECK(stack_limit == set_limit);
11072}
11073
11074
11075TEST(SetResourceConstraintsInThread) {
11076 uint32_t* set_limit;
11077 {
11078 v8::Locker locker;
11079 static const int K = 1024;
11080 set_limit = ComputeStackLimit(128 * K);
11081
11082 // Set stack limit.
11083 v8::ResourceConstraints constraints;
11084 constraints.set_stack_limit(set_limit);
11085 CHECK(v8::SetResourceConstraints(&constraints));
11086
11087 // Execute a script.
11088 v8::HandleScope scope;
11089 LocalContext env;
11090 Local<v8::FunctionTemplate> fun_templ =
11091 v8::FunctionTemplate::New(GetStackLimitCallback);
11092 Local<Function> fun = fun_templ->GetFunction();
11093 env->Global()->Set(v8_str("get_stack_limit"), fun);
11094 CompileRun("get_stack_limit();");
11095
11096 CHECK(stack_limit == set_limit);
11097 }
11098 {
11099 v8::Locker locker;
11100 CHECK(stack_limit == set_limit);
11101 }
11102}
Steve Block3ce2e202009-11-05 08:53:23 +000011103
11104
11105THREADED_TEST(GetHeapStatistics) {
11106 v8::HandleScope scope;
11107 LocalContext c1;
11108 v8::HeapStatistics heap_statistics;
Steve Blockd0582a62009-12-15 09:54:21 +000011109 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
11110 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
Steve Block3ce2e202009-11-05 08:53:23 +000011111 v8::V8::GetHeapStatistics(&heap_statistics);
Steve Blockd0582a62009-12-15 09:54:21 +000011112 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
11113 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
11114}
11115
11116
11117static double DoubleFromBits(uint64_t value) {
11118 double target;
11119#ifdef BIG_ENDIAN_FLOATING_POINT
11120 const int kIntSize = 4;
11121 // Somebody swapped the lower and higher half of doubles.
11122 memcpy(&target, reinterpret_cast<char*>(&value) + kIntSize, kIntSize);
11123 memcpy(reinterpret_cast<char*>(&target) + kIntSize, &value, kIntSize);
11124#else
11125 memcpy(&target, &value, sizeof(target));
11126#endif
11127 return target;
11128}
11129
11130
11131static uint64_t DoubleToBits(double value) {
11132 uint64_t target;
11133#ifdef BIG_ENDIAN_FLOATING_POINT
11134 const int kIntSize = 4;
11135 // Somebody swapped the lower and higher half of doubles.
11136 memcpy(&target, reinterpret_cast<char*>(&value) + kIntSize, kIntSize);
11137 memcpy(reinterpret_cast<char*>(&target) + kIntSize, &value, kIntSize);
11138#else
11139 memcpy(&target, &value, sizeof(target));
11140#endif
11141 return target;
11142}
11143
11144
11145static double DoubleToDateTime(double input) {
11146 double date_limit = 864e13;
11147 if (IsNaN(input) || input < -date_limit || input > date_limit) {
11148 return i::OS::nan_value();
11149 }
11150 return (input < 0) ? -(floor(-input)) : floor(input);
11151}
11152
11153// We don't have a consistent way to write 64-bit constants syntactically, so we
11154// split them into two 32-bit constants and combine them programmatically.
11155static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
11156 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
11157}
11158
11159
11160THREADED_TEST(QuietSignalingNaNs) {
11161 v8::HandleScope scope;
11162 LocalContext context;
11163 v8::TryCatch try_catch;
11164
11165 // Special double values.
11166 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
11167 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
11168 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
11169 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
11170 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
11171 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
11172 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
11173
11174 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
11175 // on either side of the epoch.
11176 double date_limit = 864e13;
11177
11178 double test_values[] = {
11179 snan,
11180 qnan,
11181 infinity,
11182 max_normal,
11183 date_limit + 1,
11184 date_limit,
11185 min_normal,
11186 max_denormal,
11187 min_denormal,
11188 0,
11189 -0,
11190 -min_denormal,
11191 -max_denormal,
11192 -min_normal,
11193 -date_limit,
11194 -date_limit - 1,
11195 -max_normal,
11196 -infinity,
11197 -qnan,
11198 -snan
11199 };
11200 int num_test_values = 20;
11201
11202 for (int i = 0; i < num_test_values; i++) {
11203 double test_value = test_values[i];
11204
11205 // Check that Number::New preserves non-NaNs and quiets SNaNs.
11206 v8::Handle<v8::Value> number = v8::Number::New(test_value);
11207 double stored_number = number->NumberValue();
11208 if (!IsNaN(test_value)) {
11209 CHECK_EQ(test_value, stored_number);
11210 } else {
11211 uint64_t stored_bits = DoubleToBits(stored_number);
11212 // Check if quiet nan (bits 51..62 all set).
11213 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
11214 }
11215
11216 // Check that Date::New preserves non-NaNs in the date range and
11217 // quiets SNaNs.
11218 v8::Handle<v8::Value> date = v8::Date::New(test_value);
11219 double expected_stored_date = DoubleToDateTime(test_value);
11220 double stored_date = date->NumberValue();
11221 if (!IsNaN(expected_stored_date)) {
11222 CHECK_EQ(expected_stored_date, stored_date);
11223 } else {
11224 uint64_t stored_bits = DoubleToBits(stored_date);
11225 // Check if quiet nan (bits 51..62 all set).
11226 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
11227 }
11228 }
11229}
11230
11231
11232static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
11233 v8::HandleScope scope;
11234 v8::TryCatch tc;
11235 v8::Handle<v8::String> str = args[0]->ToString();
11236 if (tc.HasCaught())
11237 return tc.ReThrow();
11238 return v8::Undefined();
11239}
11240
11241
11242// Test that an exception can be propagated down through a spaghetti
11243// stack using ReThrow.
11244THREADED_TEST(SpaghettiStackReThrow) {
11245 v8::HandleScope scope;
11246 LocalContext context;
11247 context->Global()->Set(
11248 v8::String::New("s"),
11249 v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
11250 v8::TryCatch try_catch;
11251 CompileRun(
11252 "var i = 0;"
11253 "var o = {"
11254 " toString: function () {"
11255 " if (i == 10) {"
11256 " throw 'Hey!';"
11257 " } else {"
11258 " i++;"
11259 " return s(o);"
11260 " }"
11261 " }"
11262 "};"
11263 "s(o);");
11264 CHECK(try_catch.HasCaught());
11265 v8::String::Utf8Value value(try_catch.Exception());
11266 CHECK_EQ(0, strcmp(*value, "Hey!"));
11267}
11268
11269
Steve Blockd0582a62009-12-15 09:54:21 +000011270TEST(Regress528) {
11271 v8::V8::Initialize();
11272
11273 v8::HandleScope scope;
11274 v8::Persistent<Context> context;
11275 v8::Persistent<Context> other_context;
11276 int gc_count;
11277
11278 // Create a context used to keep the code from aging in the compilation
11279 // cache.
11280 other_context = Context::New();
11281
11282 // Context-dependent context data creates reference from the compilation
11283 // cache to the global object.
11284 const char* source_simple = "1";
11285 context = Context::New();
11286 {
11287 v8::HandleScope scope;
11288
11289 context->Enter();
11290 Local<v8::String> obj = v8::String::New("");
11291 context->SetData(obj);
11292 CompileRun(source_simple);
11293 context->Exit();
11294 }
11295 context.Dispose();
11296 for (gc_count = 1; gc_count < 10; gc_count++) {
11297 other_context->Enter();
11298 CompileRun(source_simple);
11299 other_context->Exit();
Steve Block8defd9f2010-07-08 12:39:36 +010011300 i::Heap::CollectAllGarbage(false);
Steve Blockd0582a62009-12-15 09:54:21 +000011301 if (GetGlobalObjectsCount() == 1) break;
11302 }
11303 CHECK_GE(2, gc_count);
11304 CHECK_EQ(1, GetGlobalObjectsCount());
11305
11306 // Eval in a function creates reference from the compilation cache to the
11307 // global object.
11308 const char* source_eval = "function f(){eval('1')}; f()";
11309 context = Context::New();
11310 {
11311 v8::HandleScope scope;
11312
11313 context->Enter();
11314 CompileRun(source_eval);
11315 context->Exit();
11316 }
11317 context.Dispose();
11318 for (gc_count = 1; gc_count < 10; gc_count++) {
11319 other_context->Enter();
11320 CompileRun(source_eval);
11321 other_context->Exit();
Steve Block8defd9f2010-07-08 12:39:36 +010011322 i::Heap::CollectAllGarbage(false);
Steve Blockd0582a62009-12-15 09:54:21 +000011323 if (GetGlobalObjectsCount() == 1) break;
11324 }
11325 CHECK_GE(2, gc_count);
11326 CHECK_EQ(1, GetGlobalObjectsCount());
11327
11328 // Looking up the line number for an exception creates reference from the
11329 // compilation cache to the global object.
11330 const char* source_exception = "function f(){throw 1;} f()";
11331 context = Context::New();
11332 {
11333 v8::HandleScope scope;
11334
11335 context->Enter();
11336 v8::TryCatch try_catch;
11337 CompileRun(source_exception);
11338 CHECK(try_catch.HasCaught());
11339 v8::Handle<v8::Message> message = try_catch.Message();
11340 CHECK(!message.IsEmpty());
11341 CHECK_EQ(1, message->GetLineNumber());
11342 context->Exit();
11343 }
11344 context.Dispose();
11345 for (gc_count = 1; gc_count < 10; gc_count++) {
11346 other_context->Enter();
11347 CompileRun(source_exception);
11348 other_context->Exit();
Steve Block8defd9f2010-07-08 12:39:36 +010011349 i::Heap::CollectAllGarbage(false);
Steve Blockd0582a62009-12-15 09:54:21 +000011350 if (GetGlobalObjectsCount() == 1) break;
11351 }
11352 CHECK_GE(2, gc_count);
11353 CHECK_EQ(1, GetGlobalObjectsCount());
11354
11355 other_context.Dispose();
Steve Block3ce2e202009-11-05 08:53:23 +000011356}
Andrei Popescu402d9372010-02-26 13:31:12 +000011357
11358
11359THREADED_TEST(ScriptOrigin) {
11360 v8::HandleScope scope;
11361 LocalContext env;
11362 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
11363 v8::Handle<v8::String> script = v8::String::New(
11364 "function f() {}\n\nfunction g() {}");
11365 v8::Script::Compile(script, &origin)->Run();
11366 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
11367 env->Global()->Get(v8::String::New("f")));
11368 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
11369 env->Global()->Get(v8::String::New("g")));
11370
11371 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
11372 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
11373 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
11374
11375 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
11376 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
11377 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
11378}
11379
11380
11381THREADED_TEST(ScriptLineNumber) {
11382 v8::HandleScope scope;
11383 LocalContext env;
11384 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
11385 v8::Handle<v8::String> script = v8::String::New(
11386 "function f() {}\n\nfunction g() {}");
11387 v8::Script::Compile(script, &origin)->Run();
11388 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
11389 env->Global()->Get(v8::String::New("f")));
11390 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
11391 env->Global()->Get(v8::String::New("g")));
11392 CHECK_EQ(0, f->GetScriptLineNumber());
11393 CHECK_EQ(2, g->GetScriptLineNumber());
11394}
11395
11396
11397static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
11398 const AccessorInfo& info) {
11399 return v8_num(42);
11400}
11401
11402
11403static void SetterWhichSetsYOnThisTo23(Local<String> name,
11404 Local<Value> value,
11405 const AccessorInfo& info) {
11406 info.This()->Set(v8_str("y"), v8_num(23));
11407}
11408
11409
Steve Block6ded16b2010-05-10 14:33:55 +010011410TEST(SetterOnConstructorPrototype) {
Andrei Popescu402d9372010-02-26 13:31:12 +000011411 v8::HandleScope scope;
11412 Local<ObjectTemplate> templ = ObjectTemplate::New();
11413 templ->SetAccessor(v8_str("x"),
11414 GetterWhichReturns42,
11415 SetterWhichSetsYOnThisTo23);
11416 LocalContext context;
11417 context->Global()->Set(v8_str("P"), templ->NewInstance());
11418 CompileRun("function C1() {"
11419 " this.x = 23;"
11420 "};"
11421 "C1.prototype = P;"
11422 "function C2() {"
11423 " this.x = 23"
11424 "};"
11425 "C2.prototype = { };"
11426 "C2.prototype.__proto__ = P;");
11427
11428 v8::Local<v8::Script> script;
11429 script = v8::Script::Compile(v8_str("new C1();"));
11430 for (int i = 0; i < 10; i++) {
11431 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
11432 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
11433 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
11434 }
11435
11436 script = v8::Script::Compile(v8_str("new C2();"));
11437 for (int i = 0; i < 10; i++) {
11438 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
11439 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
11440 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
11441 }
11442}
11443
11444
11445static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
11446 Local<String> name, const AccessorInfo& info) {
11447 return v8_num(42);
11448}
11449
11450
11451static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
11452 Local<String> name, Local<Value> value, const AccessorInfo& info) {
11453 if (name->Equals(v8_str("x"))) {
11454 info.This()->Set(v8_str("y"), v8_num(23));
11455 }
11456 return v8::Handle<Value>();
11457}
11458
11459
11460THREADED_TEST(InterceptorOnConstructorPrototype) {
11461 v8::HandleScope scope;
11462 Local<ObjectTemplate> templ = ObjectTemplate::New();
11463 templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
11464 NamedPropertySetterWhichSetsYOnThisTo23);
11465 LocalContext context;
11466 context->Global()->Set(v8_str("P"), templ->NewInstance());
11467 CompileRun("function C1() {"
11468 " this.x = 23;"
11469 "};"
11470 "C1.prototype = P;"
11471 "function C2() {"
11472 " this.x = 23"
11473 "};"
11474 "C2.prototype = { };"
11475 "C2.prototype.__proto__ = P;");
11476
11477 v8::Local<v8::Script> script;
11478 script = v8::Script::Compile(v8_str("new C1();"));
11479 for (int i = 0; i < 10; i++) {
11480 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
11481 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
11482 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
11483 }
11484
11485 script = v8::Script::Compile(v8_str("new C2();"));
11486 for (int i = 0; i < 10; i++) {
11487 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
11488 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
11489 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
11490 }
11491}
Steve Block6ded16b2010-05-10 14:33:55 +010011492
11493
11494TEST(Bug618) {
11495 const char* source = "function C1() {"
11496 " this.x = 23;"
11497 "};"
11498 "C1.prototype = P;";
11499
11500 v8::HandleScope scope;
11501 LocalContext context;
11502 v8::Local<v8::Script> script;
11503
11504 // Use a simple object as prototype.
11505 v8::Local<v8::Object> prototype = v8::Object::New();
11506 prototype->Set(v8_str("y"), v8_num(42));
11507 context->Global()->Set(v8_str("P"), prototype);
11508
11509 // This compile will add the code to the compilation cache.
11510 CompileRun(source);
11511
11512 script = v8::Script::Compile(v8_str("new C1();"));
Kristian Monsen0d5e1162010-09-30 15:31:59 +010011513 // Allow enough iterations for the inobject slack tracking logic
11514 // to finalize instance size and install the fast construct stub.
11515 for (int i = 0; i < 256; i++) {
Steve Block6ded16b2010-05-10 14:33:55 +010011516 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
11517 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
11518 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
11519 }
11520
11521 // Use an API object with accessors as prototype.
11522 Local<ObjectTemplate> templ = ObjectTemplate::New();
11523 templ->SetAccessor(v8_str("x"),
11524 GetterWhichReturns42,
11525 SetterWhichSetsYOnThisTo23);
11526 context->Global()->Set(v8_str("P"), templ->NewInstance());
11527
11528 // This compile will get the code from the compilation cache.
11529 CompileRun(source);
11530
11531 script = v8::Script::Compile(v8_str("new C1();"));
11532 for (int i = 0; i < 10; i++) {
11533 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
11534 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
11535 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
11536 }
11537}
11538
11539int prologue_call_count = 0;
11540int epilogue_call_count = 0;
11541int prologue_call_count_second = 0;
11542int epilogue_call_count_second = 0;
11543
11544void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
11545 ++prologue_call_count;
11546}
11547
11548void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
11549 ++epilogue_call_count;
11550}
11551
11552void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
11553 ++prologue_call_count_second;
11554}
11555
11556void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
11557 ++epilogue_call_count_second;
11558}
11559
11560TEST(GCCallbacks) {
11561 LocalContext context;
11562
11563 v8::V8::AddGCPrologueCallback(PrologueCallback);
11564 v8::V8::AddGCEpilogueCallback(EpilogueCallback);
11565 CHECK_EQ(0, prologue_call_count);
11566 CHECK_EQ(0, epilogue_call_count);
11567 i::Heap::CollectAllGarbage(false);
11568 CHECK_EQ(1, prologue_call_count);
11569 CHECK_EQ(1, epilogue_call_count);
11570 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
11571 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
11572 i::Heap::CollectAllGarbage(false);
11573 CHECK_EQ(2, prologue_call_count);
11574 CHECK_EQ(2, epilogue_call_count);
11575 CHECK_EQ(1, prologue_call_count_second);
11576 CHECK_EQ(1, epilogue_call_count_second);
11577 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
11578 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
11579 i::Heap::CollectAllGarbage(false);
11580 CHECK_EQ(2, prologue_call_count);
11581 CHECK_EQ(2, epilogue_call_count);
11582 CHECK_EQ(2, prologue_call_count_second);
11583 CHECK_EQ(2, epilogue_call_count_second);
11584 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
11585 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
11586 i::Heap::CollectAllGarbage(false);
11587 CHECK_EQ(2, prologue_call_count);
11588 CHECK_EQ(2, epilogue_call_count);
11589 CHECK_EQ(2, prologue_call_count_second);
11590 CHECK_EQ(2, epilogue_call_count_second);
11591}
Kristian Monsen25f61362010-05-21 11:50:48 +010011592
11593
11594THREADED_TEST(AddToJSFunctionResultCache) {
11595 i::FLAG_allow_natives_syntax = true;
11596 v8::HandleScope scope;
11597
11598 LocalContext context;
11599
11600 const char* code =
11601 "(function() {"
11602 " var key0 = 'a';"
11603 " var key1 = 'b';"
11604 " var r0 = %_GetFromCache(0, key0);"
11605 " var r1 = %_GetFromCache(0, key1);"
11606 " var r0_ = %_GetFromCache(0, key0);"
11607 " if (r0 !== r0_)"
11608 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
11609 " var r1_ = %_GetFromCache(0, key1);"
11610 " if (r1 !== r1_)"
11611 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
11612 " return 'PASSED';"
11613 "})()";
Steve Block8defd9f2010-07-08 12:39:36 +010011614 i::Heap::ClearJSFunctionResultCaches();
Kristian Monsen25f61362010-05-21 11:50:48 +010011615 ExpectString(code, "PASSED");
11616}
11617
11618
11619static const int k0CacheSize = 16;
11620
11621THREADED_TEST(FillJSFunctionResultCache) {
11622 i::FLAG_allow_natives_syntax = true;
11623 v8::HandleScope scope;
11624
11625 LocalContext context;
11626
11627 const char* code =
11628 "(function() {"
11629 " var k = 'a';"
11630 " var r = %_GetFromCache(0, k);"
11631 " for (var i = 0; i < 16; i++) {"
11632 " %_GetFromCache(0, 'a' + i);"
11633 " };"
11634 " if (r === %_GetFromCache(0, k))"
11635 " return 'FAILED: k0CacheSize is too small';"
11636 " return 'PASSED';"
11637 "})()";
Steve Block8defd9f2010-07-08 12:39:36 +010011638 i::Heap::ClearJSFunctionResultCaches();
Kristian Monsen25f61362010-05-21 11:50:48 +010011639 ExpectString(code, "PASSED");
11640}
11641
11642
11643THREADED_TEST(RoundRobinGetFromCache) {
11644 i::FLAG_allow_natives_syntax = true;
11645 v8::HandleScope scope;
11646
11647 LocalContext context;
11648
11649 const char* code =
11650 "(function() {"
11651 " var keys = [];"
11652 " for (var i = 0; i < 16; i++) keys.push(i);"
11653 " var values = [];"
11654 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
11655 " for (var i = 0; i < 16; i++) {"
11656 " var v = %_GetFromCache(0, keys[i]);"
11657 " if (v !== values[i])"
11658 " return 'Wrong value for ' + "
11659 " keys[i] + ': ' + v + ' vs. ' + values[i];"
11660 " };"
11661 " return 'PASSED';"
11662 "})()";
Steve Block8defd9f2010-07-08 12:39:36 +010011663 i::Heap::ClearJSFunctionResultCaches();
Kristian Monsen25f61362010-05-21 11:50:48 +010011664 ExpectString(code, "PASSED");
11665}
11666
11667
11668THREADED_TEST(ReverseGetFromCache) {
11669 i::FLAG_allow_natives_syntax = true;
11670 v8::HandleScope scope;
11671
11672 LocalContext context;
11673
11674 const char* code =
11675 "(function() {"
11676 " var keys = [];"
11677 " for (var i = 0; i < 16; i++) keys.push(i);"
11678 " var values = [];"
11679 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
11680 " for (var i = 15; i >= 16; i--) {"
11681 " var v = %_GetFromCache(0, keys[i]);"
11682 " if (v !== values[i])"
11683 " return 'Wrong value for ' + "
11684 " keys[i] + ': ' + v + ' vs. ' + values[i];"
11685 " };"
11686 " return 'PASSED';"
11687 "})()";
Steve Block8defd9f2010-07-08 12:39:36 +010011688 i::Heap::ClearJSFunctionResultCaches();
Kristian Monsen25f61362010-05-21 11:50:48 +010011689 ExpectString(code, "PASSED");
11690}
11691
11692
11693THREADED_TEST(TestEviction) {
11694 i::FLAG_allow_natives_syntax = true;
11695 v8::HandleScope scope;
11696
11697 LocalContext context;
11698
11699 const char* code =
11700 "(function() {"
11701 " for (var i = 0; i < 2*16; i++) {"
11702 " %_GetFromCache(0, 'a' + i);"
11703 " };"
11704 " return 'PASSED';"
11705 "})()";
Steve Block8defd9f2010-07-08 12:39:36 +010011706 i::Heap::ClearJSFunctionResultCaches();
Kristian Monsen25f61362010-05-21 11:50:48 +010011707 ExpectString(code, "PASSED");
11708}
Steve Block8defd9f2010-07-08 12:39:36 +010011709
11710
11711THREADED_TEST(TwoByteStringInAsciiCons) {
11712 // See Chromium issue 47824.
11713 v8::HandleScope scope;
11714
11715 LocalContext context;
11716 const char* init_code =
11717 "var str1 = 'abelspendabel';"
11718 "var str2 = str1 + str1 + str1;"
11719 "str2;";
11720 Local<Value> result = CompileRun(init_code);
11721
11722 CHECK(result->IsString());
11723 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
11724 int length = string->length();
11725 CHECK(string->IsAsciiRepresentation());
11726
11727 FlattenString(string);
11728 i::Handle<i::String> flat_string = FlattenGetString(string);
11729
11730 CHECK(string->IsAsciiRepresentation());
11731 CHECK(flat_string->IsAsciiRepresentation());
11732
11733 // Create external resource.
11734 uint16_t* uc16_buffer = new uint16_t[length + 1];
11735
11736 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
11737 uc16_buffer[length] = 0;
11738
11739 TestResource resource(uc16_buffer);
11740
11741 flat_string->MakeExternal(&resource);
11742
11743 CHECK(flat_string->IsTwoByteRepresentation());
11744
11745 // At this point, we should have a Cons string which is flat and ASCII,
11746 // with a first half that is a two-byte string (although it only contains
11747 // ASCII characters). This is a valid sequence of steps, and it can happen
11748 // in real pages.
11749
11750 CHECK(string->IsAsciiRepresentation());
11751 i::ConsString* cons = i::ConsString::cast(*string);
11752 CHECK_EQ(0, cons->second()->length());
11753 CHECK(cons->first()->IsTwoByteRepresentation());
11754
11755 // Check that some string operations work.
11756
11757 // Atom RegExp.
11758 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
11759 CHECK_EQ(6, reresult->Int32Value());
11760
11761 // Nonatom RegExp.
11762 reresult = CompileRun("str2.match(/abe./g).length;");
11763 CHECK_EQ(6, reresult->Int32Value());
11764
11765 reresult = CompileRun("str2.search(/bel/g);");
11766 CHECK_EQ(1, reresult->Int32Value());
11767
11768 reresult = CompileRun("str2.search(/be./g);");
11769 CHECK_EQ(1, reresult->Int32Value());
11770
11771 ExpectTrue("/bel/g.test(str2);");
11772
11773 ExpectTrue("/be./g.test(str2);");
11774
11775 reresult = CompileRun("/bel/g.exec(str2);");
11776 CHECK(!reresult->IsNull());
11777
11778 reresult = CompileRun("/be./g.exec(str2);");
11779 CHECK(!reresult->IsNull());
11780
11781 ExpectString("str2.substring(2, 10);", "elspenda");
11782
11783 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
11784
11785 ExpectString("str2.charAt(2);", "e");
11786
11787 reresult = CompileRun("str2.charCodeAt(2);");
11788 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
11789}
Iain Merrick75681382010-08-19 15:07:18 +010011790
11791
11792// Failed access check callback that performs a GC on each invocation.
11793void FailedAccessCheckCallbackGC(Local<v8::Object> target,
11794 v8::AccessType type,
11795 Local<v8::Value> data) {
11796 i::Heap::CollectAllGarbage(true);
11797}
11798
11799
11800TEST(GCInFailedAccessCheckCallback) {
11801 // Install a failed access check callback that performs a GC on each
11802 // invocation. Then force the callback to be called from va
11803
11804 v8::V8::Initialize();
11805 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
11806
11807 v8::HandleScope scope;
11808
11809 // Create an ObjectTemplate for global objects and install access
11810 // check callbacks that will block access.
11811 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
11812 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
11813 IndexedGetAccessBlocker,
11814 v8::Handle<v8::Value>(),
11815 false);
11816
11817 // Create a context and set an x property on it's global object.
11818 LocalContext context0(NULL, global_template);
11819 context0->Global()->Set(v8_str("x"), v8_num(42));
11820 v8::Handle<v8::Object> global0 = context0->Global();
11821
11822 // Create a context with a different security token so that the
11823 // failed access check callback will be called on each access.
11824 LocalContext context1(NULL, global_template);
11825 context1->Global()->Set(v8_str("other"), global0);
11826
11827 // Get property with failed access check.
11828 ExpectUndefined("other.x");
11829
11830 // Get element with failed access check.
11831 ExpectUndefined("other[0]");
11832
11833 // Set property with failed access check.
11834 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
11835 CHECK(result->IsObject());
11836
11837 // Set element with failed access check.
11838 result = CompileRun("other[0] = new Object()");
11839 CHECK(result->IsObject());
11840
11841 // Get property attribute with failed access check.
11842 ExpectFalse("\'x\' in other");
11843
11844 // Get property attribute for element with failed access check.
11845 ExpectFalse("0 in other");
11846
11847 // Delete property.
11848 ExpectFalse("delete other.x");
11849
11850 // Delete element.
11851 CHECK_EQ(false, global0->Delete(0));
11852
11853 // DefineAccessor.
11854 CHECK_EQ(false,
11855 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
11856
11857 // Define JavaScript accessor.
11858 ExpectUndefined("Object.prototype.__defineGetter__.call("
11859 " other, \'x\', function() { return 42; })");
11860
11861 // LookupAccessor.
11862 ExpectUndefined("Object.prototype.__lookupGetter__.call("
11863 " other, \'x\')");
11864
11865 // HasLocalElement.
11866 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
11867
11868 CHECK_EQ(false, global0->HasRealIndexedProperty(0));
11869 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
11870 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
11871
11872 // Reset the failed access check callback so it does not influence
11873 // the other tests.
11874 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
11875}
Kristian Monsen0d5e1162010-09-30 15:31:59 +010011876
11877
11878TEST(StringCheckMultipleContexts) {
11879 const char* code =
11880 "(function() { return \"a\".charAt(0); })()";
11881
11882 {
11883 // Run the code twice in the first context to initialize the call IC.
11884 v8::HandleScope scope;
11885 LocalContext context1;
11886 ExpectString(code, "a");
11887 ExpectString(code, "a");
11888 }
11889
11890 {
11891 // Change the String.prototype in the second context and check
11892 // that the right function gets called.
11893 v8::HandleScope scope;
11894 LocalContext context2;
11895 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
11896 ExpectString(code, "not a");
11897 }
11898}
11899
11900
11901TEST(NumberCheckMultipleContexts) {
11902 const char* code =
11903 "(function() { return (42).toString(); })()";
11904
11905 {
11906 // Run the code twice in the first context to initialize the call IC.
11907 v8::HandleScope scope;
11908 LocalContext context1;
11909 ExpectString(code, "42");
11910 ExpectString(code, "42");
11911 }
11912
11913 {
11914 // Change the Number.prototype in the second context and check
11915 // that the right function gets called.
11916 v8::HandleScope scope;
11917 LocalContext context2;
11918 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
11919 ExpectString(code, "not 42");
11920 }
11921}
11922
11923
11924TEST(BooleanCheckMultipleContexts) {
11925 const char* code =
11926 "(function() { return true.toString(); })()";
11927
11928 {
11929 // Run the code twice in the first context to initialize the call IC.
11930 v8::HandleScope scope;
11931 LocalContext context1;
11932 ExpectString(code, "true");
11933 ExpectString(code, "true");
11934 }
11935
11936 {
11937 // Change the Boolean.prototype in the second context and check
11938 // that the right function gets called.
11939 v8::HandleScope scope;
11940 LocalContext context2;
11941 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
11942 ExpectString(code, "");
11943 }
11944}
Ben Murdochf87a2032010-10-22 12:50:53 +010011945
11946
11947TEST(DontDeleteCellLoadIC) {
11948 const char* function_code =
11949 "function readCell() { while (true) { return cell; } }";
11950
11951 {
11952 // Run the code twice in the first context to initialize the load
11953 // IC for a don't delete cell.
11954 v8::HandleScope scope;
11955 LocalContext context1;
11956 CompileRun("var cell = \"first\";");
11957 ExpectBoolean("delete cell", false);
11958 CompileRun(function_code);
11959 ExpectString("readCell()", "first");
11960 ExpectString("readCell()", "first");
11961 }
11962
11963 {
11964 // Use a deletable cell in the second context.
11965 v8::HandleScope scope;
11966 LocalContext context2;
11967 CompileRun("cell = \"second\";");
11968 CompileRun(function_code);
11969 ExpectString("readCell()", "second");
11970 ExpectBoolean("delete cell", true);
11971 ExpectString("(function() {"
11972 " try {"
11973 " return readCell();"
11974 " } catch(e) {"
11975 " return e.toString();"
11976 " }"
11977 "})()",
11978 "ReferenceError: cell is not defined");
11979 CompileRun("cell = \"new_second\";");
11980 i::Heap::CollectAllGarbage(true);
11981 ExpectString("readCell()", "new_second");
11982 ExpectString("readCell()", "new_second");
11983 }
11984}
11985
11986
11987TEST(DontDeleteCellLoadICForceDelete) {
11988 const char* function_code =
11989 "function readCell() { while (true) { return cell; } }";
11990
11991 // Run the code twice to initialize the load IC for a don't delete
11992 // cell.
11993 v8::HandleScope scope;
11994 LocalContext context;
11995 CompileRun("var cell = \"value\";");
11996 ExpectBoolean("delete cell", false);
11997 CompileRun(function_code);
11998 ExpectString("readCell()", "value");
11999 ExpectString("readCell()", "value");
12000
12001 // Delete the cell using the API and check the inlined code works
12002 // correctly.
12003 CHECK(context->Global()->ForceDelete(v8_str("cell")));
12004 ExpectString("(function() {"
12005 " try {"
12006 " return readCell();"
12007 " } catch(e) {"
12008 " return e.toString();"
12009 " }"
12010 "})()",
12011 "ReferenceError: cell is not defined");
12012}
12013
12014
12015TEST(DontDeleteCellLoadICAPI) {
12016 const char* function_code =
12017 "function readCell() { while (true) { return cell; } }";
12018
12019 // Run the code twice to initialize the load IC for a don't delete
12020 // cell created using the API.
12021 v8::HandleScope scope;
12022 LocalContext context;
12023 context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
12024 ExpectBoolean("delete cell", false);
12025 CompileRun(function_code);
12026 ExpectString("readCell()", "value");
12027 ExpectString("readCell()", "value");
12028
12029 // Delete the cell using the API and check the inlined code works
12030 // correctly.
12031 CHECK(context->Global()->ForceDelete(v8_str("cell")));
12032 ExpectString("(function() {"
12033 " try {"
12034 " return readCell();"
12035 " } catch(e) {"
12036 " return e.toString();"
12037 " }"
12038 "})()",
12039 "ReferenceError: cell is not defined");
12040}
12041
12042
12043TEST(GlobalLoadICGC) {
12044 const char* function_code =
12045 "function readCell() { while (true) { return cell; } }";
12046
12047 // Check inline load code for a don't delete cell is cleared during
12048 // GC.
12049 {
12050 v8::HandleScope scope;
12051 LocalContext context;
12052 CompileRun("var cell = \"value\";");
12053 ExpectBoolean("delete cell", false);
12054 CompileRun(function_code);
12055 ExpectString("readCell()", "value");
12056 ExpectString("readCell()", "value");
12057 }
12058 {
12059 v8::HandleScope scope;
12060 LocalContext context2;
12061 // Hold the code object in the second context.
12062 CompileRun(function_code);
12063 CheckSurvivingGlobalObjectsCount(1);
12064 }
12065
12066 // Check inline load code for a deletable cell is cleared during GC.
12067 {
12068 v8::HandleScope scope;
12069 LocalContext context;
12070 CompileRun("cell = \"value\";");
12071 CompileRun(function_code);
12072 ExpectString("readCell()", "value");
12073 ExpectString("readCell()", "value");
12074 }
12075 {
12076 v8::HandleScope scope;
12077 LocalContext context2;
12078 // Hold the code object in the second context.
12079 CompileRun(function_code);
12080 CheckSurvivingGlobalObjectsCount(1);
12081 }
12082}
12083
12084
12085TEST(RegExp) {
12086 v8::HandleScope scope;
12087 LocalContext context;
12088
12089 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
12090 CHECK(re->IsRegExp());
12091 CHECK(re->GetSource()->Equals(v8_str("foo")));
12092 CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
12093
12094 re = v8::RegExp::New(v8_str("bar"),
12095 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
12096 v8::RegExp::kGlobal));
12097 CHECK(re->IsRegExp());
12098 CHECK(re->GetSource()->Equals(v8_str("bar")));
12099 CHECK_EQ(static_cast<int>(re->GetFlags()),
12100 v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal);
12101
12102 re = v8::RegExp::New(v8_str("baz"),
12103 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
12104 v8::RegExp::kMultiline));
12105 CHECK(re->IsRegExp());
12106 CHECK(re->GetSource()->Equals(v8_str("baz")));
12107 CHECK_EQ(static_cast<int>(re->GetFlags()),
12108 v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline);
12109
12110 re = CompileRun("/quux/").As<v8::RegExp>();
12111 CHECK(re->IsRegExp());
12112 CHECK(re->GetSource()->Equals(v8_str("quux")));
12113 CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
12114
12115 re = CompileRun("/quux/gm").As<v8::RegExp>();
12116 CHECK(re->IsRegExp());
12117 CHECK(re->GetSource()->Equals(v8_str("quux")));
12118 CHECK_EQ(static_cast<int>(re->GetFlags()),
12119 v8::RegExp::kGlobal | v8::RegExp::kMultiline);
12120
12121 // Override the RegExp constructor and check the API constructor
12122 // still works.
12123 CompileRun("RegExp = function() {}");
12124
12125 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
12126 CHECK(re->IsRegExp());
12127 CHECK(re->GetSource()->Equals(v8_str("foobar")));
12128 CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
12129
12130 re = v8::RegExp::New(v8_str("foobarbaz"),
12131 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
12132 v8::RegExp::kMultiline));
12133 CHECK(re->IsRegExp());
12134 CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
12135 CHECK_EQ(static_cast<int>(re->GetFlags()),
12136 v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline);
12137
12138 context->Global()->Set(v8_str("re"), re);
12139 ExpectTrue("re.test('FoobarbaZ')");
12140
12141 v8::TryCatch try_catch;
12142 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
12143 CHECK(re.IsEmpty());
12144 CHECK(try_catch.HasCaught());
12145 context->Global()->Set(v8_str("ex"), try_catch.Exception());
12146 ExpectTrue("ex instanceof SyntaxError");
12147}
12148
12149
12150static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
12151 const v8::AccessorInfo& info ) {
12152 return v8_str("42!");
12153}
12154
12155
12156static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo& info) {
12157 v8::Handle<v8::Array> result = v8::Array::New();
12158 result->Set(0, v8_str("universalAnswer"));
12159 return result;
12160}
12161
12162
12163TEST(NamedEnumeratorAndForIn) {
12164 v8::HandleScope handle_scope;
12165 LocalContext context;
12166 v8::Context::Scope context_scope(context.local());
12167
12168 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New();
12169 tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
12170 context->Global()->Set(v8_str("o"), tmpl->NewInstance());
12171 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
12172 "var result = []; for (var k in o) result.push(k); result"));
12173 CHECK_EQ(1, result->Length());
12174 CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
12175}