blob: b3c52f1f1ff8289d26c4c451111aa12d080f473d [file] [log] [blame]
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001// Copyright 2007-2009 the V8 project authors. All rights reserved.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
ager@chromium.org3811b432009-10-28 14:53:37 +000028#include <limits.h>
29
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000030#include "v8.h"
31
32#include "api.h"
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +000033#include "compilation-cache.h"
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000034#include "execution.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000035#include "snapshot.h"
36#include "platform.h"
37#include "top.h"
ager@chromium.org3811b432009-10-28 14:53:37 +000038#include "utils.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000039#include "cctest.h"
ager@chromium.org5b2fbee2010-09-08 06:38:15 +000040#include "parser.h"
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +000041#include "unicode-inl.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000042
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000043static const bool kLogThreading = true;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000044
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +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
lrn@chromium.org32d961d2010-06-30 09:09:34 +000063namespace i = ::i;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000064
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000065
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +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
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000081static void ExpectTrue(const char* code) {
82 ExpectBoolean(code, true);
83}
84
85
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000086static void ExpectFalse(const char* code) {
87 ExpectBoolean(code, false);
88}
89
90
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +000091static void ExpectObject(const char* code, Local<Value> expected) {
92 Local<Value> result = CompileRun(code);
93 CHECK(result->Equals(expected));
94}
95
96
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000097static void ExpectUndefined(const char* code) {
98 Local<Value> result = CompileRun(code);
99 CHECK(result->IsUndefined());
100}
101
102
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +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
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +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) == '';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000209 CHECK(value1->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000210
211 v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000212 CHECK(value2->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000213
214 v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000215 CHECK(value3->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000216
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]'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000237 CHECK(value4->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000238
239 v8::Handle<Value> value5 = CompileRun(
240 "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000241 CHECK(value5->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000242
243 v8::Handle<Value> value6 = CompileRun(
244 "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000245 CHECK(value6->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000246
247 v8::Handle<Value> value7 = CompileRun(
248 "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
249 "'[object Cons1],[object Cons2],[object Cons3],d';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000250 CHECK(value7->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000251
252 v8::Handle<Value> value8 = CompileRun(
253 "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000254 CHECK(value8->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000255}
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
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000285THREADED_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
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +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) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000315 int array_length = i::StrLength(source) + 1;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000316 uint16_t* converted = i::NewArray<uint16_t>(array_length);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000317 for (int i = 0; i < array_length; i++) converted[i] = source[i];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +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
ager@chromium.org5ec48922009-05-05 07:25:34 +0000356 explicit TestAsciiResource(const char* data)
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000357 : 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:
ager@chromium.org5ec48922009-05-05 07:25:34 +0000373 const char* data_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000374 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()));
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000397 i::Heap::CollectAllGarbage(false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000398 CHECK_EQ(0, TestResource::dispose_count);
399 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000400 i::CompilationCache::Clear();
401 i::Heap::CollectAllGarbage(false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +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());
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000418 i::Heap::CollectAllGarbage(false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000419 CHECK_EQ(0, TestAsciiResource::dispose_count);
420 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000421 i::CompilationCache::Clear();
422 i::Heap::CollectAllGarbage(false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000423 CHECK_EQ(1, TestAsciiResource::dispose_count);
424}
425
426
ager@chromium.org6f10e412009-02-13 10:11:16 +0000427THREADED_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);
ager@chromium.org5c838252010-02-19 08:53:10 +0000434 // Trigger GCs so that the newly allocated string moves to old gen.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000435 i::Heap::CollectGarbage(i::NEW_SPACE); // in survivor space now
436 i::Heap::CollectGarbage(i::NEW_SPACE); // in old gen now
ager@chromium.org6f10e412009-02-13 10:11:16 +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());
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000443 i::Heap::CollectAllGarbage(false);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000444 CHECK_EQ(0, TestResource::dispose_count);
445 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000446 i::CompilationCache::Clear();
447 i::Heap::CollectAllGarbage(false);
ager@chromium.org6f10e412009-02-13 10:11:16 +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);
ager@chromium.org5c838252010-02-19 08:53:10 +0000459 // Trigger GCs so that the newly allocated string moves to old gen.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000460 i::Heap::CollectGarbage(i::NEW_SPACE); // in survivor space now
461 i::Heap::CollectGarbage(i::NEW_SPACE); // in old gen now
ager@chromium.org6f10e412009-02-13 10:11:16 +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());
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000469 i::Heap::CollectAllGarbage(false);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000470 CHECK_EQ(0, TestAsciiResource::dispose_count);
471 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000472 i::CompilationCache::Clear();
473 i::Heap::CollectAllGarbage(false);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000474 CHECK_EQ(1, TestAsciiResource::dispose_count);
475}
476
477
ager@chromium.org5c838252010-02-19 08:53:10 +0000478TEST(MakingExternalStringConditions) {
479 v8::HandleScope scope;
480 LocalContext env;
481
482 // Free some space in the new space so that we can check freshness.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000483 i::Heap::CollectGarbage(i::NEW_SPACE);
484 i::Heap::CollectGarbage(i::NEW_SPACE);
ager@chromium.org5c838252010-02-19 08:53:10 +0000485
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000486 uint16_t* two_byte_string = AsciiToTwoByteString("small");
487 Local<String> small_string = String::New(two_byte_string);
488 i::DeleteArray(two_byte_string);
489
ager@chromium.org5c838252010-02-19 08:53:10 +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.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000493 i::Heap::CollectGarbage(i::NEW_SPACE); // in survivor space now
494 i::Heap::CollectGarbage(i::NEW_SPACE); // in old gen now
ager@chromium.org5c838252010-02-19 08:53:10 +0000495 // Old space strings should be accepted.
496 CHECK(small_string->CanMakeExternal());
497
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000498 two_byte_string = AsciiToTwoByteString("small 2");
499 small_string = String::New(two_byte_string);
500 i::DeleteArray(two_byte_string);
501
ager@chromium.org5c838252010-02-19 08:53:10 +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';
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000514
515 two_byte_string = AsciiToTwoByteString(buf);
516 Local<String> large_string = String::New(two_byte_string);
ager@chromium.org5c838252010-02-19 08:53:10 +0000517 i::DeleteArray(buf);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000518 i::DeleteArray(two_byte_string);
ager@chromium.org5c838252010-02-19 08:53:10 +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.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000529 i::Heap::CollectGarbage(i::NEW_SPACE);
530 i::Heap::CollectGarbage(i::NEW_SPACE);
ager@chromium.org5c838252010-02-19 08:53:10 +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.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000536 i::Heap::CollectGarbage(i::NEW_SPACE); // in survivor space now
537 i::Heap::CollectGarbage(i::NEW_SPACE); // in old gen now
ager@chromium.org5c838252010-02-19 08:53:10 +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
ager@chromium.org6f10e412009-02-13 10:11:16 +0000561THREADED_TEST(UsingExternalString) {
ager@chromium.orge2902be2009-06-08 12:21:35 +0000562 {
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.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000569 i::Heap::CollectGarbage(i::NEW_SPACE); // in survivor space now
570 i::Heap::CollectGarbage(i::NEW_SPACE); // in old gen now
ager@chromium.orge2902be2009-06-08 12:21:35 +0000571 i::Handle<i::String> isymbol = i::Factory::SymbolFromString(istring);
572 CHECK(isymbol->IsSymbol());
573 }
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000574 i::Heap::CollectAllGarbage(false);
575 i::Heap::CollectAllGarbage(false);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000576}
577
578
579THREADED_TEST(UsingExternalAsciiString) {
ager@chromium.orge2902be2009-06-08 12:21:35 +0000580 {
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.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000587 i::Heap::CollectGarbage(i::NEW_SPACE); // in survivor space now
588 i::Heap::CollectGarbage(i::NEW_SPACE); // in old gen now
ager@chromium.orge2902be2009-06-08 12:21:35 +0000589 i::Handle<i::String> isymbol = i::Factory::SymbolFromString(istring);
590 CHECK(isymbol->IsSymbol());
591 }
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000592 i::Heap::CollectAllGarbage(false);
593 i::Heap::CollectAllGarbage(false);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000594}
595
596
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000597THREADED_TEST(ScavengeExternalString) {
598 TestResource::dispose_count = 0;
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000599 bool in_new_space = false;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +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);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000606 i::Heap::CollectGarbage(i::NEW_SPACE);
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000607 in_new_space = i::Heap::InNewSpace(*istring);
608 CHECK(in_new_space || i::Heap::old_data_space()->Contains(*istring));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000609 CHECK_EQ(0, TestResource::dispose_count);
610 }
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000611 i::Heap::CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000612 CHECK_EQ(1, TestResource::dispose_count);
613}
614
615
616THREADED_TEST(ScavengeExternalAsciiString) {
617 TestAsciiResource::dispose_count = 0;
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000618 bool in_new_space = false;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +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);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000625 i::Heap::CollectGarbage(i::NEW_SPACE);
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000626 in_new_space = i::Heap::InNewSpace(*istring);
627 CHECK(in_new_space || i::Heap::old_data_space()->Contains(*istring));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000628 CHECK_EQ(0, TestAsciiResource::dispose_count);
629 }
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000630 i::Heap::CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000631 CHECK_EQ(1, TestAsciiResource::dispose_count);
632}
633
634
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000635class 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};
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000650
651
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000652int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000653
654
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000655TEST(ExternalStringWithDisposeHandling) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000656 const char* c_source = "1 + 2 * 3";
657
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000658 // Use a stack allocated external string resource allocated object.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000659 TestAsciiResource::dispose_count = 0;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000660 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
661 TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000662 {
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());
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000670 i::Heap::CollectAllGarbage(false);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000671 CHECK_EQ(0, TestAsciiResource::dispose_count);
672 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000673 i::CompilationCache::Clear();
674 i::Heap::CollectAllGarbage(false);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000675 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000676 CHECK_EQ(0, TestAsciiResource::dispose_count);
677
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000678 // Use a heap allocated external string resource allocated object.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000679 TestAsciiResource::dispose_count = 0;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000680 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
681 TestAsciiResource* res_heap =
682 new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000683 {
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());
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000691 i::Heap::CollectAllGarbage(false);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000692 CHECK_EQ(0, TestAsciiResource::dispose_count);
693 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000694 i::CompilationCache::Clear();
695 i::Heap::CollectAllGarbage(false);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000696 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000697 CHECK_EQ(1, TestAsciiResource::dispose_count);
698}
699
700
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +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);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000713
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
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +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);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000727
728 two_byte_source = AsciiToTwoByteString(two_byte_string_2);
729 right = String::New(two_byte_source);
730 i::DeleteArray(two_byte_source);
731
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +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 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000741 i::CompilationCache::Clear();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000742 i::Heap::CollectAllGarbage(false);
743 i::Heap::CollectAllGarbage(false);
744}
745
746
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +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
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000770static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
771 ApiTestFuzzer::Fuzz();
772 return v8_num(239);
773}
774
775
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +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"));
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000802 fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), Return239);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +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);
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000810
811 result = v8_compile("(new obj()).m")->Run();
812 CHECK_EQ(239, result->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000813 }
814}
815
816
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000817static 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)
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000877 // Check a value with a leading 1 bit in x64 Smi encoding.
878 expected_ptr = reinterpret_cast<void*>(0x400000000);
879 TestExternalPointerWrapping();
880
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000881 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
882 TestExternalPointerWrapping();
883
884 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
885 TestExternalPointerWrapping();
886#endif
887}
888
889
sgjesse@chromium.org900d3b72009-08-07 11:24:25 +0000890THREADED_TEST(FindInstanceInPrototypeChain) {
891 v8::HandleScope scope;
892 LocalContext env;
893
894 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
895 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
896 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
897 derived->Inherit(base);
898
899 Local<v8::Function> base_function = base->GetFunction();
900 Local<v8::Function> derived_function = derived->GetFunction();
901 Local<v8::Function> other_function = other->GetFunction();
902
903 Local<v8::Object> base_instance = base_function->NewInstance();
904 Local<v8::Object> derived_instance = derived_function->NewInstance();
905 Local<v8::Object> derived_instance2 = derived_function->NewInstance();
906 Local<v8::Object> other_instance = other_function->NewInstance();
907 derived_instance2->Set(v8_str("__proto__"), derived_instance);
908 other_instance->Set(v8_str("__proto__"), derived_instance2);
909
910 // base_instance is only an instance of base.
911 CHECK_EQ(base_instance,
912 base_instance->FindInstanceInPrototypeChain(base));
913 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
914 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
915
916 // derived_instance is an instance of base and derived.
917 CHECK_EQ(derived_instance,
918 derived_instance->FindInstanceInPrototypeChain(base));
919 CHECK_EQ(derived_instance,
920 derived_instance->FindInstanceInPrototypeChain(derived));
921 CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
922
923 // other_instance is an instance of other and its immediate
924 // prototype derived_instance2 is an instance of base and derived.
925 // Note, derived_instance is an instance of base and derived too,
926 // but it comes after derived_instance2 in the prototype chain of
927 // other_instance.
928 CHECK_EQ(derived_instance2,
929 other_instance->FindInstanceInPrototypeChain(base));
930 CHECK_EQ(derived_instance2,
931 other_instance->FindInstanceInPrototypeChain(derived));
932 CHECK_EQ(other_instance,
933 other_instance->FindInstanceInPrototypeChain(other));
934}
935
936
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000937THREADED_TEST(TinyInteger) {
938 v8::HandleScope scope;
939 LocalContext env;
940 int32_t value = 239;
941 Local<v8::Integer> value_obj = v8::Integer::New(value);
942 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
943}
944
945
946THREADED_TEST(BigSmiInteger) {
947 v8::HandleScope scope;
948 LocalContext env;
949 int32_t value = i::Smi::kMaxValue;
950 // We cannot add one to a Smi::kMaxValue without wrapping.
951 if (i::kSmiValueSize < 32) {
952 CHECK(i::Smi::IsValid(value));
953 CHECK(!i::Smi::IsValid(value + 1));
954 Local<v8::Integer> value_obj = v8::Integer::New(value);
955 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
956 }
957}
958
959
960THREADED_TEST(BigInteger) {
961 v8::HandleScope scope;
962 LocalContext env;
963 // We cannot add one to a Smi::kMaxValue without wrapping.
964 if (i::kSmiValueSize < 32) {
965 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
966 // The code will not be run in that case, due to the "if" guard.
967 int32_t value =
968 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
969 CHECK(value > i::Smi::kMaxValue);
970 CHECK(!i::Smi::IsValid(value));
971 Local<v8::Integer> value_obj = v8::Integer::New(value);
972 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
973 }
974}
975
976
977THREADED_TEST(TinyUnsignedInteger) {
978 v8::HandleScope scope;
979 LocalContext env;
980 uint32_t value = 239;
981 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
982 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
983}
984
985
986THREADED_TEST(BigUnsignedSmiInteger) {
987 v8::HandleScope scope;
988 LocalContext env;
989 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
990 CHECK(i::Smi::IsValid(value));
991 CHECK(!i::Smi::IsValid(value + 1));
992 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
993 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
994}
995
996
997THREADED_TEST(BigUnsignedInteger) {
998 v8::HandleScope scope;
999 LocalContext env;
1000 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1001 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1002 CHECK(!i::Smi::IsValid(value));
1003 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1004 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1005}
1006
1007
1008THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1009 v8::HandleScope scope;
1010 LocalContext env;
1011 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1012 uint32_t value = INT32_MAX_AS_UINT + 1;
1013 CHECK(value > INT32_MAX_AS_UINT); // No overflow.
1014 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1015 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1016}
1017
1018
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001019THREADED_TEST(Number) {
1020 v8::HandleScope scope;
1021 LocalContext env;
1022 double PI = 3.1415926;
1023 Local<v8::Number> pi_obj = v8::Number::New(PI);
1024 CHECK_EQ(PI, pi_obj->NumberValue());
1025}
1026
1027
1028THREADED_TEST(ToNumber) {
1029 v8::HandleScope scope;
1030 LocalContext env;
1031 Local<String> str = v8_str("3.1415926");
1032 CHECK_EQ(3.1415926, str->NumberValue());
1033 v8::Handle<v8::Boolean> t = v8::True();
1034 CHECK_EQ(1.0, t->NumberValue());
1035 v8::Handle<v8::Boolean> f = v8::False();
1036 CHECK_EQ(0.0, f->NumberValue());
1037}
1038
1039
1040THREADED_TEST(Date) {
1041 v8::HandleScope scope;
1042 LocalContext env;
1043 double PI = 3.1415926;
1044 Local<Value> date_obj = v8::Date::New(PI);
1045 CHECK_EQ(3.0, date_obj->NumberValue());
1046}
1047
1048
1049THREADED_TEST(Boolean) {
1050 v8::HandleScope scope;
1051 LocalContext env;
1052 v8::Handle<v8::Boolean> t = v8::True();
1053 CHECK(t->Value());
1054 v8::Handle<v8::Boolean> f = v8::False();
1055 CHECK(!f->Value());
1056 v8::Handle<v8::Primitive> u = v8::Undefined();
1057 CHECK(!u->BooleanValue());
1058 v8::Handle<v8::Primitive> n = v8::Null();
1059 CHECK(!n->BooleanValue());
1060 v8::Handle<String> str1 = v8_str("");
1061 CHECK(!str1->BooleanValue());
1062 v8::Handle<String> str2 = v8_str("x");
1063 CHECK(str2->BooleanValue());
1064 CHECK(!v8::Number::New(0)->BooleanValue());
1065 CHECK(v8::Number::New(-1)->BooleanValue());
1066 CHECK(v8::Number::New(1)->BooleanValue());
1067 CHECK(v8::Number::New(42)->BooleanValue());
1068 CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1069}
1070
1071
1072static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
1073 ApiTestFuzzer::Fuzz();
1074 return v8_num(13.4);
1075}
1076
1077
1078static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
1079 ApiTestFuzzer::Fuzz();
1080 return v8_num(876);
1081}
1082
1083
1084THREADED_TEST(GlobalPrototype) {
1085 v8::HandleScope scope;
1086 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
1087 func_templ->PrototypeTemplate()->Set(
1088 "dummy",
1089 v8::FunctionTemplate::New(DummyCallHandler));
1090 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1091 templ->Set("x", v8_num(200));
1092 templ->SetAccessor(v8_str("m"), GetM);
1093 LocalContext env(0, templ);
1094 v8::Handle<v8::Object> obj = env->Global();
1095 v8::Handle<Script> script = v8_compile("dummy()");
1096 v8::Handle<Value> result = script->Run();
1097 CHECK_EQ(13.4, result->NumberValue());
1098 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1099 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1100}
1101
1102
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001103THREADED_TEST(ObjectTemplate) {
1104 v8::HandleScope scope;
1105 Local<ObjectTemplate> templ1 = ObjectTemplate::New();
1106 templ1->Set("x", v8_num(10));
1107 templ1->Set("y", v8_num(13));
1108 LocalContext env;
1109 Local<v8::Object> instance1 = templ1->NewInstance();
1110 env->Global()->Set(v8_str("p"), instance1);
1111 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1112 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1113 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
1114 fun->PrototypeTemplate()->Set("nirk", v8_num(123));
1115 Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1116 templ2->Set("a", v8_num(12));
1117 templ2->Set("b", templ1);
1118 Local<v8::Object> instance2 = templ2->NewInstance();
1119 env->Global()->Set(v8_str("q"), instance2);
1120 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1121 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1122 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1123 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1124}
1125
1126
1127static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
1128 ApiTestFuzzer::Fuzz();
1129 return v8_num(17.2);
1130}
1131
1132
1133static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
1134 ApiTestFuzzer::Fuzz();
1135 return v8_num(15.2);
1136}
1137
1138
1139THREADED_TEST(DescriptorInheritance) {
1140 v8::HandleScope scope;
1141 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
1142 super->PrototypeTemplate()->Set("flabby",
1143 v8::FunctionTemplate::New(GetFlabby));
1144 super->PrototypeTemplate()->Set("PI", v8_num(3.14));
1145
1146 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1147
1148 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
1149 base1->Inherit(super);
1150 base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
1151
1152 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
1153 base2->Inherit(super);
1154 base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
1155
1156 LocalContext env;
1157
1158 env->Global()->Set(v8_str("s"), super->GetFunction());
1159 env->Global()->Set(v8_str("base1"), base1->GetFunction());
1160 env->Global()->Set(v8_str("base2"), base2->GetFunction());
1161
1162 // Checks right __proto__ chain.
1163 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1164 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1165
1166 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1167
1168 // Instance accessor should not be visible on function object or its prototype
1169 CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1170 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1171 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1172
1173 env->Global()->Set(v8_str("obj"),
1174 base1->GetFunction()->NewInstance());
1175 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1176 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1177 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1178 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1179 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1180
1181 env->Global()->Set(v8_str("obj2"),
1182 base2->GetFunction()->NewInstance());
1183 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1184 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1185 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1186 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1187 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1188
1189 // base1 and base2 cannot cross reference to each's prototype
1190 CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1191 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1192}
1193
1194
1195int echo_named_call_count;
1196
1197
1198static v8::Handle<Value> EchoNamedProperty(Local<String> name,
1199 const AccessorInfo& info) {
1200 ApiTestFuzzer::Fuzz();
1201 CHECK_EQ(v8_str("data"), info.Data());
1202 echo_named_call_count++;
1203 return name;
1204}
1205
1206
1207THREADED_TEST(NamedPropertyHandlerGetter) {
1208 echo_named_call_count = 0;
1209 v8::HandleScope scope;
1210 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1211 templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
1212 0, 0, 0, 0,
1213 v8_str("data"));
1214 LocalContext env;
1215 env->Global()->Set(v8_str("obj"),
1216 templ->GetFunction()->NewInstance());
1217 CHECK_EQ(echo_named_call_count, 0);
1218 v8_compile("obj.x")->Run();
1219 CHECK_EQ(echo_named_call_count, 1);
1220 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
1221 v8::Handle<Value> str = CompileRun(code);
1222 String::AsciiValue value(str);
1223 CHECK_EQ(*value, "oddlepoddle");
1224 // Check default behavior
1225 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
1226 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
1227 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
1228}
1229
1230
1231int echo_indexed_call_count = 0;
1232
1233
1234static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
1235 const AccessorInfo& info) {
1236 ApiTestFuzzer::Fuzz();
1237 CHECK_EQ(v8_num(637), info.Data());
1238 echo_indexed_call_count++;
1239 return v8_num(index);
1240}
1241
1242
1243THREADED_TEST(IndexedPropertyHandlerGetter) {
1244 v8::HandleScope scope;
1245 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1246 templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
1247 0, 0, 0, 0,
1248 v8_num(637));
1249 LocalContext env;
1250 env->Global()->Set(v8_str("obj"),
1251 templ->GetFunction()->NewInstance());
1252 Local<Script> script = v8_compile("obj[900]");
1253 CHECK_EQ(script->Run()->Int32Value(), 900);
1254}
1255
1256
1257v8::Handle<v8::Object> bottom;
1258
1259static v8::Handle<Value> CheckThisIndexedPropertyHandler(
1260 uint32_t index,
1261 const AccessorInfo& info) {
1262 ApiTestFuzzer::Fuzz();
1263 CHECK(info.This()->Equals(bottom));
1264 return v8::Handle<Value>();
1265}
1266
1267static v8::Handle<Value> CheckThisNamedPropertyHandler(
1268 Local<String> name,
1269 const AccessorInfo& info) {
1270 ApiTestFuzzer::Fuzz();
1271 CHECK(info.This()->Equals(bottom));
1272 return v8::Handle<Value>();
1273}
1274
1275
1276v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
1277 Local<Value> value,
1278 const AccessorInfo& info) {
1279 ApiTestFuzzer::Fuzz();
1280 CHECK(info.This()->Equals(bottom));
1281 return v8::Handle<Value>();
1282}
1283
1284
1285v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
1286 Local<Value> value,
1287 const AccessorInfo& info) {
1288 ApiTestFuzzer::Fuzz();
1289 CHECK(info.This()->Equals(bottom));
1290 return v8::Handle<Value>();
1291}
1292
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001293v8::Handle<v8::Integer> CheckThisIndexedPropertyQuery(
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001294 uint32_t index,
1295 const AccessorInfo& info) {
1296 ApiTestFuzzer::Fuzz();
1297 CHECK(info.This()->Equals(bottom));
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001298 return v8::Handle<v8::Integer>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001299}
1300
1301
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001302v8::Handle<v8::Integer> CheckThisNamedPropertyQuery(Local<String> property,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001303 const AccessorInfo& info) {
1304 ApiTestFuzzer::Fuzz();
1305 CHECK(info.This()->Equals(bottom));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001306 return v8::Handle<v8::Integer>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001307}
1308
1309
1310v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
1311 uint32_t index,
1312 const AccessorInfo& info) {
1313 ApiTestFuzzer::Fuzz();
1314 CHECK(info.This()->Equals(bottom));
1315 return v8::Handle<v8::Boolean>();
1316}
1317
1318
1319v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
1320 Local<String> property,
1321 const AccessorInfo& info) {
1322 ApiTestFuzzer::Fuzz();
1323 CHECK(info.This()->Equals(bottom));
1324 return v8::Handle<v8::Boolean>();
1325}
1326
1327
1328v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
1329 const AccessorInfo& info) {
1330 ApiTestFuzzer::Fuzz();
1331 CHECK(info.This()->Equals(bottom));
1332 return v8::Handle<v8::Array>();
1333}
1334
1335
1336v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
1337 const AccessorInfo& info) {
1338 ApiTestFuzzer::Fuzz();
1339 CHECK(info.This()->Equals(bottom));
1340 return v8::Handle<v8::Array>();
1341}
1342
1343
1344THREADED_TEST(PropertyHandlerInPrototype) {
1345 v8::HandleScope scope;
1346 LocalContext env;
1347
1348 // Set up a prototype chain with three interceptors.
1349 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1350 templ->InstanceTemplate()->SetIndexedPropertyHandler(
1351 CheckThisIndexedPropertyHandler,
1352 CheckThisIndexedPropertySetter,
1353 CheckThisIndexedPropertyQuery,
1354 CheckThisIndexedPropertyDeleter,
1355 CheckThisIndexedPropertyEnumerator);
1356
1357 templ->InstanceTemplate()->SetNamedPropertyHandler(
1358 CheckThisNamedPropertyHandler,
1359 CheckThisNamedPropertySetter,
1360 CheckThisNamedPropertyQuery,
1361 CheckThisNamedPropertyDeleter,
1362 CheckThisNamedPropertyEnumerator);
1363
1364 bottom = templ->GetFunction()->NewInstance();
1365 Local<v8::Object> top = templ->GetFunction()->NewInstance();
1366 Local<v8::Object> middle = templ->GetFunction()->NewInstance();
1367
1368 bottom->Set(v8_str("__proto__"), middle);
1369 middle->Set(v8_str("__proto__"), top);
1370 env->Global()->Set(v8_str("obj"), bottom);
1371
1372 // Indexed and named get.
1373 Script::Compile(v8_str("obj[0]"))->Run();
1374 Script::Compile(v8_str("obj.x"))->Run();
1375
1376 // Indexed and named set.
1377 Script::Compile(v8_str("obj[1] = 42"))->Run();
1378 Script::Compile(v8_str("obj.y = 42"))->Run();
1379
1380 // Indexed and named query.
1381 Script::Compile(v8_str("0 in obj"))->Run();
1382 Script::Compile(v8_str("'x' in obj"))->Run();
1383
1384 // Indexed and named deleter.
1385 Script::Compile(v8_str("delete obj[0]"))->Run();
1386 Script::Compile(v8_str("delete obj.x"))->Run();
1387
1388 // Enumerators.
1389 Script::Compile(v8_str("for (var p in obj) ;"))->Run();
1390}
1391
1392
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001393static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
1394 const AccessorInfo& info) {
1395 ApiTestFuzzer::Fuzz();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001396 if (v8_str("pre")->Equals(key)) {
1397 return v8_str("PrePropertyHandler: pre");
1398 }
1399 return v8::Handle<String>();
1400}
1401
1402
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001403static v8::Handle<v8::Integer> PrePropertyHandlerQuery(Local<String> key,
1404 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001405 if (v8_str("pre")->Equals(key)) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001406 return v8::Integer::New(v8::None);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001407 }
1408
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001409 return v8::Handle<v8::Integer>(); // do not intercept the call
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001410}
1411
1412
1413THREADED_TEST(PrePropertyHandler) {
1414 v8::HandleScope scope;
1415 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
1416 desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
1417 0,
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001418 PrePropertyHandlerQuery);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001419 LocalContext env(NULL, desc->InstanceTemplate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001420 Script::Compile(v8_str(
1421 "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
1422 v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
1423 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
1424 v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
1425 CHECK_EQ(v8_str("Object: on"), result_on);
1426 v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
1427 CHECK(result_post.IsEmpty());
1428}
1429
1430
ager@chromium.org870a0b62008-11-04 11:43:05 +00001431THREADED_TEST(UndefinedIsNotEnumerable) {
1432 v8::HandleScope scope;
1433 LocalContext env;
1434 v8::Handle<Value> result = Script::Compile(v8_str(
1435 "this.propertyIsEnumerable(undefined)"))->Run();
1436 CHECK(result->IsFalse());
1437}
1438
1439
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001440v8::Handle<Script> call_recursively_script;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001441static const int kTargetRecursionDepth = 200; // near maximum
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001442
1443
1444static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
1445 ApiTestFuzzer::Fuzz();
1446 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1447 if (depth == kTargetRecursionDepth) return v8::Undefined();
1448 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1449 return call_recursively_script->Run();
1450}
1451
1452
1453static v8::Handle<Value> CallFunctionRecursivelyCall(
1454 const v8::Arguments& args) {
1455 ApiTestFuzzer::Fuzz();
1456 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1457 if (depth == kTargetRecursionDepth) {
1458 printf("[depth = %d]\n", depth);
1459 return v8::Undefined();
1460 }
1461 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1462 v8::Handle<Value> function =
1463 args.This()->Get(v8_str("callFunctionRecursively"));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001464 return function.As<Function>()->Call(args.This(), 0, NULL);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001465}
1466
1467
1468THREADED_TEST(DeepCrossLanguageRecursion) {
1469 v8::HandleScope scope;
1470 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
1471 global->Set(v8_str("callScriptRecursively"),
1472 v8::FunctionTemplate::New(CallScriptRecursivelyCall));
1473 global->Set(v8_str("callFunctionRecursively"),
1474 v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
1475 LocalContext env(NULL, global);
1476
1477 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1478 call_recursively_script = v8_compile("callScriptRecursively()");
1479 v8::Handle<Value> result = call_recursively_script->Run();
1480 call_recursively_script = v8::Handle<Script>();
1481
1482 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1483 Script::Compile(v8_str("callFunctionRecursively()"))->Run();
1484}
1485
1486
1487static v8::Handle<Value>
1488 ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1489 ApiTestFuzzer::Fuzz();
1490 return v8::ThrowException(key);
1491}
1492
1493
1494static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
1495 Local<Value>,
1496 const AccessorInfo&) {
1497 v8::ThrowException(key);
1498 return v8::Undefined(); // not the same as v8::Handle<v8::Value>()
1499}
1500
1501
1502THREADED_TEST(CallbackExceptionRegression) {
1503 v8::HandleScope scope;
1504 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1505 obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
1506 ThrowingPropertyHandlerSet);
1507 LocalContext env;
1508 env->Global()->Set(v8_str("obj"), obj->NewInstance());
1509 v8::Handle<Value> otto = Script::Compile(v8_str(
1510 "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
1511 CHECK_EQ(v8_str("otto"), otto);
1512 v8::Handle<Value> netto = Script::Compile(v8_str(
1513 "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
1514 CHECK_EQ(v8_str("netto"), netto);
1515}
1516
1517
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001518THREADED_TEST(FunctionPrototype) {
1519 v8::HandleScope scope;
1520 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
1521 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
1522 LocalContext env;
1523 env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
1524 Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
1525 CHECK_EQ(script->Run()->Int32Value(), 321);
1526}
1527
1528
1529THREADED_TEST(InternalFields) {
1530 v8::HandleScope scope;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001531 LocalContext env;
1532
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001533 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1534 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1535 instance_templ->SetInternalFieldCount(1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001536 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1537 CHECK_EQ(1, obj->InternalFieldCount());
1538 CHECK(obj->GetInternalField(0)->IsUndefined());
1539 obj->SetInternalField(0, v8_num(17));
1540 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
1541}
1542
1543
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001544THREADED_TEST(GlobalObjectInternalFields) {
1545 v8::HandleScope scope;
1546 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
1547 global_template->SetInternalFieldCount(1);
1548 LocalContext env(NULL, global_template);
1549 v8::Handle<v8::Object> global_proxy = env->Global();
1550 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
1551 CHECK_EQ(1, global->InternalFieldCount());
1552 CHECK(global->GetInternalField(0)->IsUndefined());
1553 global->SetInternalField(0, v8_num(17));
1554 CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
1555}
1556
1557
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001558THREADED_TEST(InternalFieldsNativePointers) {
1559 v8::HandleScope scope;
1560 LocalContext env;
1561
1562 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1563 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1564 instance_templ->SetInternalFieldCount(1);
1565 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1566 CHECK_EQ(1, obj->InternalFieldCount());
1567 CHECK(obj->GetPointerFromInternalField(0) == NULL);
1568
1569 char* data = new char[100];
1570
1571 void* aligned = data;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001572 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001573 void* unaligned = data + 1;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001574 CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001575
1576 // Check reading and writing aligned pointers.
1577 obj->SetPointerInInternalField(0, aligned);
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001578 i::Heap::CollectAllGarbage(false);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001579 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1580
1581 // Check reading and writing unaligned pointers.
1582 obj->SetPointerInInternalField(0, unaligned);
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001583 i::Heap::CollectAllGarbage(false);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001584 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1585
1586 delete[] data;
1587}
1588
1589
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001590THREADED_TEST(InternalFieldsNativePointersAndExternal) {
1591 v8::HandleScope scope;
1592 LocalContext env;
1593
1594 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1595 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1596 instance_templ->SetInternalFieldCount(1);
1597 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1598 CHECK_EQ(1, obj->InternalFieldCount());
1599 CHECK(obj->GetPointerFromInternalField(0) == NULL);
1600
1601 char* data = new char[100];
1602
1603 void* aligned = data;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001604 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001605 void* unaligned = data + 1;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001606 CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001607
1608 obj->SetPointerInInternalField(0, aligned);
1609 i::Heap::CollectAllGarbage(false);
1610 CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0)));
1611
1612 obj->SetPointerInInternalField(0, unaligned);
1613 i::Heap::CollectAllGarbage(false);
1614 CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0)));
1615
1616 obj->SetInternalField(0, v8::External::Wrap(aligned));
1617 i::Heap::CollectAllGarbage(false);
1618 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1619
1620 obj->SetInternalField(0, v8::External::Wrap(unaligned));
1621 i::Heap::CollectAllGarbage(false);
1622 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1623
1624 delete[] data;
1625}
1626
1627
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001628THREADED_TEST(IdentityHash) {
1629 v8::HandleScope scope;
1630 LocalContext env;
1631
1632 // Ensure that the test starts with an fresh heap to test whether the hash
1633 // code is based on the address.
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001634 i::Heap::CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001635 Local<v8::Object> obj = v8::Object::New();
1636 int hash = obj->GetIdentityHash();
1637 int hash1 = obj->GetIdentityHash();
1638 CHECK_EQ(hash, hash1);
1639 int hash2 = v8::Object::New()->GetIdentityHash();
1640 // Since the identity hash is essentially a random number two consecutive
1641 // objects should not be assigned the same hash code. If the test below fails
1642 // the random number generator should be evaluated.
1643 CHECK_NE(hash, hash2);
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001644 i::Heap::CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001645 int hash3 = v8::Object::New()->GetIdentityHash();
1646 // Make sure that the identity hash is not based on the initial address of
1647 // the object alone. If the test below fails the random number generator
1648 // should be evaluated.
1649 CHECK_NE(hash, hash3);
1650 int hash4 = obj->GetIdentityHash();
1651 CHECK_EQ(hash, hash4);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001652
1653 // Check identity hashes behaviour in the presence of JS accessors.
1654 // Put a getter for 'v8::IdentityHash' on the Object's prototype:
1655 {
1656 CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
1657 Local<v8::Object> o1 = v8::Object::New();
1658 Local<v8::Object> o2 = v8::Object::New();
1659 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
1660 }
1661 {
1662 CompileRun(
1663 "function cnst() { return 42; };\n"
1664 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
1665 Local<v8::Object> o1 = v8::Object::New();
1666 Local<v8::Object> o2 = v8::Object::New();
1667 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
1668 }
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001669}
1670
1671
1672THREADED_TEST(HiddenProperties) {
1673 v8::HandleScope scope;
1674 LocalContext env;
1675
1676 v8::Local<v8::Object> obj = v8::Object::New();
1677 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1678 v8::Local<v8::String> empty = v8_str("");
1679 v8::Local<v8::String> prop_name = v8_str("prop_name");
1680
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001681 i::Heap::CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001682
kasperl@chromium.orgacae3782009-04-11 09:17:08 +00001683 // Make sure delete of a non-existent hidden value works
1684 CHECK(obj->DeleteHiddenValue(key));
1685
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001686 CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
1687 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
1688 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
1689 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1690
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001691 i::Heap::CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001692
1693 // Make sure we do not find the hidden property.
1694 CHECK(!obj->Has(empty));
1695 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1696 CHECK(obj->Get(empty)->IsUndefined());
1697 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1698 CHECK(obj->Set(empty, v8::Integer::New(2003)));
1699 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1700 CHECK_EQ(2003, obj->Get(empty)->Int32Value());
1701
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001702 i::Heap::CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001703
1704 // Add another property and delete it afterwards to force the object in
1705 // slow case.
1706 CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
1707 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1708 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
1709 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1710 CHECK(obj->Delete(prop_name));
1711 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1712
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001713 i::Heap::CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001714
1715 CHECK(obj->DeleteHiddenValue(key));
1716 CHECK(obj->GetHiddenValue(key).IsEmpty());
1717}
1718
1719
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001720static bool interceptor_for_hidden_properties_called;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001721static v8::Handle<Value> InterceptorForHiddenProperties(
1722 Local<String> name, const AccessorInfo& info) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001723 interceptor_for_hidden_properties_called = true;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001724 return v8::Handle<Value>();
1725}
1726
1727
1728THREADED_TEST(HiddenPropertiesWithInterceptors) {
1729 v8::HandleScope scope;
1730 LocalContext context;
1731
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001732 interceptor_for_hidden_properties_called = false;
1733
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001734 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1735
1736 // Associate an interceptor with an object and start setting hidden values.
1737 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
1738 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
1739 instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
1740 Local<v8::Function> function = fun_templ->GetFunction();
1741 Local<v8::Object> obj = function->NewInstance();
1742 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
1743 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001744 CHECK(!interceptor_for_hidden_properties_called);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001745}
1746
1747
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001748THREADED_TEST(External) {
1749 v8::HandleScope scope;
1750 int x = 3;
1751 Local<v8::External> ext = v8::External::New(&x);
1752 LocalContext env;
1753 env->Global()->Set(v8_str("ext"), ext);
1754 Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001755 v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001756 int* ptr = static_cast<int*>(reext->Value());
1757 CHECK_EQ(x, 3);
1758 *ptr = 10;
1759 CHECK_EQ(x, 10);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001760
1761 // Make sure unaligned pointers are wrapped properly.
1762 char* data = i::StrDup("0123456789");
1763 Local<v8::Value> zero = v8::External::Wrap(&data[0]);
1764 Local<v8::Value> one = v8::External::Wrap(&data[1]);
1765 Local<v8::Value> two = v8::External::Wrap(&data[2]);
1766 Local<v8::Value> three = v8::External::Wrap(&data[3]);
1767
1768 char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero));
1769 CHECK_EQ('0', *char_ptr);
1770 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one));
1771 CHECK_EQ('1', *char_ptr);
1772 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two));
1773 CHECK_EQ('2', *char_ptr);
1774 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three));
1775 CHECK_EQ('3', *char_ptr);
1776 i::DeleteArray(data);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001777}
1778
1779
1780THREADED_TEST(GlobalHandle) {
1781 v8::Persistent<String> global;
1782 {
1783 v8::HandleScope scope;
1784 Local<String> str = v8_str("str");
1785 global = v8::Persistent<String>::New(str);
1786 }
1787 CHECK_EQ(global->Length(), 3);
1788 global.Dispose();
1789}
1790
1791
1792THREADED_TEST(ScriptException) {
1793 v8::HandleScope scope;
1794 LocalContext env;
1795 Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
1796 v8::TryCatch try_catch;
1797 Local<Value> result = script->Run();
1798 CHECK(result.IsEmpty());
1799 CHECK(try_catch.HasCaught());
1800 String::AsciiValue exception_value(try_catch.Exception());
1801 CHECK_EQ(*exception_value, "panama!");
1802}
1803
1804
1805bool message_received;
1806
1807
1808static void check_message(v8::Handle<v8::Message> message,
1809 v8::Handle<Value> data) {
1810 CHECK_EQ(5.76, data->NumberValue());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001811 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001812 CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001813 message_received = true;
1814}
1815
1816
1817THREADED_TEST(MessageHandlerData) {
1818 message_received = false;
1819 v8::HandleScope scope;
1820 CHECK(!message_received);
1821 v8::V8::AddMessageListener(check_message, v8_num(5.76));
1822 LocalContext context;
1823 v8::ScriptOrigin origin =
1824 v8::ScriptOrigin(v8_str("6.75"));
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001825 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
1826 &origin);
1827 script->SetData(v8_str("7.56"));
1828 script->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001829 CHECK(message_received);
1830 // clear out the message listener
1831 v8::V8::RemoveMessageListeners(check_message);
1832}
1833
1834
1835THREADED_TEST(GetSetProperty) {
1836 v8::HandleScope scope;
1837 LocalContext context;
1838 context->Global()->Set(v8_str("foo"), v8_num(14));
1839 context->Global()->Set(v8_str("12"), v8_num(92));
1840 context->Global()->Set(v8::Integer::New(16), v8_num(32));
1841 context->Global()->Set(v8_num(13), v8_num(56));
1842 Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
1843 CHECK_EQ(14, foo->Int32Value());
1844 Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
1845 CHECK_EQ(92, twelve->Int32Value());
1846 Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
1847 CHECK_EQ(32, sixteen->Int32Value());
1848 Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
1849 CHECK_EQ(56, thirteen->Int32Value());
1850 CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
1851 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
1852 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
1853 CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
1854 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
1855 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
1856 CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
1857 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
1858 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
1859}
1860
1861
1862THREADED_TEST(PropertyAttributes) {
1863 v8::HandleScope scope;
1864 LocalContext context;
1865 // read-only
1866 Local<String> prop = v8_str("read_only");
1867 context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
1868 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1869 Script::Compile(v8_str("read_only = 9"))->Run();
1870 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1871 context->Global()->Set(prop, v8_num(10));
1872 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1873 // dont-delete
1874 prop = v8_str("dont_delete");
1875 context->Global()->Set(prop, v8_num(13), v8::DontDelete);
1876 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
1877 Script::Compile(v8_str("delete dont_delete"))->Run();
1878 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
1879}
1880
1881
1882THREADED_TEST(Array) {
1883 v8::HandleScope scope;
1884 LocalContext context;
1885 Local<v8::Array> array = v8::Array::New();
1886 CHECK_EQ(0, array->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001887 CHECK(array->Get(0)->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001888 CHECK(!array->Has(0));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001889 CHECK(array->Get(100)->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001890 CHECK(!array->Has(100));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001891 array->Set(2, v8_num(7));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001892 CHECK_EQ(3, array->Length());
1893 CHECK(!array->Has(0));
1894 CHECK(!array->Has(1));
1895 CHECK(array->Has(2));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001896 CHECK_EQ(7, array->Get(2)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001897 Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001898 Local<v8::Array> arr = obj.As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001899 CHECK_EQ(3, arr->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001900 CHECK_EQ(1, arr->Get(0)->Int32Value());
1901 CHECK_EQ(2, arr->Get(1)->Int32Value());
1902 CHECK_EQ(3, arr->Get(2)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001903}
1904
1905
1906v8::Handle<Value> HandleF(const v8::Arguments& args) {
1907 v8::HandleScope scope;
1908 ApiTestFuzzer::Fuzz();
1909 Local<v8::Array> result = v8::Array::New(args.Length());
1910 for (int i = 0; i < args.Length(); i++)
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001911 result->Set(i, args[i]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001912 return scope.Close(result);
1913}
1914
1915
1916THREADED_TEST(Vector) {
1917 v8::HandleScope scope;
1918 Local<ObjectTemplate> global = ObjectTemplate::New();
1919 global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
1920 LocalContext context(0, global);
1921
1922 const char* fun = "f()";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001923 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001924 CHECK_EQ(0, a0->Length());
1925
1926 const char* fun2 = "f(11)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001927 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001928 CHECK_EQ(1, a1->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001929 CHECK_EQ(11, a1->Get(0)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001930
1931 const char* fun3 = "f(12, 13)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001932 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001933 CHECK_EQ(2, a2->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001934 CHECK_EQ(12, a2->Get(0)->Int32Value());
1935 CHECK_EQ(13, a2->Get(1)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001936
1937 const char* fun4 = "f(14, 15, 16)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001938 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001939 CHECK_EQ(3, a3->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001940 CHECK_EQ(14, a3->Get(0)->Int32Value());
1941 CHECK_EQ(15, a3->Get(1)->Int32Value());
1942 CHECK_EQ(16, a3->Get(2)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001943
1944 const char* fun5 = "f(17, 18, 19, 20)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001945 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001946 CHECK_EQ(4, a4->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001947 CHECK_EQ(17, a4->Get(0)->Int32Value());
1948 CHECK_EQ(18, a4->Get(1)->Int32Value());
1949 CHECK_EQ(19, a4->Get(2)->Int32Value());
1950 CHECK_EQ(20, a4->Get(3)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001951}
1952
1953
1954THREADED_TEST(FunctionCall) {
1955 v8::HandleScope scope;
1956 LocalContext context;
1957 CompileRun(
1958 "function Foo() {"
1959 " var result = [];"
1960 " for (var i = 0; i < arguments.length; i++) {"
1961 " result.push(arguments[i]);"
1962 " }"
1963 " return result;"
1964 "}");
1965 Local<Function> Foo =
1966 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
1967
1968 v8::Handle<Value>* args0 = NULL;
1969 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
1970 CHECK_EQ(0, a0->Length());
1971
1972 v8::Handle<Value> args1[] = { v8_num(1.1) };
1973 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
1974 CHECK_EQ(1, a1->Length());
1975 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
1976
1977 v8::Handle<Value> args2[] = { v8_num(2.2),
1978 v8_num(3.3) };
1979 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
1980 CHECK_EQ(2, a2->Length());
1981 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
1982 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
1983
1984 v8::Handle<Value> args3[] = { v8_num(4.4),
1985 v8_num(5.5),
1986 v8_num(6.6) };
1987 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
1988 CHECK_EQ(3, a3->Length());
1989 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
1990 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
1991 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
1992
1993 v8::Handle<Value> args4[] = { v8_num(7.7),
1994 v8_num(8.8),
1995 v8_num(9.9),
1996 v8_num(10.11) };
1997 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
1998 CHECK_EQ(4, a4->Length());
1999 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2000 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2001 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2002 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2003}
2004
2005
2006static const char* js_code_causing_out_of_memory =
2007 "var a = new Array(); while(true) a.push(a);";
2008
2009
2010// These tests run for a long time and prevent us from running tests
2011// that come after them so they cannot run in parallel.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002012TEST(OutOfMemory) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002013 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002014 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002015 // Set heap limits.
2016 static const int K = 1024;
2017 v8::ResourceConstraints constraints;
2018 constraints.set_max_young_space_size(256 * K);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002019 constraints.set_max_old_space_size(4 * K * K);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002020 v8::SetResourceConstraints(&constraints);
2021
2022 // Execute a script that causes out of memory.
2023 v8::HandleScope scope;
2024 LocalContext context;
2025 v8::V8::IgnoreOutOfMemoryException();
2026 Local<Script> script =
2027 Script::Compile(String::New(js_code_causing_out_of_memory));
2028 Local<Value> result = script->Run();
2029
2030 // Check for out of memory state.
2031 CHECK(result.IsEmpty());
2032 CHECK(context->HasOutOfMemoryException());
2033}
2034
2035
2036v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
2037 ApiTestFuzzer::Fuzz();
2038
2039 v8::HandleScope scope;
2040 LocalContext context;
2041 Local<Script> script =
2042 Script::Compile(String::New(js_code_causing_out_of_memory));
2043 Local<Value> result = script->Run();
2044
2045 // Check for out of memory state.
2046 CHECK(result.IsEmpty());
2047 CHECK(context->HasOutOfMemoryException());
2048
2049 return result;
2050}
2051
2052
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002053TEST(OutOfMemoryNested) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002054 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002055 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002056 // Set heap limits.
2057 static const int K = 1024;
2058 v8::ResourceConstraints constraints;
2059 constraints.set_max_young_space_size(256 * K);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002060 constraints.set_max_old_space_size(4 * K * K);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002061 v8::SetResourceConstraints(&constraints);
2062
2063 v8::HandleScope scope;
2064 Local<ObjectTemplate> templ = ObjectTemplate::New();
2065 templ->Set(v8_str("ProvokeOutOfMemory"),
2066 v8::FunctionTemplate::New(ProvokeOutOfMemory));
2067 LocalContext context(0, templ);
2068 v8::V8::IgnoreOutOfMemoryException();
2069 Local<Value> result = CompileRun(
2070 "var thrown = false;"
2071 "try {"
2072 " ProvokeOutOfMemory();"
2073 "} catch (e) {"
2074 " thrown = true;"
2075 "}");
2076 // Check for out of memory state.
2077 CHECK(result.IsEmpty());
2078 CHECK(context->HasOutOfMemoryException());
2079}
2080
2081
2082TEST(HugeConsStringOutOfMemory) {
2083 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002084 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002085 v8::HandleScope scope;
2086 LocalContext context;
2087 // Set heap limits.
2088 static const int K = 1024;
2089 v8::ResourceConstraints constraints;
2090 constraints.set_max_young_space_size(256 * K);
2091 constraints.set_max_old_space_size(2 * K * K);
2092 v8::SetResourceConstraints(&constraints);
2093
2094 // Execute a script that causes out of memory.
2095 v8::V8::IgnoreOutOfMemoryException();
2096
2097 // Build huge string. This should fail with out of memory exception.
2098 Local<Value> result = CompileRun(
2099 "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002100 "for (var i = 0; i < 22; i++) { str = str + str; }");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002101
2102 // Check for out of memory state.
2103 CHECK(result.IsEmpty());
2104 CHECK(context->HasOutOfMemoryException());
2105}
2106
2107
2108THREADED_TEST(ConstructCall) {
2109 v8::HandleScope scope;
2110 LocalContext context;
2111 CompileRun(
2112 "function Foo() {"
2113 " var result = [];"
2114 " for (var i = 0; i < arguments.length; i++) {"
2115 " result.push(arguments[i]);"
2116 " }"
2117 " return result;"
2118 "}");
2119 Local<Function> Foo =
2120 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2121
2122 v8::Handle<Value>* args0 = NULL;
2123 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
2124 CHECK_EQ(0, a0->Length());
2125
2126 v8::Handle<Value> args1[] = { v8_num(1.1) };
2127 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
2128 CHECK_EQ(1, a1->Length());
2129 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2130
2131 v8::Handle<Value> args2[] = { v8_num(2.2),
2132 v8_num(3.3) };
2133 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
2134 CHECK_EQ(2, a2->Length());
2135 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2136 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2137
2138 v8::Handle<Value> args3[] = { v8_num(4.4),
2139 v8_num(5.5),
2140 v8_num(6.6) };
2141 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
2142 CHECK_EQ(3, a3->Length());
2143 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2144 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2145 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2146
2147 v8::Handle<Value> args4[] = { v8_num(7.7),
2148 v8_num(8.8),
2149 v8_num(9.9),
2150 v8_num(10.11) };
2151 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
2152 CHECK_EQ(4, a4->Length());
2153 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2154 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2155 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2156 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2157}
2158
2159
2160static void CheckUncle(v8::TryCatch* try_catch) {
2161 CHECK(try_catch->HasCaught());
2162 String::AsciiValue str_value(try_catch->Exception());
2163 CHECK_EQ(*str_value, "uncle?");
2164 try_catch->Reset();
2165}
2166
2167
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002168THREADED_TEST(ConversionNumber) {
2169 v8::HandleScope scope;
2170 LocalContext env;
2171 // Very large number.
2172 CompileRun("var obj = Math.pow(2,32) * 1237;");
2173 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2174 CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
2175 CHECK_EQ(0, obj->ToInt32()->Value());
2176 CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned.
2177 // Large number.
2178 CompileRun("var obj = -1234567890123;");
2179 obj = env->Global()->Get(v8_str("obj"));
2180 CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
2181 CHECK_EQ(-1912276171, obj->ToInt32()->Value());
2182 CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT
2183 // Small positive integer.
2184 CompileRun("var obj = 42;");
2185 obj = env->Global()->Get(v8_str("obj"));
2186 CHECK_EQ(42.0, obj->ToNumber()->Value());
2187 CHECK_EQ(42, obj->ToInt32()->Value());
2188 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
2189 // Negative integer.
2190 CompileRun("var obj = -37;");
2191 obj = env->Global()->Get(v8_str("obj"));
2192 CHECK_EQ(-37.0, obj->ToNumber()->Value());
2193 CHECK_EQ(-37, obj->ToInt32()->Value());
2194 CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT
2195 // Positive non-int32 integer.
2196 CompileRun("var obj = 0x81234567;");
2197 obj = env->Global()->Get(v8_str("obj"));
2198 CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
2199 CHECK_EQ(-2128394905, obj->ToInt32()->Value());
2200 CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT
2201 // Fraction.
2202 CompileRun("var obj = 42.3;");
2203 obj = env->Global()->Get(v8_str("obj"));
2204 CHECK_EQ(42.3, obj->ToNumber()->Value());
2205 CHECK_EQ(42, obj->ToInt32()->Value());
2206 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
2207 // Large negative fraction.
2208 CompileRun("var obj = -5726623061.75;");
2209 obj = env->Global()->Get(v8_str("obj"));
2210 CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
2211 CHECK_EQ(-1431655765, obj->ToInt32()->Value());
2212 CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT
2213}
2214
2215
2216THREADED_TEST(isNumberType) {
2217 v8::HandleScope scope;
2218 LocalContext env;
2219 // Very large number.
2220 CompileRun("var obj = Math.pow(2,32) * 1237;");
2221 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2222 CHECK(!obj->IsInt32());
2223 CHECK(!obj->IsUint32());
2224 // Large negative number.
2225 CompileRun("var obj = -1234567890123;");
2226 obj = env->Global()->Get(v8_str("obj"));
2227 CHECK(!obj->IsInt32());
2228 CHECK(!obj->IsUint32());
2229 // Small positive integer.
2230 CompileRun("var obj = 42;");
2231 obj = env->Global()->Get(v8_str("obj"));
2232 CHECK(obj->IsInt32());
2233 CHECK(obj->IsUint32());
2234 // Negative integer.
2235 CompileRun("var obj = -37;");
2236 obj = env->Global()->Get(v8_str("obj"));
2237 CHECK(obj->IsInt32());
2238 CHECK(!obj->IsUint32());
2239 // Positive non-int32 integer.
2240 CompileRun("var obj = 0x81234567;");
2241 obj = env->Global()->Get(v8_str("obj"));
2242 CHECK(!obj->IsInt32());
2243 CHECK(obj->IsUint32());
2244 // Fraction.
2245 CompileRun("var obj = 42.3;");
2246 obj = env->Global()->Get(v8_str("obj"));
2247 CHECK(!obj->IsInt32());
2248 CHECK(!obj->IsUint32());
2249 // Large negative fraction.
2250 CompileRun("var obj = -5726623061.75;");
2251 obj = env->Global()->Get(v8_str("obj"));
2252 CHECK(!obj->IsInt32());
2253 CHECK(!obj->IsUint32());
2254}
2255
2256
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002257THREADED_TEST(ConversionException) {
2258 v8::HandleScope scope;
2259 LocalContext env;
2260 CompileRun(
2261 "function TestClass() { };"
2262 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
2263 "var obj = new TestClass();");
2264 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2265
2266 v8::TryCatch try_catch;
2267
2268 Local<Value> to_string_result = obj->ToString();
2269 CHECK(to_string_result.IsEmpty());
2270 CheckUncle(&try_catch);
2271
2272 Local<Value> to_number_result = obj->ToNumber();
2273 CHECK(to_number_result.IsEmpty());
2274 CheckUncle(&try_catch);
2275
2276 Local<Value> to_integer_result = obj->ToInteger();
2277 CHECK(to_integer_result.IsEmpty());
2278 CheckUncle(&try_catch);
2279
2280 Local<Value> to_uint32_result = obj->ToUint32();
2281 CHECK(to_uint32_result.IsEmpty());
2282 CheckUncle(&try_catch);
2283
2284 Local<Value> to_int32_result = obj->ToInt32();
2285 CHECK(to_int32_result.IsEmpty());
2286 CheckUncle(&try_catch);
2287
2288 Local<Value> to_object_result = v8::Undefined()->ToObject();
2289 CHECK(to_object_result.IsEmpty());
2290 CHECK(try_catch.HasCaught());
2291 try_catch.Reset();
2292
2293 int32_t int32_value = obj->Int32Value();
2294 CHECK_EQ(0, int32_value);
2295 CheckUncle(&try_catch);
2296
2297 uint32_t uint32_value = obj->Uint32Value();
2298 CHECK_EQ(0, uint32_value);
2299 CheckUncle(&try_catch);
2300
2301 double number_value = obj->NumberValue();
2302 CHECK_NE(0, IsNaN(number_value));
2303 CheckUncle(&try_catch);
2304
2305 int64_t integer_value = obj->IntegerValue();
2306 CHECK_EQ(0.0, static_cast<double>(integer_value));
2307 CheckUncle(&try_catch);
2308}
2309
2310
2311v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
2312 ApiTestFuzzer::Fuzz();
2313 return v8::ThrowException(v8_str("konto"));
2314}
2315
2316
ager@chromium.org8bb60582008-12-11 12:02:20 +00002317v8::Handle<Value> CCatcher(const v8::Arguments& args) {
2318 if (args.Length() < 1) return v8::Boolean::New(false);
2319 v8::HandleScope scope;
2320 v8::TryCatch try_catch;
ager@chromium.org71daaf62009-04-01 07:22:49 +00002321 Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
2322 CHECK(!try_catch.HasCaught() || result.IsEmpty());
ager@chromium.org8bb60582008-12-11 12:02:20 +00002323 return v8::Boolean::New(try_catch.HasCaught());
2324}
2325
2326
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002327THREADED_TEST(APICatch) {
2328 v8::HandleScope scope;
2329 Local<ObjectTemplate> templ = ObjectTemplate::New();
2330 templ->Set(v8_str("ThrowFromC"),
2331 v8::FunctionTemplate::New(ThrowFromC));
2332 LocalContext context(0, templ);
2333 CompileRun(
2334 "var thrown = false;"
2335 "try {"
2336 " ThrowFromC();"
2337 "} catch (e) {"
2338 " thrown = true;"
2339 "}");
2340 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
2341 CHECK(thrown->BooleanValue());
2342}
2343
2344
ager@chromium.org8bb60582008-12-11 12:02:20 +00002345THREADED_TEST(APIThrowTryCatch) {
2346 v8::HandleScope scope;
2347 Local<ObjectTemplate> templ = ObjectTemplate::New();
2348 templ->Set(v8_str("ThrowFromC"),
2349 v8::FunctionTemplate::New(ThrowFromC));
2350 LocalContext context(0, templ);
2351 v8::TryCatch try_catch;
2352 CompileRun("ThrowFromC();");
2353 CHECK(try_catch.HasCaught());
2354}
2355
2356
2357// Test that a try-finally block doesn't shadow a try-catch block
2358// when setting up an external handler.
ager@chromium.org71daaf62009-04-01 07:22:49 +00002359//
2360// BUG(271): Some of the exception propagation does not work on the
2361// ARM simulator because the simulator separates the C++ stack and the
2362// JS stack. This test therefore fails on the simulator. The test is
2363// not threaded to allow the threading tests to run on the simulator.
2364TEST(TryCatchInTryFinally) {
ager@chromium.org8bb60582008-12-11 12:02:20 +00002365 v8::HandleScope scope;
2366 Local<ObjectTemplate> templ = ObjectTemplate::New();
2367 templ->Set(v8_str("CCatcher"),
2368 v8::FunctionTemplate::New(CCatcher));
2369 LocalContext context(0, templ);
2370 Local<Value> result = CompileRun("try {"
2371 " try {"
2372 " CCatcher('throw 7;');"
2373 " } finally {"
2374 " }"
2375 "} catch (e) {"
2376 "}");
2377 CHECK(result->IsTrue());
2378}
2379
2380
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002381static void check_reference_error_message(
2382 v8::Handle<v8::Message> message,
2383 v8::Handle<v8::Value> data) {
2384 const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
2385 CHECK(message->Get()->Equals(v8_str(reference_error)));
2386}
2387
2388
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00002389static v8::Handle<Value> Fail(const v8::Arguments& args) {
2390 ApiTestFuzzer::Fuzz();
2391 CHECK(false);
2392 return v8::Undefined();
2393}
2394
2395
2396// Test that overwritten methods are not invoked on uncaught exception
2397// formatting. However, they are invoked when performing normal error
2398// string conversions.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002399TEST(APIThrowMessageOverwrittenToString) {
2400 v8::HandleScope scope;
2401 v8::V8::AddMessageListener(check_reference_error_message);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00002402 Local<ObjectTemplate> templ = ObjectTemplate::New();
2403 templ->Set(v8_str("fail"), v8::FunctionTemplate::New(Fail));
2404 LocalContext context(NULL, templ);
2405 CompileRun("asdf;");
2406 CompileRun("var limit = {};"
2407 "limit.valueOf = fail;"
2408 "Error.stackTraceLimit = limit;");
2409 CompileRun("asdf");
2410 CompileRun("Array.prototype.pop = fail;");
2411 CompileRun("Object.prototype.hasOwnProperty = fail;");
2412 CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
whesse@chromium.org7a392b32011-01-31 11:30:36 +00002413 CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
2414 CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002415 CompileRun("ReferenceError.prototype.toString ="
2416 " function() { return 'Whoops' }");
2417 CompileRun("asdf;");
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002418 CompileRun("ReferenceError.prototype.constructor.name = void 0;");
2419 CompileRun("asdf;");
2420 CompileRun("ReferenceError.prototype.constructor = void 0;");
2421 CompileRun("asdf;");
ager@chromium.org0ee099b2011-01-25 14:06:47 +00002422 CompileRun("ReferenceError.prototype.__proto__ = new Object();");
2423 CompileRun("asdf;");
2424 CompileRun("ReferenceError.prototype = new Object();");
2425 CompileRun("asdf;");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002426 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
2427 CHECK(string->Equals(v8_str("Whoops")));
ager@chromium.org378b34e2011-01-28 08:04:38 +00002428 CompileRun("ReferenceError.prototype.constructor = new Object();"
2429 "ReferenceError.prototype.constructor.name = 1;"
2430 "Number.prototype.toString = function() { return 'Whoops'; };"
2431 "ReferenceError.prototype.toString = Object.prototype.toString;");
2432 CompileRun("asdf;");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002433 v8::V8::RemoveMessageListeners(check_message);
2434}
2435
2436
ager@chromium.org8bb60582008-12-11 12:02:20 +00002437static void receive_message(v8::Handle<v8::Message> message,
2438 v8::Handle<v8::Value> data) {
ager@chromium.org71daaf62009-04-01 07:22:49 +00002439 message->Get();
ager@chromium.org8bb60582008-12-11 12:02:20 +00002440 message_received = true;
2441}
2442
2443
2444TEST(APIThrowMessage) {
2445 message_received = false;
2446 v8::HandleScope scope;
2447 v8::V8::AddMessageListener(receive_message);
2448 Local<ObjectTemplate> templ = ObjectTemplate::New();
2449 templ->Set(v8_str("ThrowFromC"),
2450 v8::FunctionTemplate::New(ThrowFromC));
2451 LocalContext context(0, templ);
2452 CompileRun("ThrowFromC();");
2453 CHECK(message_received);
2454 v8::V8::RemoveMessageListeners(check_message);
2455}
2456
2457
2458TEST(APIThrowMessageAndVerboseTryCatch) {
2459 message_received = false;
2460 v8::HandleScope scope;
2461 v8::V8::AddMessageListener(receive_message);
2462 Local<ObjectTemplate> templ = ObjectTemplate::New();
2463 templ->Set(v8_str("ThrowFromC"),
2464 v8::FunctionTemplate::New(ThrowFromC));
2465 LocalContext context(0, templ);
2466 v8::TryCatch try_catch;
2467 try_catch.SetVerbose(true);
ager@chromium.org71daaf62009-04-01 07:22:49 +00002468 Local<Value> result = CompileRun("ThrowFromC();");
ager@chromium.org8bb60582008-12-11 12:02:20 +00002469 CHECK(try_catch.HasCaught());
ager@chromium.org71daaf62009-04-01 07:22:49 +00002470 CHECK(result.IsEmpty());
ager@chromium.org8bb60582008-12-11 12:02:20 +00002471 CHECK(message_received);
2472 v8::V8::RemoveMessageListeners(check_message);
2473}
2474
2475
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002476THREADED_TEST(ExternalScriptException) {
2477 v8::HandleScope scope;
2478 Local<ObjectTemplate> templ = ObjectTemplate::New();
2479 templ->Set(v8_str("ThrowFromC"),
2480 v8::FunctionTemplate::New(ThrowFromC));
2481 LocalContext context(0, templ);
2482
2483 v8::TryCatch try_catch;
2484 Local<Script> script
2485 = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
2486 Local<Value> result = script->Run();
2487 CHECK(result.IsEmpty());
2488 CHECK(try_catch.HasCaught());
2489 String::AsciiValue exception_value(try_catch.Exception());
2490 CHECK_EQ("konto", *exception_value);
2491}
2492
2493
2494
2495v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
2496 ApiTestFuzzer::Fuzz();
2497 CHECK_EQ(4, args.Length());
2498 int count = args[0]->Int32Value();
2499 int cInterval = args[2]->Int32Value();
2500 if (count == 0) {
2501 return v8::ThrowException(v8_str("FromC"));
2502 } else {
2503 Local<v8::Object> global = Context::GetCurrent()->Global();
2504 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
2505 v8::Handle<Value> argv[] = { v8_num(count - 1),
2506 args[1],
2507 args[2],
2508 args[3] };
2509 if (count % cInterval == 0) {
2510 v8::TryCatch try_catch;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002511 Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002512 int expected = args[3]->Int32Value();
2513 if (try_catch.HasCaught()) {
2514 CHECK_EQ(expected, count);
ager@chromium.org71daaf62009-04-01 07:22:49 +00002515 CHECK(result.IsEmpty());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002516 CHECK(!i::Top::has_scheduled_exception());
2517 } else {
2518 CHECK_NE(expected, count);
2519 }
2520 return result;
2521 } else {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002522 return fun.As<Function>()->Call(global, 4, argv);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002523 }
2524 }
2525}
2526
2527
2528v8::Handle<Value> JSCheck(const v8::Arguments& args) {
2529 ApiTestFuzzer::Fuzz();
2530 CHECK_EQ(3, args.Length());
2531 bool equality = args[0]->BooleanValue();
2532 int count = args[1]->Int32Value();
2533 int expected = args[2]->Int32Value();
2534 if (equality) {
2535 CHECK_EQ(count, expected);
2536 } else {
2537 CHECK_NE(count, expected);
2538 }
2539 return v8::Undefined();
2540}
2541
2542
ager@chromium.org8bb60582008-12-11 12:02:20 +00002543THREADED_TEST(EvalInTryFinally) {
2544 v8::HandleScope scope;
2545 LocalContext context;
2546 v8::TryCatch try_catch;
2547 CompileRun("(function() {"
2548 " try {"
2549 " eval('asldkf (*&^&*^');"
2550 " } finally {"
2551 " return;"
2552 " }"
2553 "})()");
2554 CHECK(!try_catch.HasCaught());
2555}
2556
2557
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002558// This test works by making a stack of alternating JavaScript and C
2559// activations. These activations set up exception handlers with regular
2560// intervals, one interval for C activations and another for JavaScript
2561// activations. When enough activations have been created an exception is
2562// thrown and we check that the right activation catches the exception and that
2563// no other activations do. The right activation is always the topmost one with
2564// a handler, regardless of whether it is in JavaScript or C.
2565//
2566// The notation used to describe a test case looks like this:
2567//
2568// *JS[4] *C[3] @JS[2] C[1] JS[0]
2569//
2570// Each entry is an activation, either JS or C. The index is the count at that
2571// level. Stars identify activations with exception handlers, the @ identifies
2572// the exception handler that should catch the exception.
ager@chromium.org71daaf62009-04-01 07:22:49 +00002573//
2574// BUG(271): Some of the exception propagation does not work on the
2575// ARM simulator because the simulator separates the C++ stack and the
2576// JS stack. This test therefore fails on the simulator. The test is
2577// not threaded to allow the threading tests to run on the simulator.
2578TEST(ExceptionOrder) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002579 v8::HandleScope scope;
2580 Local<ObjectTemplate> templ = ObjectTemplate::New();
2581 templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
2582 templ->Set(v8_str("CThrowCountDown"),
2583 v8::FunctionTemplate::New(CThrowCountDown));
2584 LocalContext context(0, templ);
2585 CompileRun(
2586 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
2587 " if (count == 0) throw 'FromJS';"
2588 " if (count % jsInterval == 0) {"
2589 " try {"
2590 " var value = CThrowCountDown(count - 1,"
2591 " jsInterval,"
2592 " cInterval,"
2593 " expected);"
2594 " check(false, count, expected);"
2595 " return value;"
2596 " } catch (e) {"
2597 " check(true, count, expected);"
2598 " }"
2599 " } else {"
2600 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
2601 " }"
2602 "}");
2603 Local<Function> fun =
2604 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
2605
2606 const int argc = 4;
2607 // count jsInterval cInterval expected
2608
2609 // *JS[4] *C[3] @JS[2] C[1] JS[0]
2610 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
2611 fun->Call(fun, argc, a0);
2612
2613 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
2614 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
2615 fun->Call(fun, argc, a1);
2616
2617 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
2618 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
2619 fun->Call(fun, argc, a2);
2620
2621 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
2622 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
2623 fun->Call(fun, argc, a3);
2624
2625 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
2626 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
2627 fun->Call(fun, argc, a4);
2628
2629 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
2630 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
2631 fun->Call(fun, argc, a5);
2632}
2633
2634
2635v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
2636 ApiTestFuzzer::Fuzz();
2637 CHECK_EQ(1, args.Length());
2638 return v8::ThrowException(args[0]);
2639}
2640
2641
2642THREADED_TEST(ThrowValues) {
2643 v8::HandleScope scope;
2644 Local<ObjectTemplate> templ = ObjectTemplate::New();
2645 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
2646 LocalContext context(0, templ);
2647 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
2648 "function Run(obj) {"
2649 " try {"
2650 " Throw(obj);"
2651 " } catch (e) {"
2652 " return e;"
2653 " }"
2654 " return 'no exception';"
2655 "}"
2656 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
2657 CHECK_EQ(5, result->Length());
2658 CHECK(result->Get(v8::Integer::New(0))->IsString());
2659 CHECK(result->Get(v8::Integer::New(1))->IsNumber());
2660 CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
2661 CHECK(result->Get(v8::Integer::New(2))->IsNumber());
2662 CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
2663 CHECK(result->Get(v8::Integer::New(3))->IsNull());
2664 CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
2665}
2666
2667
2668THREADED_TEST(CatchZero) {
2669 v8::HandleScope scope;
2670 LocalContext context;
2671 v8::TryCatch try_catch;
2672 CHECK(!try_catch.HasCaught());
2673 Script::Compile(v8_str("throw 10"))->Run();
2674 CHECK(try_catch.HasCaught());
2675 CHECK_EQ(10, try_catch.Exception()->Int32Value());
2676 try_catch.Reset();
2677 CHECK(!try_catch.HasCaught());
2678 Script::Compile(v8_str("throw 0"))->Run();
2679 CHECK(try_catch.HasCaught());
2680 CHECK_EQ(0, try_catch.Exception()->Int32Value());
2681}
2682
2683
2684THREADED_TEST(CatchExceptionFromWith) {
2685 v8::HandleScope scope;
2686 LocalContext context;
2687 v8::TryCatch try_catch;
2688 CHECK(!try_catch.HasCaught());
2689 Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
2690 CHECK(try_catch.HasCaught());
2691}
2692
2693
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002694THREADED_TEST(TryCatchAndFinallyHidingException) {
2695 v8::HandleScope scope;
2696 LocalContext context;
2697 v8::TryCatch try_catch;
2698 CHECK(!try_catch.HasCaught());
2699 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
2700 CompileRun("f({toString: function() { throw 42; }});");
2701 CHECK(!try_catch.HasCaught());
2702}
2703
2704
2705v8::Handle<v8::Value> WithTryCatch(const v8::Arguments& args) {
2706 v8::TryCatch try_catch;
2707 return v8::Undefined();
2708}
2709
2710
2711THREADED_TEST(TryCatchAndFinally) {
2712 v8::HandleScope scope;
2713 LocalContext context;
2714 context->Global()->Set(
2715 v8_str("native_with_try_catch"),
2716 v8::FunctionTemplate::New(WithTryCatch)->GetFunction());
2717 v8::TryCatch try_catch;
2718 CHECK(!try_catch.HasCaught());
2719 CompileRun(
2720 "try {\n"
2721 " throw new Error('a');\n"
2722 "} finally {\n"
2723 " native_with_try_catch();\n"
2724 "}\n");
2725 CHECK(try_catch.HasCaught());
2726}
2727
2728
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002729THREADED_TEST(Equality) {
2730 v8::HandleScope scope;
2731 LocalContext context;
2732 // Check that equality works at all before relying on CHECK_EQ
2733 CHECK(v8_str("a")->Equals(v8_str("a")));
2734 CHECK(!v8_str("a")->Equals(v8_str("b")));
2735
2736 CHECK_EQ(v8_str("a"), v8_str("a"));
2737 CHECK_NE(v8_str("a"), v8_str("b"));
2738 CHECK_EQ(v8_num(1), v8_num(1));
2739 CHECK_EQ(v8_num(1.00), v8_num(1));
2740 CHECK_NE(v8_num(1), v8_num(2));
2741
2742 // Assume String is not symbol.
2743 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
2744 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
2745 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
2746 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
2747 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
2748 CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
2749 Local<Value> not_a_number = v8_num(i::OS::nan_value());
2750 CHECK(!not_a_number->StrictEquals(not_a_number));
2751 CHECK(v8::False()->StrictEquals(v8::False()));
2752 CHECK(!v8::False()->StrictEquals(v8::Undefined()));
2753
2754 v8::Handle<v8::Object> obj = v8::Object::New();
2755 v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
2756 CHECK(alias->StrictEquals(obj));
2757 alias.Dispose();
2758}
2759
2760
2761THREADED_TEST(MultiRun) {
2762 v8::HandleScope scope;
2763 LocalContext context;
2764 Local<Script> script = Script::Compile(v8_str("x"));
2765 for (int i = 0; i < 10; i++)
2766 script->Run();
2767}
2768
2769
2770static v8::Handle<Value> GetXValue(Local<String> name,
2771 const AccessorInfo& info) {
2772 ApiTestFuzzer::Fuzz();
2773 CHECK_EQ(info.Data(), v8_str("donut"));
2774 CHECK_EQ(name, v8_str("x"));
2775 return name;
2776}
2777
2778
2779THREADED_TEST(SimplePropertyRead) {
2780 v8::HandleScope scope;
2781 Local<ObjectTemplate> templ = ObjectTemplate::New();
2782 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2783 LocalContext context;
2784 context->Global()->Set(v8_str("obj"), templ->NewInstance());
2785 Local<Script> script = Script::Compile(v8_str("obj.x"));
2786 for (int i = 0; i < 10; i++) {
2787 Local<Value> result = script->Run();
2788 CHECK_EQ(result, v8_str("x"));
2789 }
2790}
2791
ager@chromium.org5c838252010-02-19 08:53:10 +00002792THREADED_TEST(DefinePropertyOnAPIAccessor) {
2793 v8::HandleScope scope;
2794 Local<ObjectTemplate> templ = ObjectTemplate::New();
2795 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2796 LocalContext context;
2797 context->Global()->Set(v8_str("obj"), templ->NewInstance());
2798
2799 // Uses getOwnPropertyDescriptor to check the configurable status
2800 Local<Script> script_desc
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002801 = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
ager@chromium.org5c838252010-02-19 08:53:10 +00002802 "obj, 'x');"
2803 "prop.configurable;"));
2804 Local<Value> result = script_desc->Run();
2805 CHECK_EQ(result->BooleanValue(), true);
2806
2807 // Redefine get - but still configurable
2808 Local<Script> script_define
2809 = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
2810 " configurable: true };"
2811 "Object.defineProperty(obj, 'x', desc);"
2812 "obj.x"));
2813 result = script_define->Run();
2814 CHECK_EQ(result, v8_num(42));
2815
2816 // Check that the accessor is still configurable
2817 result = script_desc->Run();
2818 CHECK_EQ(result->BooleanValue(), true);
2819
2820 // Redefine to a non-configurable
2821 script_define
2822 = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
2823 " configurable: false };"
2824 "Object.defineProperty(obj, 'x', desc);"
2825 "obj.x"));
2826 result = script_define->Run();
2827 CHECK_EQ(result, v8_num(43));
2828 result = script_desc->Run();
2829 CHECK_EQ(result->BooleanValue(), false);
2830
2831 // Make sure that it is not possible to redefine again
2832 v8::TryCatch try_catch;
2833 result = script_define->Run();
2834 CHECK(try_catch.HasCaught());
2835 String::AsciiValue exception_value(try_catch.Exception());
2836 CHECK_EQ(*exception_value,
2837 "TypeError: Cannot redefine property: defineProperty");
2838}
2839
2840THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
2841 v8::HandleScope scope;
2842 Local<ObjectTemplate> templ = ObjectTemplate::New();
2843 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2844 LocalContext context;
2845 context->Global()->Set(v8_str("obj"), templ->NewInstance());
2846
2847 Local<Script> script_desc = Script::Compile(v8_str("var prop ="
2848 "Object.getOwnPropertyDescriptor( "
2849 "obj, 'x');"
2850 "prop.configurable;"));
2851 Local<Value> result = script_desc->Run();
2852 CHECK_EQ(result->BooleanValue(), true);
2853
2854 Local<Script> script_define =
2855 Script::Compile(v8_str("var desc = {get: function(){return 42; },"
2856 " configurable: true };"
2857 "Object.defineProperty(obj, 'x', desc);"
2858 "obj.x"));
2859 result = script_define->Run();
2860 CHECK_EQ(result, v8_num(42));
2861
2862
2863 result = script_desc->Run();
2864 CHECK_EQ(result->BooleanValue(), true);
2865
2866
2867 script_define =
2868 Script::Compile(v8_str("var desc = {get: function(){return 43; },"
2869 " configurable: false };"
2870 "Object.defineProperty(obj, 'x', desc);"
2871 "obj.x"));
2872 result = script_define->Run();
2873 CHECK_EQ(result, v8_num(43));
2874 result = script_desc->Run();
2875
2876 CHECK_EQ(result->BooleanValue(), false);
2877
2878 v8::TryCatch try_catch;
2879 result = script_define->Run();
2880 CHECK(try_catch.HasCaught());
2881 String::AsciiValue exception_value(try_catch.Exception());
2882 CHECK_EQ(*exception_value,
2883 "TypeError: Cannot redefine property: defineProperty");
2884}
2885
2886
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002887static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
2888 char const* name) {
2889 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
2890}
ager@chromium.org5c838252010-02-19 08:53:10 +00002891
2892
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002893THREADED_TEST(DefineAPIAccessorOnObject) {
2894 v8::HandleScope scope;
2895 Local<ObjectTemplate> templ = ObjectTemplate::New();
2896 LocalContext context;
2897
2898 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
2899 CompileRun("var obj2 = {};");
2900
2901 CHECK(CompileRun("obj1.x")->IsUndefined());
2902 CHECK(CompileRun("obj2.x")->IsUndefined());
2903
2904 CHECK(GetGlobalProperty(&context, "obj1")->
2905 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2906
2907 ExpectString("obj1.x", "x");
2908 CHECK(CompileRun("obj2.x")->IsUndefined());
2909
2910 CHECK(GetGlobalProperty(&context, "obj2")->
2911 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2912
2913 ExpectString("obj1.x", "x");
2914 ExpectString("obj2.x", "x");
2915
2916 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2917 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2918
2919 CompileRun("Object.defineProperty(obj1, 'x',"
2920 "{ get: function() { return 'y'; }, configurable: true })");
2921
2922 ExpectString("obj1.x", "y");
2923 ExpectString("obj2.x", "x");
2924
2925 CompileRun("Object.defineProperty(obj2, 'x',"
2926 "{ get: function() { return 'y'; }, configurable: true })");
2927
2928 ExpectString("obj1.x", "y");
2929 ExpectString("obj2.x", "y");
2930
2931 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2932 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2933
2934 CHECK(GetGlobalProperty(&context, "obj1")->
2935 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2936 CHECK(GetGlobalProperty(&context, "obj2")->
2937 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2938
2939 ExpectString("obj1.x", "x");
2940 ExpectString("obj2.x", "x");
2941
2942 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2943 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2944
2945 // Define getters/setters, but now make them not configurable.
2946 CompileRun("Object.defineProperty(obj1, 'x',"
2947 "{ get: function() { return 'z'; }, configurable: false })");
2948 CompileRun("Object.defineProperty(obj2, 'x',"
2949 "{ get: function() { return 'z'; }, configurable: false })");
2950
2951 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2952 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2953
2954 ExpectString("obj1.x", "z");
2955 ExpectString("obj2.x", "z");
2956
2957 CHECK(!GetGlobalProperty(&context, "obj1")->
2958 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2959 CHECK(!GetGlobalProperty(&context, "obj2")->
2960 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2961
2962 ExpectString("obj1.x", "z");
2963 ExpectString("obj2.x", "z");
2964}
2965
2966
2967THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
2968 v8::HandleScope scope;
2969 Local<ObjectTemplate> templ = ObjectTemplate::New();
2970 LocalContext context;
2971
2972 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
2973 CompileRun("var obj2 = {};");
2974
2975 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
2976 v8_str("x"),
2977 GetXValue, NULL,
2978 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
2979 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
2980 v8_str("x"),
2981 GetXValue, NULL,
2982 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
2983
2984 ExpectString("obj1.x", "x");
2985 ExpectString("obj2.x", "x");
2986
2987 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2988 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2989
2990 CHECK(!GetGlobalProperty(&context, "obj1")->
2991 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2992 CHECK(!GetGlobalProperty(&context, "obj2")->
2993 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2994
2995 {
2996 v8::TryCatch try_catch;
2997 CompileRun("Object.defineProperty(obj1, 'x',"
2998 "{get: function() { return 'func'; }})");
2999 CHECK(try_catch.HasCaught());
3000 String::AsciiValue exception_value(try_catch.Exception());
3001 CHECK_EQ(*exception_value,
3002 "TypeError: Cannot redefine property: defineProperty");
3003 }
3004 {
3005 v8::TryCatch try_catch;
3006 CompileRun("Object.defineProperty(obj2, 'x',"
3007 "{get: function() { return 'func'; }})");
3008 CHECK(try_catch.HasCaught());
3009 String::AsciiValue exception_value(try_catch.Exception());
3010 CHECK_EQ(*exception_value,
3011 "TypeError: Cannot redefine property: defineProperty");
3012 }
3013}
3014
3015
3016static v8::Handle<Value> Get239Value(Local<String> name,
3017 const AccessorInfo& info) {
3018 ApiTestFuzzer::Fuzz();
3019 CHECK_EQ(info.Data(), v8_str("donut"));
3020 CHECK_EQ(name, v8_str("239"));
3021 return name;
3022}
3023
3024
3025THREADED_TEST(ElementAPIAccessor) {
3026 v8::HandleScope scope;
3027 Local<ObjectTemplate> templ = ObjectTemplate::New();
3028 LocalContext context;
3029
3030 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3031 CompileRun("var obj2 = {};");
3032
3033 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3034 v8_str("239"),
3035 Get239Value, NULL,
3036 v8_str("donut")));
3037 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3038 v8_str("239"),
3039 Get239Value, NULL,
3040 v8_str("donut")));
3041
3042 ExpectString("obj1[239]", "239");
3043 ExpectString("obj2[239]", "239");
3044 ExpectString("obj1['239']", "239");
3045 ExpectString("obj2['239']", "239");
3046}
3047
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003048
3049v8::Persistent<Value> xValue;
3050
3051
3052static void SetXValue(Local<String> name,
3053 Local<Value> value,
3054 const AccessorInfo& info) {
3055 CHECK_EQ(value, v8_num(4));
3056 CHECK_EQ(info.Data(), v8_str("donut"));
3057 CHECK_EQ(name, v8_str("x"));
3058 CHECK(xValue.IsEmpty());
3059 xValue = v8::Persistent<Value>::New(value);
3060}
3061
3062
3063THREADED_TEST(SimplePropertyWrite) {
3064 v8::HandleScope scope;
3065 Local<ObjectTemplate> templ = ObjectTemplate::New();
3066 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
3067 LocalContext context;
3068 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3069 Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
3070 for (int i = 0; i < 10; i++) {
3071 CHECK(xValue.IsEmpty());
3072 script->Run();
3073 CHECK_EQ(v8_num(4), xValue);
3074 xValue.Dispose();
3075 xValue = v8::Persistent<Value>();
3076 }
3077}
3078
3079
3080static v8::Handle<Value> XPropertyGetter(Local<String> property,
3081 const AccessorInfo& info) {
3082 ApiTestFuzzer::Fuzz();
3083 CHECK(info.Data()->IsUndefined());
3084 return property;
3085}
3086
3087
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003088THREADED_TEST(NamedInterceptorPropertyRead) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003089 v8::HandleScope scope;
3090 Local<ObjectTemplate> templ = ObjectTemplate::New();
3091 templ->SetNamedPropertyHandler(XPropertyGetter);
3092 LocalContext context;
3093 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3094 Local<Script> script = Script::Compile(v8_str("obj.x"));
3095 for (int i = 0; i < 10; i++) {
3096 Local<Value> result = script->Run();
3097 CHECK_EQ(result, v8_str("x"));
3098 }
3099}
3100
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003101
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00003102THREADED_TEST(NamedInterceptorDictionaryIC) {
3103 v8::HandleScope scope;
3104 Local<ObjectTemplate> templ = ObjectTemplate::New();
3105 templ->SetNamedPropertyHandler(XPropertyGetter);
3106 LocalContext context;
3107 // Create an object with a named interceptor.
3108 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
3109 Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
3110 for (int i = 0; i < 10; i++) {
3111 Local<Value> result = script->Run();
3112 CHECK_EQ(result, v8_str("x"));
3113 }
3114 // Create a slow case object and a function accessing a property in
3115 // that slow case object (with dictionary probing in generated
3116 // code). Then force object with a named interceptor into slow-case,
3117 // pass it to the function, and check that the interceptor is called
3118 // instead of accessing the local property.
3119 Local<Value> result =
3120 CompileRun("function get_x(o) { return o.x; };"
3121 "var obj = { x : 42, y : 0 };"
3122 "delete obj.y;"
3123 "for (var i = 0; i < 10; i++) get_x(obj);"
3124 "interceptor_obj.x = 42;"
3125 "interceptor_obj.y = 10;"
3126 "delete interceptor_obj.y;"
3127 "get_x(interceptor_obj)");
3128 CHECK_EQ(result, v8_str("x"));
3129}
3130
3131
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003132THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
3133 v8::HandleScope scope;
3134
3135 v8::Persistent<Context> context1 = Context::New();
3136
3137 context1->Enter();
3138 Local<ObjectTemplate> templ = ObjectTemplate::New();
3139 templ->SetNamedPropertyHandler(XPropertyGetter);
3140 // Create an object with a named interceptor.
3141 v8::Local<v8::Object> object = templ->NewInstance();
3142 context1->Global()->Set(v8_str("interceptor_obj"), object);
3143
3144 // Force the object into the slow case.
3145 CompileRun("interceptor_obj.y = 0;"
3146 "delete interceptor_obj.y;");
3147 context1->Exit();
3148
3149 {
3150 // Introduce the object into a different context.
3151 // Repeat named loads to exercise ICs.
3152 LocalContext context2;
3153 context2->Global()->Set(v8_str("interceptor_obj"), object);
3154 Local<Value> result =
3155 CompileRun("function get_x(o) { return o.x; }"
3156 "interceptor_obj.x = 42;"
3157 "for (var i=0; i != 10; i++) {"
3158 " get_x(interceptor_obj);"
3159 "}"
3160 "get_x(interceptor_obj)");
3161 // Check that the interceptor was actually invoked.
3162 CHECK_EQ(result, v8_str("x"));
3163 }
3164
3165 // Return to the original context and force some object to the slow case
3166 // to cause the NormalizedMapCache to verify.
3167 context1->Enter();
3168 CompileRun("var obj = { x : 0 }; delete obj.x;");
3169 context1->Exit();
3170
3171 context1.Dispose();
3172}
3173
3174
ager@chromium.org5c838252010-02-19 08:53:10 +00003175static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
3176 const AccessorInfo& info) {
3177 // Set x on the prototype object and do not handle the get request.
3178 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003179 proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
ager@chromium.org5c838252010-02-19 08:53:10 +00003180 return v8::Handle<Value>();
3181}
3182
3183
3184// This is a regression test for http://crbug.com/20104. Map
3185// transitions should not interfere with post interceptor lookup.
3186THREADED_TEST(NamedInterceptorMapTransitionRead) {
3187 v8::HandleScope scope;
3188 Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
3189 Local<v8::ObjectTemplate> instance_template
3190 = function_template->InstanceTemplate();
3191 instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
3192 LocalContext context;
3193 context->Global()->Set(v8_str("F"), function_template->GetFunction());
3194 // Create an instance of F and introduce a map transition for x.
3195 CompileRun("var o = new F(); o.x = 23;");
3196 // Create an instance of F and invoke the getter. The result should be 23.
3197 Local<Value> result = CompileRun("o = new F(); o.x");
3198 CHECK_EQ(result->Int32Value(), 23);
3199}
3200
3201
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003202static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
3203 const AccessorInfo& info) {
3204 ApiTestFuzzer::Fuzz();
3205 if (index == 37) {
3206 return v8::Handle<Value>(v8_num(625));
3207 }
3208 return v8::Handle<Value>();
3209}
3210
3211
3212static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
3213 Local<Value> value,
3214 const AccessorInfo& info) {
3215 ApiTestFuzzer::Fuzz();
3216 if (index == 39) {
3217 return value;
3218 }
3219 return v8::Handle<Value>();
3220}
3221
3222
3223THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
3224 v8::HandleScope scope;
3225 Local<ObjectTemplate> templ = ObjectTemplate::New();
3226 templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
3227 IndexedPropertySetter);
3228 LocalContext context;
3229 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3230 Local<Script> getter_script = Script::Compile(v8_str(
3231 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
3232 Local<Script> setter_script = Script::Compile(v8_str(
3233 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
3234 "obj[17] = 23;"
3235 "obj.foo;"));
3236 Local<Script> interceptor_setter_script = Script::Compile(v8_str(
3237 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
3238 "obj[39] = 47;"
3239 "obj.foo;")); // This setter should not run, due to the interceptor.
3240 Local<Script> interceptor_getter_script = Script::Compile(v8_str(
3241 "obj[37];"));
3242 Local<Value> result = getter_script->Run();
3243 CHECK_EQ(v8_num(5), result);
3244 result = setter_script->Run();
3245 CHECK_EQ(v8_num(23), result);
3246 result = interceptor_setter_script->Run();
3247 CHECK_EQ(v8_num(23), result);
3248 result = interceptor_getter_script->Run();
3249 CHECK_EQ(v8_num(625), result);
3250}
3251
3252
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00003253static v8::Handle<Value> IdentityIndexedPropertyGetter(
3254 uint32_t index,
3255 const AccessorInfo& info) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003256 return v8::Integer::NewFromUnsigned(index);
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00003257}
3258
3259
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003260THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
3261 v8::HandleScope scope;
3262 Local<ObjectTemplate> templ = ObjectTemplate::New();
3263 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3264
3265 LocalContext context;
3266 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3267
3268 // Check fast object case.
3269 const char* fast_case_code =
3270 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
3271 ExpectString(fast_case_code, "0");
3272
3273 // Check slow case.
3274 const char* slow_case_code =
3275 "obj.x = 1; delete obj.x;"
3276 "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
3277 ExpectString(slow_case_code, "1");
3278}
3279
3280
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00003281THREADED_TEST(IndexedInterceptorWithNoSetter) {
3282 v8::HandleScope scope;
3283 Local<ObjectTemplate> templ = ObjectTemplate::New();
3284 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3285
3286 LocalContext context;
3287 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3288
3289 const char* code =
3290 "try {"
3291 " obj[0] = 239;"
3292 " for (var i = 0; i < 100; i++) {"
3293 " var v = obj[0];"
3294 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
3295 " }"
3296 " 'PASSED'"
3297 "} catch(e) {"
3298 " e"
3299 "}";
3300 ExpectString(code, "PASSED");
3301}
3302
3303
ager@chromium.org5c838252010-02-19 08:53:10 +00003304THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
3305 v8::HandleScope scope;
3306 Local<ObjectTemplate> templ = ObjectTemplate::New();
3307 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3308
3309 LocalContext context;
3310 Local<v8::Object> obj = templ->NewInstance();
3311 obj->TurnOnAccessCheck();
3312 context->Global()->Set(v8_str("obj"), obj);
3313
3314 const char* code =
3315 "try {"
3316 " for (var i = 0; i < 100; i++) {"
3317 " var v = obj[0];"
3318 " if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
3319 " }"
3320 " 'PASSED'"
3321 "} catch(e) {"
3322 " e"
3323 "}";
3324 ExpectString(code, "PASSED");
3325}
3326
3327
3328THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
3329 i::FLAG_allow_natives_syntax = true;
3330 v8::HandleScope scope;
3331 Local<ObjectTemplate> templ = ObjectTemplate::New();
3332 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3333
3334 LocalContext context;
3335 Local<v8::Object> obj = templ->NewInstance();
3336 context->Global()->Set(v8_str("obj"), obj);
3337
3338 const char* code =
3339 "try {"
3340 " for (var i = 0; i < 100; i++) {"
3341 " var expected = i;"
3342 " if (i == 5) {"
3343 " %EnableAccessChecks(obj);"
3344 " expected = undefined;"
3345 " }"
3346 " var v = obj[i];"
3347 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3348 " if (i == 5) %DisableAccessChecks(obj);"
3349 " }"
3350 " 'PASSED'"
3351 "} catch(e) {"
3352 " e"
3353 "}";
3354 ExpectString(code, "PASSED");
3355}
3356
3357
3358THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
3359 v8::HandleScope scope;
3360 Local<ObjectTemplate> templ = ObjectTemplate::New();
3361 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3362
3363 LocalContext context;
3364 Local<v8::Object> obj = templ->NewInstance();
3365 context->Global()->Set(v8_str("obj"), obj);
3366
3367 const char* code =
3368 "try {"
3369 " for (var i = 0; i < 100; i++) {"
3370 " var v = obj[i];"
3371 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
3372 " }"
3373 " 'PASSED'"
3374 "} catch(e) {"
3375 " e"
3376 "}";
3377 ExpectString(code, "PASSED");
3378}
3379
3380
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003381THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
3382 v8::HandleScope scope;
3383 Local<ObjectTemplate> templ = ObjectTemplate::New();
3384 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3385
3386 LocalContext context;
3387 Local<v8::Object> obj = templ->NewInstance();
3388 context->Global()->Set(v8_str("obj"), obj);
3389
3390 const char* code =
3391 "try {"
3392 " for (var i = 0; i < 100; i++) {"
3393 " var expected = i;"
3394 " var key = i;"
3395 " if (i == 25) {"
3396 " key = -1;"
3397 " expected = undefined;"
3398 " }"
3399 " if (i == 50) {"
3400 " /* probe minimal Smi number on 32-bit platforms */"
3401 " key = -(1 << 30);"
3402 " expected = undefined;"
3403 " }"
3404 " if (i == 75) {"
3405 " /* probe minimal Smi number on 64-bit platforms */"
3406 " key = 1 << 31;"
3407 " expected = undefined;"
3408 " }"
3409 " var v = obj[key];"
3410 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3411 " }"
3412 " 'PASSED'"
3413 "} catch(e) {"
3414 " e"
3415 "}";
3416 ExpectString(code, "PASSED");
3417}
3418
3419
ager@chromium.org5c838252010-02-19 08:53:10 +00003420THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
3421 v8::HandleScope scope;
3422 Local<ObjectTemplate> templ = ObjectTemplate::New();
3423 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3424
3425 LocalContext context;
3426 Local<v8::Object> obj = templ->NewInstance();
3427 context->Global()->Set(v8_str("obj"), obj);
3428
3429 const char* code =
3430 "try {"
3431 " for (var i = 0; i < 100; i++) {"
3432 " var expected = i;"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003433 " var key = i;"
ager@chromium.org5c838252010-02-19 08:53:10 +00003434 " if (i == 50) {"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003435 " key = 'foobar';"
ager@chromium.org5c838252010-02-19 08:53:10 +00003436 " expected = undefined;"
3437 " }"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003438 " var v = obj[key];"
ager@chromium.org5c838252010-02-19 08:53:10 +00003439 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3440 " }"
3441 " 'PASSED'"
3442 "} catch(e) {"
3443 " e"
3444 "}";
3445 ExpectString(code, "PASSED");
3446}
3447
3448
3449THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
3450 v8::HandleScope scope;
3451 Local<ObjectTemplate> templ = ObjectTemplate::New();
3452 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3453
3454 LocalContext context;
3455 Local<v8::Object> obj = templ->NewInstance();
3456 context->Global()->Set(v8_str("obj"), obj);
3457
3458 const char* code =
3459 "var original = obj;"
3460 "try {"
3461 " for (var i = 0; i < 100; i++) {"
3462 " var expected = i;"
3463 " if (i == 50) {"
3464 " obj = {50: 'foobar'};"
3465 " expected = 'foobar';"
3466 " }"
3467 " var v = obj[i];"
3468 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3469 " if (i == 50) obj = original;"
3470 " }"
3471 " 'PASSED'"
3472 "} catch(e) {"
3473 " e"
3474 "}";
3475 ExpectString(code, "PASSED");
3476}
3477
3478
3479THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
3480 v8::HandleScope scope;
3481 Local<ObjectTemplate> templ = ObjectTemplate::New();
3482 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3483
3484 LocalContext context;
3485 Local<v8::Object> obj = templ->NewInstance();
3486 context->Global()->Set(v8_str("obj"), obj);
3487
3488 const char* code =
3489 "var original = obj;"
3490 "try {"
3491 " for (var i = 0; i < 100; i++) {"
3492 " var expected = i;"
3493 " if (i == 5) {"
3494 " obj = 239;"
3495 " expected = undefined;"
3496 " }"
3497 " var v = obj[i];"
3498 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3499 " if (i == 5) obj = original;"
3500 " }"
3501 " 'PASSED'"
3502 "} catch(e) {"
3503 " e"
3504 "}";
3505 ExpectString(code, "PASSED");
3506}
3507
3508
3509THREADED_TEST(IndexedInterceptorOnProto) {
3510 v8::HandleScope scope;
3511 Local<ObjectTemplate> templ = ObjectTemplate::New();
3512 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3513
3514 LocalContext context;
3515 Local<v8::Object> obj = templ->NewInstance();
3516 context->Global()->Set(v8_str("obj"), obj);
3517
3518 const char* code =
3519 "var o = {__proto__: obj};"
3520 "try {"
3521 " for (var i = 0; i < 100; i++) {"
3522 " var v = o[i];"
3523 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
3524 " }"
3525 " 'PASSED'"
3526 "} catch(e) {"
3527 " e"
3528 "}";
3529 ExpectString(code, "PASSED");
3530}
3531
3532
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003533THREADED_TEST(MultiContexts) {
3534 v8::HandleScope scope;
3535 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
3536 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
3537
3538 Local<String> password = v8_str("Password");
3539
3540 // Create an environment
3541 LocalContext context0(0, templ);
3542 context0->SetSecurityToken(password);
3543 v8::Handle<v8::Object> global0 = context0->Global();
3544 global0->Set(v8_str("custom"), v8_num(1234));
3545 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
3546
3547 // Create an independent environment
3548 LocalContext context1(0, templ);
3549 context1->SetSecurityToken(password);
3550 v8::Handle<v8::Object> global1 = context1->Global();
3551 global1->Set(v8_str("custom"), v8_num(1234));
3552 CHECK_NE(global0, global1);
3553 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
3554 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
3555
3556 // Now create a new context with the old global
3557 LocalContext context2(0, templ, global1);
3558 context2->SetSecurityToken(password);
3559 v8::Handle<v8::Object> global2 = context2->Global();
3560 CHECK_EQ(global1, global2);
3561 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
3562 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
3563}
3564
3565
3566THREADED_TEST(FunctionPrototypeAcrossContexts) {
3567 // Make sure that functions created by cloning boilerplates cannot
3568 // communicate through their __proto__ field.
3569
3570 v8::HandleScope scope;
3571
3572 LocalContext env0;
3573 v8::Handle<v8::Object> global0 =
3574 env0->Global();
3575 v8::Handle<v8::Object> object0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003576 global0->Get(v8_str("Object")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003577 v8::Handle<v8::Object> tostring0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003578 object0->Get(v8_str("toString")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003579 v8::Handle<v8::Object> proto0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003580 tostring0->Get(v8_str("__proto__")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003581 proto0->Set(v8_str("custom"), v8_num(1234));
3582
3583 LocalContext env1;
3584 v8::Handle<v8::Object> global1 =
3585 env1->Global();
3586 v8::Handle<v8::Object> object1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003587 global1->Get(v8_str("Object")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003588 v8::Handle<v8::Object> tostring1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003589 object1->Get(v8_str("toString")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003590 v8::Handle<v8::Object> proto1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003591 tostring1->Get(v8_str("__proto__")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003592 CHECK(!proto1->Has(v8_str("custom")));
3593}
3594
3595
3596THREADED_TEST(Regress892105) {
3597 // Make sure that object and array literals created by cloning
3598 // boilerplates cannot communicate through their __proto__
3599 // field. This is rather difficult to check, but we try to add stuff
3600 // to Object.prototype and Array.prototype and create a new
3601 // environment. This should succeed.
3602
3603 v8::HandleScope scope;
3604
3605 Local<String> source = v8_str("Object.prototype.obj = 1234;"
3606 "Array.prototype.arr = 4567;"
3607 "8901");
3608
3609 LocalContext env0;
3610 Local<Script> script0 = Script::Compile(source);
3611 CHECK_EQ(8901.0, script0->Run()->NumberValue());
3612
3613 LocalContext env1;
3614 Local<Script> script1 = Script::Compile(source);
3615 CHECK_EQ(8901.0, script1->Run()->NumberValue());
3616}
3617
3618
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003619THREADED_TEST(UndetectableObject) {
3620 v8::HandleScope scope;
3621 LocalContext env;
3622
3623 Local<v8::FunctionTemplate> desc =
3624 v8::FunctionTemplate::New(0, v8::Handle<Value>());
3625 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
3626
3627 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
3628 env->Global()->Set(v8_str("undetectable"), obj);
3629
3630 ExpectString("undetectable.toString()", "[object Object]");
3631 ExpectString("typeof undetectable", "undefined");
3632 ExpectString("typeof(undetectable)", "undefined");
3633 ExpectBoolean("typeof undetectable == 'undefined'", true);
3634 ExpectBoolean("typeof undetectable == 'object'", false);
3635 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
3636 ExpectBoolean("!undetectable", true);
3637
3638 ExpectObject("true&&undetectable", obj);
3639 ExpectBoolean("false&&undetectable", false);
3640 ExpectBoolean("true||undetectable", true);
3641 ExpectObject("false||undetectable", obj);
3642
3643 ExpectObject("undetectable&&true", obj);
3644 ExpectObject("undetectable&&false", obj);
3645 ExpectBoolean("undetectable||true", true);
3646 ExpectBoolean("undetectable||false", false);
3647
3648 ExpectBoolean("undetectable==null", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00003649 ExpectBoolean("null==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003650 ExpectBoolean("undetectable==undefined", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00003651 ExpectBoolean("undefined==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003652 ExpectBoolean("undetectable==undetectable", true);
3653
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00003654
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003655 ExpectBoolean("undetectable===null", false);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00003656 ExpectBoolean("null===undetectable", false);
3657 ExpectBoolean("undetectable===undefined", false);
3658 ExpectBoolean("undefined===undetectable", false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003659 ExpectBoolean("undetectable===undetectable", true);
3660}
3661
3662
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00003663
3664THREADED_TEST(ExtensibleOnUndetectable) {
3665 v8::HandleScope scope;
3666 LocalContext env;
3667
3668 Local<v8::FunctionTemplate> desc =
3669 v8::FunctionTemplate::New(0, v8::Handle<Value>());
3670 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
3671
3672 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
3673 env->Global()->Set(v8_str("undetectable"), obj);
3674
3675 Local<String> source = v8_str("undetectable.x = 42;"
3676 "undetectable.x");
3677
3678 Local<Script> script = Script::Compile(source);
3679
3680 CHECK_EQ(v8::Integer::New(42), script->Run());
3681
3682 ExpectBoolean("Object.isExtensible(undetectable)", true);
3683
3684 source = v8_str("Object.preventExtensions(undetectable);");
3685 script = Script::Compile(source);
3686 script->Run();
3687 ExpectBoolean("Object.isExtensible(undetectable)", false);
3688
3689 source = v8_str("undetectable.y = 2000;");
3690 script = Script::Compile(source);
3691 v8::TryCatch try_catch;
3692 Local<Value> result = script->Run();
3693 CHECK(result.IsEmpty());
3694 CHECK(try_catch.HasCaught());
3695}
3696
3697
3698
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003699THREADED_TEST(UndetectableString) {
3700 v8::HandleScope scope;
3701 LocalContext env;
3702
3703 Local<String> obj = String::NewUndetectable("foo");
3704 env->Global()->Set(v8_str("undetectable"), obj);
3705
3706 ExpectString("undetectable", "foo");
3707 ExpectString("typeof undetectable", "undefined");
3708 ExpectString("typeof(undetectable)", "undefined");
3709 ExpectBoolean("typeof undetectable == 'undefined'", true);
3710 ExpectBoolean("typeof undetectable == 'string'", false);
3711 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
3712 ExpectBoolean("!undetectable", true);
3713
3714 ExpectObject("true&&undetectable", obj);
3715 ExpectBoolean("false&&undetectable", false);
3716 ExpectBoolean("true||undetectable", true);
3717 ExpectObject("false||undetectable", obj);
3718
3719 ExpectObject("undetectable&&true", obj);
3720 ExpectObject("undetectable&&false", obj);
3721 ExpectBoolean("undetectable||true", true);
3722 ExpectBoolean("undetectable||false", false);
3723
3724 ExpectBoolean("undetectable==null", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00003725 ExpectBoolean("null==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003726 ExpectBoolean("undetectable==undefined", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00003727 ExpectBoolean("undefined==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003728 ExpectBoolean("undetectable==undetectable", true);
3729
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00003730
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003731 ExpectBoolean("undetectable===null", false);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00003732 ExpectBoolean("null===undetectable", false);
3733 ExpectBoolean("undetectable===undefined", false);
3734 ExpectBoolean("undefined===undetectable", false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003735 ExpectBoolean("undetectable===undetectable", true);
3736}
3737
3738
3739template <typename T> static void USE(T) { }
3740
3741
3742// This test is not intended to be run, just type checked.
3743static void PersistentHandles() {
3744 USE(PersistentHandles);
3745 Local<String> str = v8_str("foo");
3746 v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
3747 USE(p_str);
3748 Local<Script> scr = Script::Compile(v8_str(""));
3749 v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
3750 USE(p_scr);
3751 Local<ObjectTemplate> templ = ObjectTemplate::New();
3752 v8::Persistent<ObjectTemplate> p_templ =
3753 v8::Persistent<ObjectTemplate>::New(templ);
3754 USE(p_templ);
3755}
3756
3757
3758static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
3759 ApiTestFuzzer::Fuzz();
3760 return v8::Undefined();
3761}
3762
3763
3764THREADED_TEST(GlobalObjectTemplate) {
3765 v8::HandleScope handle_scope;
3766 Local<ObjectTemplate> global_template = ObjectTemplate::New();
3767 global_template->Set(v8_str("JSNI_Log"),
3768 v8::FunctionTemplate::New(HandleLogDelegator));
3769 v8::Persistent<Context> context = Context::New(0, global_template);
3770 Context::Scope context_scope(context);
3771 Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
3772 context.Dispose();
3773}
3774
3775
3776static const char* kSimpleExtensionSource =
3777 "function Foo() {"
3778 " return 4;"
3779 "}";
3780
3781
3782THREADED_TEST(SimpleExtensions) {
3783 v8::HandleScope handle_scope;
3784 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
3785 const char* extension_names[] = { "simpletest" };
3786 v8::ExtensionConfiguration extensions(1, extension_names);
3787 v8::Handle<Context> context = Context::New(&extensions);
3788 Context::Scope lock(context);
3789 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
3790 CHECK_EQ(result, v8::Integer::New(4));
3791}
3792
3793
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003794static const char* kEvalExtensionSource1 =
3795 "function UseEval1() {"
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00003796 " var x = 42;"
3797 " return eval('x');"
3798 "}";
3799
3800
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003801static const char* kEvalExtensionSource2 =
3802 "(function() {"
3803 " var x = 42;"
3804 " function e() {"
3805 " return eval('x');"
3806 " }"
3807 " this.UseEval2 = e;"
3808 "})()";
3809
3810
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00003811THREADED_TEST(UseEvalFromExtension) {
3812 v8::HandleScope handle_scope;
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003813 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
3814 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
3815 const char* extension_names[] = { "evaltest1", "evaltest2" };
3816 v8::ExtensionConfiguration extensions(2, extension_names);
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00003817 v8::Handle<Context> context = Context::New(&extensions);
3818 Context::Scope lock(context);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003819 v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
3820 CHECK_EQ(result, v8::Integer::New(42));
3821 result = Script::Compile(v8_str("UseEval2()"))->Run();
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00003822 CHECK_EQ(result, v8::Integer::New(42));
3823}
3824
3825
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003826static const char* kWithExtensionSource1 =
3827 "function UseWith1() {"
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00003828 " var x = 42;"
3829 " with({x:87}) { return x; }"
3830 "}";
3831
3832
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003833
3834static const char* kWithExtensionSource2 =
3835 "(function() {"
3836 " var x = 42;"
3837 " function e() {"
3838 " with ({x:87}) { return x; }"
3839 " }"
3840 " this.UseWith2 = e;"
3841 "})()";
3842
3843
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00003844THREADED_TEST(UseWithFromExtension) {
3845 v8::HandleScope handle_scope;
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003846 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
3847 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
3848 const char* extension_names[] = { "withtest1", "withtest2" };
3849 v8::ExtensionConfiguration extensions(2, extension_names);
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00003850 v8::Handle<Context> context = Context::New(&extensions);
3851 Context::Scope lock(context);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003852 v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
3853 CHECK_EQ(result, v8::Integer::New(87));
3854 result = Script::Compile(v8_str("UseWith2()"))->Run();
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00003855 CHECK_EQ(result, v8::Integer::New(87));
3856}
3857
3858
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003859THREADED_TEST(AutoExtensions) {
3860 v8::HandleScope handle_scope;
3861 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
3862 extension->set_auto_enable(true);
3863 v8::RegisterExtension(extension);
3864 v8::Handle<Context> context = Context::New();
3865 Context::Scope lock(context);
3866 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
3867 CHECK_EQ(result, v8::Integer::New(4));
3868}
3869
3870
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003871static const char* kSyntaxErrorInExtensionSource =
3872 "[";
3873
3874
3875// Test that a syntax error in an extension does not cause a fatal
3876// error but results in an empty context.
3877THREADED_TEST(SyntaxErrorExtensions) {
3878 v8::HandleScope handle_scope;
3879 v8::RegisterExtension(new Extension("syntaxerror",
3880 kSyntaxErrorInExtensionSource));
3881 const char* extension_names[] = { "syntaxerror" };
3882 v8::ExtensionConfiguration extensions(1, extension_names);
3883 v8::Handle<Context> context = Context::New(&extensions);
3884 CHECK(context.IsEmpty());
3885}
3886
3887
3888static const char* kExceptionInExtensionSource =
3889 "throw 42";
3890
3891
3892// Test that an exception when installing an extension does not cause
3893// a fatal error but results in an empty context.
3894THREADED_TEST(ExceptionExtensions) {
3895 v8::HandleScope handle_scope;
3896 v8::RegisterExtension(new Extension("exception",
3897 kExceptionInExtensionSource));
3898 const char* extension_names[] = { "exception" };
3899 v8::ExtensionConfiguration extensions(1, extension_names);
3900 v8::Handle<Context> context = Context::New(&extensions);
3901 CHECK(context.IsEmpty());
3902}
3903
3904
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00003905static const char* kNativeCallInExtensionSource =
3906 "function call_runtime_last_index_of(x) {"
3907 " return %StringLastIndexOf(x, 'bob', 10);"
3908 "}";
3909
3910
3911static const char* kNativeCallTest =
3912 "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
3913
3914// Test that a native runtime calls are supported in extensions.
3915THREADED_TEST(NativeCallInExtensions) {
3916 v8::HandleScope handle_scope;
3917 v8::RegisterExtension(new Extension("nativecall",
3918 kNativeCallInExtensionSource));
3919 const char* extension_names[] = { "nativecall" };
3920 v8::ExtensionConfiguration extensions(1, extension_names);
3921 v8::Handle<Context> context = Context::New(&extensions);
3922 Context::Scope lock(context);
3923 v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run();
3924 CHECK_EQ(result, v8::Integer::New(3));
3925}
3926
3927
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003928static void CheckDependencies(const char* name, const char* expected) {
3929 v8::HandleScope handle_scope;
3930 v8::ExtensionConfiguration config(1, &name);
3931 LocalContext context(&config);
3932 CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
3933}
3934
3935
3936/*
3937 * Configuration:
3938 *
3939 * /-- B <--\
3940 * A <- -- D <-- E
3941 * \-- C <--/
3942 */
3943THREADED_TEST(ExtensionDependency) {
3944 static const char* kEDeps[] = { "D" };
3945 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
3946 static const char* kDDeps[] = { "B", "C" };
3947 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
3948 static const char* kBCDeps[] = { "A" };
3949 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
3950 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
3951 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
3952 CheckDependencies("A", "undefinedA");
3953 CheckDependencies("B", "undefinedAB");
3954 CheckDependencies("C", "undefinedAC");
3955 CheckDependencies("D", "undefinedABCD");
3956 CheckDependencies("E", "undefinedABCDE");
3957 v8::HandleScope handle_scope;
3958 static const char* exts[2] = { "C", "E" };
3959 v8::ExtensionConfiguration config(2, exts);
3960 LocalContext context(&config);
3961 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
3962}
3963
3964
3965static const char* kExtensionTestScript =
3966 "native function A();"
3967 "native function B();"
3968 "native function C();"
3969 "function Foo(i) {"
3970 " if (i == 0) return A();"
3971 " if (i == 1) return B();"
3972 " if (i == 2) return C();"
3973 "}";
3974
3975
3976static v8::Handle<Value> CallFun(const v8::Arguments& args) {
3977 ApiTestFuzzer::Fuzz();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003978 if (args.IsConstructCall()) {
3979 args.This()->Set(v8_str("data"), args.Data());
3980 return v8::Null();
3981 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003982 return args.Data();
3983}
3984
3985
3986class FunctionExtension : public Extension {
3987 public:
3988 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
3989 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
3990 v8::Handle<String> name);
3991};
3992
3993
3994static int lookup_count = 0;
3995v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
3996 v8::Handle<String> name) {
3997 lookup_count++;
3998 if (name->Equals(v8_str("A"))) {
3999 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
4000 } else if (name->Equals(v8_str("B"))) {
4001 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
4002 } else if (name->Equals(v8_str("C"))) {
4003 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
4004 } else {
4005 return v8::Handle<v8::FunctionTemplate>();
4006 }
4007}
4008
4009
4010THREADED_TEST(FunctionLookup) {
4011 v8::RegisterExtension(new FunctionExtension());
4012 v8::HandleScope handle_scope;
4013 static const char* exts[1] = { "functiontest" };
4014 v8::ExtensionConfiguration config(1, exts);
4015 LocalContext context(&config);
4016 CHECK_EQ(3, lookup_count);
4017 CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
4018 CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
4019 CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
4020}
4021
4022
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004023THREADED_TEST(NativeFunctionConstructCall) {
4024 v8::RegisterExtension(new FunctionExtension());
4025 v8::HandleScope handle_scope;
4026 static const char* exts[1] = { "functiontest" };
4027 v8::ExtensionConfiguration config(1, exts);
4028 LocalContext context(&config);
4029 for (int i = 0; i < 10; i++) {
4030 // Run a few times to ensure that allocation of objects doesn't
4031 // change behavior of a constructor function.
4032 CHECK_EQ(v8::Integer::New(8),
4033 Script::Compile(v8_str("(new A()).data"))->Run());
4034 CHECK_EQ(v8::Integer::New(7),
4035 Script::Compile(v8_str("(new B()).data"))->Run());
4036 CHECK_EQ(v8::Integer::New(6),
4037 Script::Compile(v8_str("(new C()).data"))->Run());
4038 }
4039}
4040
4041
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004042static const char* last_location;
4043static const char* last_message;
4044void StoringErrorCallback(const char* location, const char* message) {
4045 if (last_location == NULL) {
4046 last_location = location;
4047 last_message = message;
4048 }
4049}
4050
4051
4052// ErrorReporting creates a circular extensions configuration and
4053// tests that the fatal error handler gets called. This renders V8
4054// unusable and therefore this test cannot be run in parallel.
4055TEST(ErrorReporting) {
4056 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
4057 static const char* aDeps[] = { "B" };
4058 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
4059 static const char* bDeps[] = { "A" };
4060 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
4061 last_location = NULL;
4062 v8::ExtensionConfiguration config(1, bDeps);
4063 v8::Handle<Context> context = Context::New(&config);
4064 CHECK(context.IsEmpty());
4065 CHECK_NE(last_location, NULL);
4066}
4067
4068
ager@chromium.org7c537e22008-10-16 08:43:32 +00004069static const char* js_code_causing_huge_string_flattening =
4070 "var str = 'X';"
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00004071 "for (var i = 0; i < 30; i++) {"
ager@chromium.org7c537e22008-10-16 08:43:32 +00004072 " str = str + str;"
4073 "}"
4074 "str.match(/X/);";
4075
4076
4077void OOMCallback(const char* location, const char* message) {
4078 exit(0);
4079}
4080
4081
4082TEST(RegexpOutOfMemory) {
4083 // Execute a script that causes out of memory when flattening a string.
4084 v8::HandleScope scope;
4085 v8::V8::SetFatalErrorHandler(OOMCallback);
4086 LocalContext context;
4087 Local<Script> script =
4088 Script::Compile(String::New(js_code_causing_huge_string_flattening));
4089 last_location = NULL;
4090 Local<Value> result = script->Run();
4091
4092 CHECK(false); // Should not return.
4093}
4094
4095
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004096static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
4097 v8::Handle<Value> data) {
4098 CHECK_EQ(v8::Undefined(), data);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004099 CHECK(message->GetScriptResourceName()->IsUndefined());
4100 CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004101 message->GetLineNumber();
4102 message->GetSourceLine();
4103}
4104
4105
4106THREADED_TEST(ErrorWithMissingScriptInfo) {
4107 v8::HandleScope scope;
4108 LocalContext context;
4109 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
4110 Script::Compile(v8_str("throw Error()"))->Run();
4111 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
4112}
4113
4114
4115int global_index = 0;
4116
4117class Snorkel {
4118 public:
4119 Snorkel() { index_ = global_index++; }
4120 int index_;
4121};
4122
4123class Whammy {
4124 public:
4125 Whammy() {
4126 cursor_ = 0;
4127 }
4128 ~Whammy() {
4129 script_.Dispose();
4130 }
4131 v8::Handle<Script> getScript() {
4132 if (script_.IsEmpty())
4133 script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
4134 return Local<Script>(*script_);
4135 }
4136
4137 public:
4138 static const int kObjectCount = 256;
4139 int cursor_;
4140 v8::Persistent<v8::Object> objects_[kObjectCount];
4141 v8::Persistent<Script> script_;
4142};
4143
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004144static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004145 Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
4146 delete snorkel;
4147 obj.ClearWeak();
4148}
4149
4150v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
4151 const AccessorInfo& info) {
4152 Whammy* whammy =
4153 static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
4154
4155 v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
4156
4157 v8::Handle<v8::Object> obj = v8::Object::New();
4158 v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
4159 if (!prev.IsEmpty()) {
4160 prev->Set(v8_str("next"), obj);
4161 prev.MakeWeak(new Snorkel(), &HandleWeakReference);
4162 whammy->objects_[whammy->cursor_].Clear();
4163 }
4164 whammy->objects_[whammy->cursor_] = global;
4165 whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
4166 return whammy->getScript()->Run();
4167}
4168
4169THREADED_TEST(WeakReference) {
4170 v8::HandleScope handle_scope;
4171 v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00004172 Whammy* whammy = new Whammy();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004173 templ->SetNamedPropertyHandler(WhammyPropertyGetter,
4174 0, 0, 0, 0,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00004175 v8::External::New(whammy));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004176 const char* extension_list[] = { "v8/gc" };
4177 v8::ExtensionConfiguration extensions(1, extension_list);
4178 v8::Persistent<Context> context = Context::New(&extensions);
4179 Context::Scope context_scope(context);
4180
4181 v8::Handle<v8::Object> interceptor = templ->NewInstance();
4182 context->Global()->Set(v8_str("whammy"), interceptor);
4183 const char* code =
4184 "var last;"
4185 "for (var i = 0; i < 10000; i++) {"
4186 " var obj = whammy.length;"
4187 " if (last) last.next = obj;"
4188 " last = obj;"
4189 "}"
4190 "gc();"
4191 "4";
4192 v8::Handle<Value> result = CompileRun(code);
4193 CHECK_EQ(4.0, result->NumberValue());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00004194 delete whammy;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004195 context.Dispose();
4196}
4197
4198
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004199static bool in_scavenge = false;
4200static int last = -1;
4201
4202static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
4203 CHECK_EQ(-1, last);
4204 last = 0;
4205 obj.Dispose();
4206 obj.Clear();
4207 in_scavenge = true;
4208 i::Heap::PerformScavenge();
4209 in_scavenge = false;
4210 *(reinterpret_cast<bool*>(data)) = true;
4211}
4212
4213static void CheckIsNotInvokedInScavenge(v8::Persistent<v8::Value> obj,
4214 void* data) {
4215 CHECK_EQ(0, last);
4216 last = 1;
4217 *(reinterpret_cast<bool*>(data)) = in_scavenge;
4218 obj.Dispose();
4219 obj.Clear();
4220}
4221
4222THREADED_TEST(NoWeakRefCallbacksInScavenge) {
4223 // Test verifies that scavenge cannot invoke WeakReferenceCallbacks.
4224 // Calling callbacks from scavenges is unsafe as objects held by those
4225 // handlers might have become strongly reachable, but scavenge doesn't
4226 // check that.
4227 v8::Persistent<Context> context = Context::New();
4228 Context::Scope context_scope(context);
4229
4230 v8::Persistent<v8::Object> object_a;
4231 v8::Persistent<v8::Object> object_b;
4232
4233 {
4234 v8::HandleScope handle_scope;
4235 object_b = v8::Persistent<v8::Object>::New(v8::Object::New());
4236 object_a = v8::Persistent<v8::Object>::New(v8::Object::New());
4237 }
4238
4239 bool object_a_disposed = false;
4240 object_a.MakeWeak(&object_a_disposed, &ForceScavenge);
4241 bool released_in_scavenge = false;
4242 object_b.MakeWeak(&released_in_scavenge, &CheckIsNotInvokedInScavenge);
4243
4244 while (!object_a_disposed) {
4245 i::Heap::CollectAllGarbage(false);
4246 }
4247 CHECK(!released_in_scavenge);
4248}
4249
4250
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004251v8::Handle<Function> args_fun;
4252
4253
4254static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
4255 ApiTestFuzzer::Fuzz();
4256 CHECK_EQ(args_fun, args.Callee());
4257 CHECK_EQ(3, args.Length());
4258 CHECK_EQ(v8::Integer::New(1), args[0]);
4259 CHECK_EQ(v8::Integer::New(2), args[1]);
4260 CHECK_EQ(v8::Integer::New(3), args[2]);
4261 CHECK_EQ(v8::Undefined(), args[3]);
4262 v8::HandleScope scope;
ager@chromium.orgab99eea2009-08-25 07:05:41 +00004263 i::Heap::CollectAllGarbage(false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004264 return v8::Undefined();
4265}
4266
4267
4268THREADED_TEST(Arguments) {
4269 v8::HandleScope scope;
4270 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
4271 global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
4272 LocalContext context(NULL, global);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004273 args_fun = context->Global()->Get(v8_str("f")).As<Function>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004274 v8_compile("f(1, 2, 3)")->Run();
4275}
4276
4277
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004278static v8::Handle<Value> NoBlockGetterX(Local<String> name,
4279 const AccessorInfo&) {
4280 return v8::Handle<Value>();
4281}
4282
4283
4284static v8::Handle<Value> NoBlockGetterI(uint32_t index,
4285 const AccessorInfo&) {
4286 return v8::Handle<Value>();
4287}
4288
4289
4290static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
4291 const AccessorInfo&) {
4292 if (!name->Equals(v8_str("foo"))) {
4293 return v8::Handle<v8::Boolean>(); // not intercepted
4294 }
4295
4296 return v8::False(); // intercepted, and don't delete the property
4297}
4298
4299
4300static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
4301 if (index != 2) {
4302 return v8::Handle<v8::Boolean>(); // not intercepted
4303 }
4304
4305 return v8::False(); // intercepted, and don't delete the property
4306}
4307
4308
4309THREADED_TEST(Deleter) {
4310 v8::HandleScope scope;
4311 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4312 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
4313 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
4314 LocalContext context;
4315 context->Global()->Set(v8_str("k"), obj->NewInstance());
4316 CompileRun(
4317 "k.foo = 'foo';"
4318 "k.bar = 'bar';"
4319 "k[2] = 2;"
4320 "k[4] = 4;");
4321 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
4322 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
4323
4324 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
4325 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
4326
4327 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
4328 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
4329
4330 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
4331 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
4332}
4333
4334
4335static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
4336 ApiTestFuzzer::Fuzz();
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004337 if (name->Equals(v8_str("foo")) ||
4338 name->Equals(v8_str("bar")) ||
4339 name->Equals(v8_str("baz"))) {
4340 return v8::Undefined();
4341 }
4342 return v8::Handle<Value>();
4343}
4344
4345
4346static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
4347 ApiTestFuzzer::Fuzz();
4348 if (index == 0 || index == 1) return v8::Undefined();
4349 return v8::Handle<Value>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004350}
4351
4352
4353static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
4354 ApiTestFuzzer::Fuzz();
4355 v8::Handle<v8::Array> result = v8::Array::New(3);
4356 result->Set(v8::Integer::New(0), v8_str("foo"));
4357 result->Set(v8::Integer::New(1), v8_str("bar"));
4358 result->Set(v8::Integer::New(2), v8_str("baz"));
4359 return result;
4360}
4361
4362
4363static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
4364 ApiTestFuzzer::Fuzz();
4365 v8::Handle<v8::Array> result = v8::Array::New(2);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004366 result->Set(v8::Integer::New(0), v8_str("0"));
4367 result->Set(v8::Integer::New(1), v8_str("1"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004368 return result;
4369}
4370
4371
4372THREADED_TEST(Enumerators) {
4373 v8::HandleScope scope;
4374 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4375 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004376 obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004377 LocalContext context;
4378 context->Global()->Set(v8_str("k"), obj->NewInstance());
4379 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004380 "k[10] = 0;"
4381 "k.a = 0;"
4382 "k[5] = 0;"
4383 "k.b = 0;"
4384 "k[4294967295] = 0;"
4385 "k.c = 0;"
4386 "k[4294967296] = 0;"
4387 "k.d = 0;"
4388 "k[140000] = 0;"
4389 "k.e = 0;"
4390 "k[30000000000] = 0;"
4391 "k.f = 0;"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004392 "var result = [];"
4393 "for (var prop in k) {"
4394 " result.push(prop);"
4395 "}"
4396 "result"));
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004397 // Check that we get all the property names returned including the
4398 // ones from the enumerators in the right order: indexed properties
4399 // in numerical order, indexed interceptor properties, named
4400 // properties in insertion order, named interceptor properties.
4401 // This order is not mandated by the spec, so this test is just
4402 // documenting our behavior.
4403 CHECK_EQ(17, result->Length());
4404 // Indexed properties in numerical order.
4405 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
4406 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
4407 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
4408 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
4409 // Indexed interceptor properties in the order they are returned
4410 // from the enumerator interceptor.
4411 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
4412 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
4413 // Named properties in insertion order.
4414 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
4415 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
4416 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
4417 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
4418 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
4419 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
4420 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
4421 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
4422 // Named interceptor properties.
4423 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
4424 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
4425 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004426}
4427
4428
4429int p_getter_count;
4430int p_getter_count2;
4431
4432
4433static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
4434 ApiTestFuzzer::Fuzz();
4435 p_getter_count++;
4436 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
4437 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
4438 if (name->Equals(v8_str("p1"))) {
4439 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
4440 } else if (name->Equals(v8_str("p2"))) {
4441 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
4442 } else if (name->Equals(v8_str("p3"))) {
4443 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
4444 } else if (name->Equals(v8_str("p4"))) {
4445 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
4446 }
4447 return v8::Undefined();
4448}
4449
4450
4451static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
4452 ApiTestFuzzer::Fuzz();
4453 LocalContext context;
4454 context->Global()->Set(v8_str("o1"), obj->NewInstance());
4455 CompileRun(
4456 "o1.__proto__ = { };"
4457 "var o2 = { __proto__: o1 };"
4458 "var o3 = { __proto__: o2 };"
4459 "var o4 = { __proto__: o3 };"
4460 "for (var i = 0; i < 10; i++) o4.p4;"
4461 "for (var i = 0; i < 10; i++) o3.p3;"
4462 "for (var i = 0; i < 10; i++) o2.p2;"
4463 "for (var i = 0; i < 10; i++) o1.p1;");
4464}
4465
4466
4467static v8::Handle<Value> PGetter2(Local<String> name,
4468 const AccessorInfo& info) {
4469 ApiTestFuzzer::Fuzz();
4470 p_getter_count2++;
4471 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
4472 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
4473 if (name->Equals(v8_str("p1"))) {
4474 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
4475 } else if (name->Equals(v8_str("p2"))) {
4476 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
4477 } else if (name->Equals(v8_str("p3"))) {
4478 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
4479 } else if (name->Equals(v8_str("p4"))) {
4480 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
4481 }
4482 return v8::Undefined();
4483}
4484
4485
4486THREADED_TEST(GetterHolders) {
4487 v8::HandleScope scope;
4488 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4489 obj->SetAccessor(v8_str("p1"), PGetter);
4490 obj->SetAccessor(v8_str("p2"), PGetter);
4491 obj->SetAccessor(v8_str("p3"), PGetter);
4492 obj->SetAccessor(v8_str("p4"), PGetter);
4493 p_getter_count = 0;
4494 RunHolderTest(obj);
4495 CHECK_EQ(40, p_getter_count);
4496}
4497
4498
4499THREADED_TEST(PreInterceptorHolders) {
4500 v8::HandleScope scope;
4501 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4502 obj->SetNamedPropertyHandler(PGetter2);
4503 p_getter_count2 = 0;
4504 RunHolderTest(obj);
4505 CHECK_EQ(40, p_getter_count2);
4506}
4507
4508
4509THREADED_TEST(ObjectInstantiation) {
4510 v8::HandleScope scope;
4511 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
4512 templ->SetAccessor(v8_str("t"), PGetter2);
4513 LocalContext context;
4514 context->Global()->Set(v8_str("o"), templ->NewInstance());
4515 for (int i = 0; i < 100; i++) {
4516 v8::HandleScope inner_scope;
4517 v8::Handle<v8::Object> obj = templ->NewInstance();
4518 CHECK_NE(obj, context->Global()->Get(v8_str("o")));
4519 context->Global()->Set(v8_str("o2"), obj);
4520 v8::Handle<Value> value =
4521 Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
4522 CHECK_EQ(v8::True(), value);
4523 context->Global()->Set(v8_str("o"), obj);
4524 }
4525}
4526
4527
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004528static int StrCmp16(uint16_t* a, uint16_t* b) {
4529 while (true) {
4530 if (*a == 0 && *b == 0) return 0;
4531 if (*a != *b) return 0 + *a - *b;
4532 a++;
4533 b++;
4534 }
4535}
4536
4537
4538static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
4539 while (true) {
4540 if (n-- == 0) return 0;
4541 if (*a == 0 && *b == 0) return 0;
4542 if (*a != *b) return 0 + *a - *b;
4543 a++;
4544 b++;
4545 }
4546}
4547
4548
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004549THREADED_TEST(StringWrite) {
4550 v8::HandleScope scope;
4551 v8::Handle<String> str = v8_str("abcde");
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004552 // abc<Icelandic eth><Unicode snowman>.
4553 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
4554
4555 CHECK_EQ(5, str2->Length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004556
4557 char buf[100];
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004558 char utf8buf[100];
4559 uint16_t wbuf[100];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004560 int len;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004561 int charlen;
4562
4563 memset(utf8buf, 0x1, sizeof(utf8buf));
4564 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
4565 CHECK_EQ(len, 9);
4566 CHECK_EQ(charlen, 5);
4567 CHECK_EQ(strcmp(utf8buf, "abc\303\260\342\230\203"), 0);
4568
4569 memset(utf8buf, 0x1, sizeof(utf8buf));
4570 len = str2->WriteUtf8(utf8buf, 8, &charlen);
4571 CHECK_EQ(len, 8);
4572 CHECK_EQ(charlen, 5);
4573 CHECK_EQ(strncmp(utf8buf, "abc\303\260\342\230\203\1", 9), 0);
4574
4575 memset(utf8buf, 0x1, sizeof(utf8buf));
4576 len = str2->WriteUtf8(utf8buf, 7, &charlen);
4577 CHECK_EQ(len, 5);
4578 CHECK_EQ(charlen, 4);
4579 CHECK_EQ(strncmp(utf8buf, "abc\303\260\1", 5), 0);
4580
4581 memset(utf8buf, 0x1, sizeof(utf8buf));
4582 len = str2->WriteUtf8(utf8buf, 6, &charlen);
4583 CHECK_EQ(len, 5);
4584 CHECK_EQ(charlen, 4);
4585 CHECK_EQ(strncmp(utf8buf, "abc\303\260\1", 5), 0);
4586
4587 memset(utf8buf, 0x1, sizeof(utf8buf));
4588 len = str2->WriteUtf8(utf8buf, 5, &charlen);
4589 CHECK_EQ(len, 5);
4590 CHECK_EQ(charlen, 4);
4591 CHECK_EQ(strncmp(utf8buf, "abc\303\260\1", 5), 0);
4592
4593 memset(utf8buf, 0x1, sizeof(utf8buf));
4594 len = str2->WriteUtf8(utf8buf, 4, &charlen);
4595 CHECK_EQ(len, 3);
4596 CHECK_EQ(charlen, 3);
4597 CHECK_EQ(strncmp(utf8buf, "abc\1", 4), 0);
4598
4599 memset(utf8buf, 0x1, sizeof(utf8buf));
4600 len = str2->WriteUtf8(utf8buf, 3, &charlen);
4601 CHECK_EQ(len, 3);
4602 CHECK_EQ(charlen, 3);
4603 CHECK_EQ(strncmp(utf8buf, "abc\1", 4), 0);
4604
4605 memset(utf8buf, 0x1, sizeof(utf8buf));
4606 len = str2->WriteUtf8(utf8buf, 2, &charlen);
4607 CHECK_EQ(len, 2);
4608 CHECK_EQ(charlen, 2);
4609 CHECK_EQ(strncmp(utf8buf, "ab\1", 3), 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004610
4611 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004612 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004613 len = str->WriteAscii(buf);
4614 CHECK_EQ(len, 5);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004615 len = str->Write(wbuf);
4616 CHECK_EQ(len, 5);
4617 CHECK_EQ(strcmp("abcde", buf), 0);
4618 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
4619 CHECK_EQ(StrCmp16(answer1, wbuf), 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004620
4621 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004622 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004623 len = str->WriteAscii(buf, 0, 4);
4624 CHECK_EQ(len, 4);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004625 len = str->Write(wbuf, 0, 4);
4626 CHECK_EQ(len, 4);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004627 CHECK_EQ(strncmp("abcd\1", buf, 5), 0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004628 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
4629 CHECK_EQ(StrNCmp16(answer2, wbuf, 5), 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004630
4631 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004632 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004633 len = str->WriteAscii(buf, 0, 5);
4634 CHECK_EQ(len, 5);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004635 len = str->Write(wbuf, 0, 5);
4636 CHECK_EQ(len, 5);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004637 CHECK_EQ(strncmp("abcde\1", buf, 6), 0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004638 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
4639 CHECK_EQ(StrNCmp16(answer3, wbuf, 6), 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004640
4641 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004642 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004643 len = str->WriteAscii(buf, 0, 6);
4644 CHECK_EQ(len, 5);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004645 len = str->Write(wbuf, 0, 6);
4646 CHECK_EQ(len, 5);
4647 CHECK_EQ(strcmp("abcde", buf), 0);
4648 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
4649 CHECK_EQ(StrCmp16(answer4, wbuf), 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004650
4651 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004652 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004653 len = str->WriteAscii(buf, 4, -1);
4654 CHECK_EQ(len, 1);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004655 len = str->Write(wbuf, 4, -1);
4656 CHECK_EQ(len, 1);
4657 CHECK_EQ(strcmp("e", buf), 0);
4658 uint16_t answer5[] = {'e', '\0'};
4659 CHECK_EQ(StrCmp16(answer5, wbuf), 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004660
4661 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004662 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004663 len = str->WriteAscii(buf, 4, 6);
4664 CHECK_EQ(len, 1);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004665 len = str->Write(wbuf, 4, 6);
4666 CHECK_EQ(len, 1);
4667 CHECK_EQ(strcmp("e", buf), 0);
4668 CHECK_EQ(StrCmp16(answer5, wbuf), 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004669
4670 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004671 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004672 len = str->WriteAscii(buf, 4, 1);
4673 CHECK_EQ(len, 1);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004674 len = str->Write(wbuf, 4, 1);
4675 CHECK_EQ(len, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004676 CHECK_EQ(strncmp("e\1", buf, 2), 0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004677 uint16_t answer6[] = {'e', 0x101};
4678 CHECK_EQ(StrNCmp16(answer6, wbuf, 2), 0);
4679
4680 memset(buf, 0x1, sizeof(buf));
4681 memset(wbuf, 0x1, sizeof(wbuf));
4682 len = str->WriteAscii(buf, 3, 1);
4683 CHECK_EQ(len, 1);
4684 len = str->Write(wbuf, 3, 1);
4685 CHECK_EQ(len, 1);
4686 CHECK_EQ(strncmp("d\1", buf, 2), 0);
4687 uint16_t answer7[] = {'d', 0x101};
4688 CHECK_EQ(StrNCmp16(answer7, wbuf, 2), 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004689}
4690
4691
4692THREADED_TEST(ToArrayIndex) {
4693 v8::HandleScope scope;
4694 LocalContext context;
4695
4696 v8::Handle<String> str = v8_str("42");
4697 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
4698 CHECK(!index.IsEmpty());
4699 CHECK_EQ(42.0, index->Uint32Value());
4700 str = v8_str("42asdf");
4701 index = str->ToArrayIndex();
4702 CHECK(index.IsEmpty());
4703 str = v8_str("-42");
4704 index = str->ToArrayIndex();
4705 CHECK(index.IsEmpty());
4706 str = v8_str("4294967295");
4707 index = str->ToArrayIndex();
4708 CHECK(!index.IsEmpty());
4709 CHECK_EQ(4294967295.0, index->Uint32Value());
4710 v8::Handle<v8::Number> num = v8::Number::New(1);
4711 index = num->ToArrayIndex();
4712 CHECK(!index.IsEmpty());
4713 CHECK_EQ(1.0, index->Uint32Value());
4714 num = v8::Number::New(-1);
4715 index = num->ToArrayIndex();
4716 CHECK(index.IsEmpty());
4717 v8::Handle<v8::Object> obj = v8::Object::New();
4718 index = obj->ToArrayIndex();
4719 CHECK(index.IsEmpty());
4720}
4721
4722
4723THREADED_TEST(ErrorConstruction) {
4724 v8::HandleScope scope;
4725 LocalContext context;
4726
4727 v8::Handle<String> foo = v8_str("foo");
4728 v8::Handle<String> message = v8_str("message");
4729 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
4730 CHECK(range_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004731 v8::Handle<v8::Object> range_obj = range_error.As<v8::Object>();
4732 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004733 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
4734 CHECK(reference_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004735 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004736 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
4737 CHECK(syntax_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004738 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004739 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
4740 CHECK(type_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004741 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004742 v8::Handle<Value> error = v8::Exception::Error(foo);
4743 CHECK(error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004744 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004745}
4746
4747
4748static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
4749 ApiTestFuzzer::Fuzz();
4750 return v8_num(10);
4751}
4752
4753
4754static void YSetter(Local<String> name,
4755 Local<Value> value,
4756 const AccessorInfo& info) {
4757 if (info.This()->Has(name)) {
4758 info.This()->Delete(name);
4759 }
4760 info.This()->Set(name, value);
4761}
4762
4763
4764THREADED_TEST(DeleteAccessor) {
4765 v8::HandleScope scope;
4766 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4767 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
4768 LocalContext context;
4769 v8::Handle<v8::Object> holder = obj->NewInstance();
4770 context->Global()->Set(v8_str("holder"), holder);
4771 v8::Handle<Value> result = CompileRun(
4772 "holder.y = 11; holder.y = 12; holder.y");
4773 CHECK_EQ(12, result->Uint32Value());
4774}
4775
4776
4777THREADED_TEST(TypeSwitch) {
4778 v8::HandleScope scope;
4779 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
4780 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
4781 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
4782 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
4783 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
4784 LocalContext context;
4785 v8::Handle<v8::Object> obj0 = v8::Object::New();
4786 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
4787 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
4788 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
4789 for (int i = 0; i < 10; i++) {
4790 CHECK_EQ(0, type_switch->match(obj0));
4791 CHECK_EQ(1, type_switch->match(obj1));
4792 CHECK_EQ(2, type_switch->match(obj2));
4793 CHECK_EQ(3, type_switch->match(obj3));
4794 CHECK_EQ(3, type_switch->match(obj3));
4795 CHECK_EQ(2, type_switch->match(obj2));
4796 CHECK_EQ(1, type_switch->match(obj1));
4797 CHECK_EQ(0, type_switch->match(obj0));
4798 }
4799}
4800
4801
4802// For use within the TestSecurityHandler() test.
4803static bool g_security_callback_result = false;
4804static bool NamedSecurityTestCallback(Local<v8::Object> global,
4805 Local<Value> name,
4806 v8::AccessType type,
4807 Local<Value> data) {
4808 // Always allow read access.
4809 if (type == v8::ACCESS_GET)
4810 return true;
4811
4812 // Sometimes allow other access.
4813 return g_security_callback_result;
4814}
4815
4816
4817static bool IndexedSecurityTestCallback(Local<v8::Object> global,
4818 uint32_t key,
4819 v8::AccessType type,
4820 Local<Value> data) {
4821 // Always allow read access.
4822 if (type == v8::ACCESS_GET)
4823 return true;
4824
4825 // Sometimes allow other access.
4826 return g_security_callback_result;
4827}
4828
4829
4830static int trouble_nesting = 0;
4831static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
4832 ApiTestFuzzer::Fuzz();
4833 trouble_nesting++;
4834
4835 // Call a JS function that throws an uncaught exception.
4836 Local<v8::Object> arg_this = Context::GetCurrent()->Global();
4837 Local<Value> trouble_callee = (trouble_nesting == 3) ?
4838 arg_this->Get(v8_str("trouble_callee")) :
4839 arg_this->Get(v8_str("trouble_caller"));
4840 CHECK(trouble_callee->IsFunction());
4841 return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
4842}
4843
4844
4845static int report_count = 0;
4846static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
4847 v8::Handle<Value>) {
4848 report_count++;
4849}
4850
4851
4852// Counts uncaught exceptions, but other tests running in parallel
4853// also have uncaught exceptions.
4854TEST(ApiUncaughtException) {
ager@chromium.org8bb60582008-12-11 12:02:20 +00004855 report_count = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004856 v8::HandleScope scope;
4857 LocalContext env;
4858 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
4859
4860 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
4861 v8::Local<v8::Object> global = env->Global();
4862 global->Set(v8_str("trouble"), fun->GetFunction());
4863
4864 Script::Compile(v8_str("function trouble_callee() {"
4865 " var x = null;"
4866 " return x.foo;"
4867 "};"
4868 "function trouble_caller() {"
4869 " trouble();"
4870 "};"))->Run();
4871 Local<Value> trouble = global->Get(v8_str("trouble"));
4872 CHECK(trouble->IsFunction());
4873 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
4874 CHECK(trouble_callee->IsFunction());
4875 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
4876 CHECK(trouble_caller->IsFunction());
4877 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
4878 CHECK_EQ(1, report_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00004879 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
4880}
4881
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004882static const char* script_resource_name = "ExceptionInNativeScript.js";
4883static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
4884 v8::Handle<Value>) {
4885 v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
4886 CHECK(!name_val.IsEmpty() && name_val->IsString());
4887 v8::String::AsciiValue name(message->GetScriptResourceName());
4888 CHECK_EQ(script_resource_name, *name);
4889 CHECK_EQ(3, message->GetLineNumber());
4890 v8::String::AsciiValue source_line(message->GetSourceLine());
4891 CHECK_EQ(" new o.foo();", *source_line);
4892}
4893
4894TEST(ExceptionInNativeScript) {
4895 v8::HandleScope scope;
4896 LocalContext env;
4897 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
4898
4899 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
4900 v8::Local<v8::Object> global = env->Global();
4901 global->Set(v8_str("trouble"), fun->GetFunction());
4902
4903 Script::Compile(v8_str("function trouble() {\n"
4904 " var o = {};\n"
4905 " new o.foo();\n"
4906 "};"), v8::String::New(script_resource_name))->Run();
4907 Local<Value> trouble = global->Get(v8_str("trouble"));
4908 CHECK(trouble->IsFunction());
4909 Function::Cast(*trouble)->Call(global, 0, NULL);
4910 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
4911}
4912
ager@chromium.org8bb60582008-12-11 12:02:20 +00004913
4914TEST(CompilationErrorUsingTryCatchHandler) {
4915 v8::HandleScope scope;
4916 LocalContext env;
4917 v8::TryCatch try_catch;
4918 Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
4919 CHECK_NE(NULL, *try_catch.Exception());
4920 CHECK(try_catch.HasCaught());
4921}
4922
4923
4924TEST(TryCatchFinallyUsingTryCatchHandler) {
4925 v8::HandleScope scope;
4926 LocalContext env;
4927 v8::TryCatch try_catch;
4928 Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
4929 CHECK(!try_catch.HasCaught());
4930 Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
4931 CHECK(try_catch.HasCaught());
4932 try_catch.Reset();
4933 Script::Compile(v8_str("(function() {"
4934 "try { throw ''; } finally { return; }"
4935 "})()"))->Run();
4936 CHECK(!try_catch.HasCaught());
4937 Script::Compile(v8_str("(function()"
4938 " { try { throw ''; } finally { throw 0; }"
4939 "})()"))->Run();
4940 CHECK(try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004941}
4942
4943
4944// SecurityHandler can't be run twice
4945TEST(SecurityHandler) {
4946 v8::HandleScope scope0;
4947 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
4948 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
4949 IndexedSecurityTestCallback);
4950 // Create an environment
4951 v8::Persistent<Context> context0 =
4952 Context::New(NULL, global_template);
4953 context0->Enter();
4954
4955 v8::Handle<v8::Object> global0 = context0->Global();
4956 v8::Handle<Script> script0 = v8_compile("foo = 111");
4957 script0->Run();
4958 global0->Set(v8_str("0"), v8_num(999));
4959 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
4960 CHECK_EQ(111, foo0->Int32Value());
4961 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
4962 CHECK_EQ(999, z0->Int32Value());
4963
4964 // Create another environment, should fail security checks.
4965 v8::HandleScope scope1;
4966
4967 v8::Persistent<Context> context1 =
4968 Context::New(NULL, global_template);
4969 context1->Enter();
4970
4971 v8::Handle<v8::Object> global1 = context1->Global();
4972 global1->Set(v8_str("othercontext"), global0);
4973 // This set will fail the security check.
4974 v8::Handle<Script> script1 =
4975 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
4976 script1->Run();
4977 // This read will pass the security check.
4978 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
4979 CHECK_EQ(111, foo1->Int32Value());
4980 // This read will pass the security check.
4981 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
4982 CHECK_EQ(999, z1->Int32Value());
4983
4984 // Create another environment, should pass security checks.
4985 { g_security_callback_result = true; // allow security handler to pass.
4986 v8::HandleScope scope2;
4987 LocalContext context2;
4988 v8::Handle<v8::Object> global2 = context2->Global();
4989 global2->Set(v8_str("othercontext"), global0);
4990 v8::Handle<Script> script2 =
4991 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
4992 script2->Run();
4993 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
4994 CHECK_EQ(333, foo2->Int32Value());
4995 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
4996 CHECK_EQ(888, z2->Int32Value());
4997 }
4998
4999 context1->Exit();
5000 context1.Dispose();
5001
5002 context0->Exit();
5003 context0.Dispose();
5004}
5005
5006
5007THREADED_TEST(SecurityChecks) {
5008 v8::HandleScope handle_scope;
5009 LocalContext env1;
5010 v8::Persistent<Context> env2 = Context::New();
5011
5012 Local<Value> foo = v8_str("foo");
5013 Local<Value> bar = v8_str("bar");
5014
5015 // Set to the same domain.
5016 env1->SetSecurityToken(foo);
5017
5018 // Create a function in env1.
5019 Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
5020 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
5021 CHECK(spy->IsFunction());
5022
5023 // Create another function accessing global objects.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005024 Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005025 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
5026 CHECK(spy2->IsFunction());
5027
5028 // Switch to env2 in the same domain and invoke spy on env2.
5029 {
5030 env2->SetSecurityToken(foo);
5031 // Enter env2
5032 Context::Scope scope_env2(env2);
5033 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
5034 CHECK(result->IsFunction());
5035 }
5036
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005037 {
5038 env2->SetSecurityToken(bar);
5039 Context::Scope scope_env2(env2);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005040
5041 // Call cross_domain_call, it should throw an exception
5042 v8::TryCatch try_catch;
5043 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
5044 CHECK(try_catch.HasCaught());
5045 }
5046
5047 env2.Dispose();
5048}
5049
5050
5051// Regression test case for issue 1183439.
5052THREADED_TEST(SecurityChecksForPrototypeChain) {
5053 v8::HandleScope scope;
5054 LocalContext current;
5055 v8::Persistent<Context> other = Context::New();
5056
5057 // Change context to be able to get to the Object function in the
5058 // other context without hitting the security checks.
5059 v8::Local<Value> other_object;
5060 { Context::Scope scope(other);
5061 other_object = other->Global()->Get(v8_str("Object"));
5062 other->Global()->Set(v8_num(42), v8_num(87));
5063 }
5064
5065 current->Global()->Set(v8_str("other"), other->Global());
5066 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
5067
5068 // Make sure the security check fails here and we get an undefined
5069 // result instead of getting the Object function. Repeat in a loop
5070 // to make sure to exercise the IC code.
5071 v8::Local<Script> access_other0 = v8_compile("other.Object");
5072 v8::Local<Script> access_other1 = v8_compile("other[42]");
5073 for (int i = 0; i < 5; i++) {
5074 CHECK(!access_other0->Run()->Equals(other_object));
5075 CHECK(access_other0->Run()->IsUndefined());
5076 CHECK(!access_other1->Run()->Equals(v8_num(87)));
5077 CHECK(access_other1->Run()->IsUndefined());
5078 }
5079
5080 // Create an object that has 'other' in its prototype chain and make
5081 // sure we cannot access the Object function indirectly through
5082 // that. Repeat in a loop to make sure to exercise the IC code.
5083 v8_compile("function F() { };"
5084 "F.prototype = other;"
5085 "var f = new F();")->Run();
5086 v8::Local<Script> access_f0 = v8_compile("f.Object");
5087 v8::Local<Script> access_f1 = v8_compile("f[42]");
5088 for (int j = 0; j < 5; j++) {
5089 CHECK(!access_f0->Run()->Equals(other_object));
5090 CHECK(access_f0->Run()->IsUndefined());
5091 CHECK(!access_f1->Run()->Equals(v8_num(87)));
5092 CHECK(access_f1->Run()->IsUndefined());
5093 }
5094
5095 // Now it gets hairy: Set the prototype for the other global object
5096 // to be the current global object. The prototype chain for 'f' now
5097 // goes through 'other' but ends up in the current global object.
5098 { Context::Scope scope(other);
5099 other->Global()->Set(v8_str("__proto__"), current->Global());
5100 }
5101 // Set a named and an index property on the current global
5102 // object. To force the lookup to go through the other global object,
5103 // the properties must not exist in the other global object.
5104 current->Global()->Set(v8_str("foo"), v8_num(100));
5105 current->Global()->Set(v8_num(99), v8_num(101));
5106 // Try to read the properties from f and make sure that the access
5107 // gets stopped by the security checks on the other global object.
5108 Local<Script> access_f2 = v8_compile("f.foo");
5109 Local<Script> access_f3 = v8_compile("f[99]");
5110 for (int k = 0; k < 5; k++) {
5111 CHECK(!access_f2->Run()->Equals(v8_num(100)));
5112 CHECK(access_f2->Run()->IsUndefined());
5113 CHECK(!access_f3->Run()->Equals(v8_num(101)));
5114 CHECK(access_f3->Run()->IsUndefined());
5115 }
5116 other.Dispose();
5117}
5118
5119
5120THREADED_TEST(CrossDomainDelete) {
5121 v8::HandleScope handle_scope;
5122 LocalContext env1;
5123 v8::Persistent<Context> env2 = Context::New();
5124
5125 Local<Value> foo = v8_str("foo");
5126 Local<Value> bar = v8_str("bar");
5127
5128 // Set to the same domain.
5129 env1->SetSecurityToken(foo);
5130 env2->SetSecurityToken(foo);
5131
5132 env1->Global()->Set(v8_str("prop"), v8_num(3));
5133 env2->Global()->Set(v8_str("env1"), env1->Global());
5134
5135 // Change env2 to a different domain and delete env1.prop.
5136 env2->SetSecurityToken(bar);
5137 {
5138 Context::Scope scope_env2(env2);
5139 Local<Value> result =
5140 Script::Compile(v8_str("delete env1.prop"))->Run();
5141 CHECK(result->IsFalse());
5142 }
5143
5144 // Check that env1.prop still exists.
5145 Local<Value> v = env1->Global()->Get(v8_str("prop"));
5146 CHECK(v->IsNumber());
5147 CHECK_EQ(3, v->Int32Value());
5148
5149 env2.Dispose();
5150}
5151
5152
ager@chromium.org870a0b62008-11-04 11:43:05 +00005153THREADED_TEST(CrossDomainIsPropertyEnumerable) {
5154 v8::HandleScope handle_scope;
5155 LocalContext env1;
5156 v8::Persistent<Context> env2 = Context::New();
5157
5158 Local<Value> foo = v8_str("foo");
5159 Local<Value> bar = v8_str("bar");
5160
5161 // Set to the same domain.
5162 env1->SetSecurityToken(foo);
5163 env2->SetSecurityToken(foo);
5164
5165 env1->Global()->Set(v8_str("prop"), v8_num(3));
5166 env2->Global()->Set(v8_str("env1"), env1->Global());
5167
5168 // env1.prop is enumerable in env2.
5169 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
5170 {
5171 Context::Scope scope_env2(env2);
5172 Local<Value> result = Script::Compile(test)->Run();
5173 CHECK(result->IsTrue());
5174 }
5175
5176 // Change env2 to a different domain and test again.
5177 env2->SetSecurityToken(bar);
5178 {
5179 Context::Scope scope_env2(env2);
5180 Local<Value> result = Script::Compile(test)->Run();
5181 CHECK(result->IsFalse());
5182 }
5183
5184 env2.Dispose();
5185}
5186
5187
ager@chromium.org236ad962008-09-25 09:45:57 +00005188THREADED_TEST(CrossDomainForIn) {
5189 v8::HandleScope handle_scope;
5190 LocalContext env1;
5191 v8::Persistent<Context> env2 = Context::New();
5192
5193 Local<Value> foo = v8_str("foo");
5194 Local<Value> bar = v8_str("bar");
5195
5196 // Set to the same domain.
5197 env1->SetSecurityToken(foo);
5198 env2->SetSecurityToken(foo);
5199
5200 env1->Global()->Set(v8_str("prop"), v8_num(3));
5201 env2->Global()->Set(v8_str("env1"), env1->Global());
5202
5203 // Change env2 to a different domain and set env1's global object
5204 // as the __proto__ of an object in env2 and enumerate properties
5205 // in for-in. It shouldn't enumerate properties on env1's global
5206 // object.
5207 env2->SetSecurityToken(bar);
5208 {
5209 Context::Scope scope_env2(env2);
5210 Local<Value> result =
5211 CompileRun("(function(){var obj = {'__proto__':env1};"
5212 "for (var p in obj)"
5213 " if (p == 'prop') return false;"
5214 "return true;})()");
5215 CHECK(result->IsTrue());
5216 }
5217 env2.Dispose();
5218}
5219
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005220
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005221TEST(ContextDetachGlobal) {
5222 v8::HandleScope handle_scope;
5223 LocalContext env1;
5224 v8::Persistent<Context> env2 = Context::New();
5225
5226 Local<v8::Object> global1 = env1->Global();
5227
5228 Local<Value> foo = v8_str("foo");
5229
5230 // Set to the same domain.
5231 env1->SetSecurityToken(foo);
5232 env2->SetSecurityToken(foo);
5233
5234 // Enter env2
5235 env2->Enter();
5236
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00005237 // Create a function in env2 and add a reference to it in env1.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005238 Local<v8::Object> global2 = env2->Global();
5239 global2->Set(v8_str("prop"), v8::Integer::New(1));
5240 CompileRun("function getProp() {return prop;}");
5241
5242 env1->Global()->Set(v8_str("getProp"),
5243 global2->Get(v8_str("getProp")));
5244
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00005245 // Detach env2's global, and reuse the global object of env2
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005246 env2->Exit();
5247 env2->DetachGlobal();
5248 // env2 has a new global object.
5249 CHECK(!env2->Global()->Equals(global2));
5250
5251 v8::Persistent<Context> env3 =
5252 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
5253 env3->SetSecurityToken(v8_str("bar"));
5254 env3->Enter();
5255
5256 Local<v8::Object> global3 = env3->Global();
5257 CHECK_EQ(global2, global3);
5258 CHECK(global3->Get(v8_str("prop"))->IsUndefined());
5259 CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
5260 global3->Set(v8_str("prop"), v8::Integer::New(-1));
5261 global3->Set(v8_str("prop2"), v8::Integer::New(2));
5262 env3->Exit();
5263
5264 // Call getProp in env1, and it should return the value 1
5265 {
5266 Local<Value> get_prop = global1->Get(v8_str("getProp"));
5267 CHECK(get_prop->IsFunction());
5268 v8::TryCatch try_catch;
5269 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
5270 CHECK(!try_catch.HasCaught());
5271 CHECK_EQ(1, r->Int32Value());
5272 }
5273
5274 // Check that env3 is not accessible from env1
5275 {
5276 Local<Value> r = global3->Get(v8_str("prop2"));
5277 CHECK(r->IsUndefined());
5278 }
5279
5280 env2.Dispose();
5281 env3.Dispose();
5282}
5283
5284
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00005285TEST(DetachAndReattachGlobal) {
5286 v8::HandleScope scope;
5287 LocalContext env1;
5288
5289 // Create second environment.
5290 v8::Persistent<Context> env2 = Context::New();
5291
5292 Local<Value> foo = v8_str("foo");
5293
5294 // Set same security token for env1 and env2.
5295 env1->SetSecurityToken(foo);
5296 env2->SetSecurityToken(foo);
5297
5298 // Create a property on the global object in env2.
5299 {
5300 v8::Context::Scope scope(env2);
5301 env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
5302 }
5303
5304 // Create a reference to env2 global from env1 global.
5305 env1->Global()->Set(v8_str("other"), env2->Global());
5306
5307 // Check that we have access to other.p in env2 from env1.
5308 Local<Value> result = CompileRun("other.p");
5309 CHECK(result->IsInt32());
5310 CHECK_EQ(42, result->Int32Value());
5311
5312 // Hold on to global from env2 and detach global from env2.
5313 Local<v8::Object> global2 = env2->Global();
5314 env2->DetachGlobal();
5315
5316 // Check that the global has been detached. No other.p property can
5317 // be found.
5318 result = CompileRun("other.p");
5319 CHECK(result->IsUndefined());
5320
5321 // Reuse global2 for env3.
5322 v8::Persistent<Context> env3 =
5323 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
5324 CHECK_EQ(global2, env3->Global());
5325
5326 // Start by using the same security token for env3 as for env1 and env2.
5327 env3->SetSecurityToken(foo);
5328
5329 // Create a property on the global object in env3.
5330 {
5331 v8::Context::Scope scope(env3);
5332 env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
5333 }
5334
5335 // Check that other.p is now the property in env3 and that we have access.
5336 result = CompileRun("other.p");
5337 CHECK(result->IsInt32());
5338 CHECK_EQ(24, result->Int32Value());
5339
5340 // Change security token for env3 to something different from env1 and env2.
5341 env3->SetSecurityToken(v8_str("bar"));
5342
5343 // Check that we do not have access to other.p in env1. |other| is now
5344 // the global object for env3 which has a different security token,
5345 // so access should be blocked.
5346 result = CompileRun("other.p");
5347 CHECK(result->IsUndefined());
5348
5349 // Detach the global for env3 and reattach it to env2.
5350 env3->DetachGlobal();
5351 env2->ReattachGlobal(global2);
5352
5353 // Check that we have access to other.p again in env1. |other| is now
5354 // the global object for env2 which has the same security token as env1.
5355 result = CompileRun("other.p");
5356 CHECK(result->IsInt32());
5357 CHECK_EQ(42, result->Int32Value());
5358
5359 env2.Dispose();
5360 env3.Dispose();
5361}
5362
5363
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005364static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005365static bool NamedAccessBlocker(Local<v8::Object> global,
5366 Local<Value> name,
5367 v8::AccessType type,
5368 Local<Value> data) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005369 return Context::GetCurrent()->Global()->Equals(global) ||
5370 allowed_access_type[type];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005371}
5372
5373
5374static bool IndexedAccessBlocker(Local<v8::Object> global,
5375 uint32_t key,
5376 v8::AccessType type,
5377 Local<Value> data) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005378 return Context::GetCurrent()->Global()->Equals(global) ||
5379 allowed_access_type[type];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005380}
5381
5382
5383static int g_echo_value = -1;
5384static v8::Handle<Value> EchoGetter(Local<String> name,
5385 const AccessorInfo& info) {
5386 return v8_num(g_echo_value);
5387}
5388
5389
5390static void EchoSetter(Local<String> name,
5391 Local<Value> value,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005392 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005393 if (value->IsNumber())
5394 g_echo_value = value->Int32Value();
5395}
5396
5397
5398static v8::Handle<Value> UnreachableGetter(Local<String> name,
5399 const AccessorInfo& info) {
5400 CHECK(false); // This function should not be called..
5401 return v8::Undefined();
5402}
5403
5404
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005405static void UnreachableSetter(Local<String>, Local<Value>,
5406 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005407 CHECK(false); // This function should nto be called.
5408}
5409
5410
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005411TEST(AccessControl) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005412 v8::HandleScope handle_scope;
5413 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
5414
5415 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
5416 IndexedAccessBlocker);
5417
5418 // Add an accessor accessible by cross-domain JS code.
5419 global_template->SetAccessor(
5420 v8_str("accessible_prop"),
5421 EchoGetter, EchoSetter,
5422 v8::Handle<Value>(),
5423 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
5424
5425 // Add an accessor that is not accessible by cross-domain JS code.
ager@chromium.org870a0b62008-11-04 11:43:05 +00005426 global_template->SetAccessor(v8_str("blocked_prop"),
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005427 UnreachableGetter, UnreachableSetter,
5428 v8::Handle<Value>(),
5429 v8::DEFAULT);
5430
5431 // Create an environment
5432 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
5433 context0->Enter();
5434
5435 v8::Handle<v8::Object> global0 = context0->Global();
5436
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005437 // Define a property with JS getter and setter.
5438 CompileRun(
5439 "function getter() { return 'getter'; };\n"
5440 "function setter() { return 'setter'; }\n"
5441 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
5442
5443 Local<Value> getter = global0->Get(v8_str("getter"));
5444 Local<Value> setter = global0->Get(v8_str("setter"));
5445
5446 // And define normal element.
5447 global0->Set(239, v8_str("239"));
5448
5449 // Define an element with JS getter and setter.
5450 CompileRun(
5451 "function el_getter() { return 'el_getter'; };\n"
5452 "function el_setter() { return 'el_setter'; };\n"
5453 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
5454
5455 Local<Value> el_getter = global0->Get(v8_str("el_getter"));
5456 Local<Value> el_setter = global0->Get(v8_str("el_setter"));
5457
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005458 v8::HandleScope scope1;
5459
5460 v8::Persistent<Context> context1 = Context::New();
5461 context1->Enter();
5462
5463 v8::Handle<v8::Object> global1 = context1->Global();
5464 global1->Set(v8_str("other"), global0);
5465
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005466 // Access blocked property.
5467 CompileRun("other.blocked_prop = 1");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005468
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005469 ExpectUndefined("other.blocked_prop");
5470 ExpectUndefined(
5471 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
5472 ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005473
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005474 // Enable ACCESS_HAS
5475 allowed_access_type[v8::ACCESS_HAS] = true;
5476 ExpectUndefined("other.blocked_prop");
5477 // ... and now we can get the descriptor...
5478 ExpectUndefined(
antonm@chromium.orgdca01352011-01-31 17:15:05 +00005479 "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005480 // ... and enumerate the property.
5481 ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
5482 allowed_access_type[v8::ACCESS_HAS] = false;
antonm@chromium.orgdca01352011-01-31 17:15:05 +00005483
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005484 // Access blocked element.
5485 CompileRun("other[239] = 1");
5486
5487 ExpectUndefined("other[239]");
5488 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
5489 ExpectFalse("propertyIsEnumerable.call(other, '239')");
5490
5491 // Enable ACCESS_HAS
5492 allowed_access_type[v8::ACCESS_HAS] = true;
5493 ExpectUndefined("other[239]");
5494 // ... and now we can get the descriptor...
5495 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
5496 // ... and enumerate the property.
5497 ExpectTrue("propertyIsEnumerable.call(other, '239')");
5498 allowed_access_type[v8::ACCESS_HAS] = false;
5499
5500 // Access a property with JS accessor.
5501 CompileRun("other.js_accessor_p = 2");
5502
5503 ExpectUndefined("other.js_accessor_p");
5504 ExpectUndefined(
5505 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
5506
5507 // Enable ACCESS_HAS.
5508 allowed_access_type[v8::ACCESS_HAS] = true;
5509 ExpectUndefined("other.js_accessor_p");
5510 ExpectUndefined(
5511 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
5512 ExpectUndefined(
5513 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
5514 ExpectUndefined(
5515 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
5516 allowed_access_type[v8::ACCESS_HAS] = false;
5517
5518 // Enable both ACCESS_HAS and ACCESS_GET.
5519 allowed_access_type[v8::ACCESS_HAS] = true;
5520 allowed_access_type[v8::ACCESS_GET] = true;
5521
5522 ExpectString("other.js_accessor_p", "getter");
5523 ExpectObject(
5524 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
5525 ExpectUndefined(
5526 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
5527 ExpectUndefined(
5528 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
5529
5530 allowed_access_type[v8::ACCESS_GET] = false;
5531 allowed_access_type[v8::ACCESS_HAS] = false;
5532
5533 // Enable both ACCESS_HAS and ACCESS_SET.
5534 allowed_access_type[v8::ACCESS_HAS] = true;
5535 allowed_access_type[v8::ACCESS_SET] = true;
5536
5537 ExpectUndefined("other.js_accessor_p");
5538 ExpectUndefined(
5539 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
5540 ExpectObject(
5541 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
5542 ExpectUndefined(
5543 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
5544
5545 allowed_access_type[v8::ACCESS_SET] = false;
5546 allowed_access_type[v8::ACCESS_HAS] = false;
5547
5548 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
5549 allowed_access_type[v8::ACCESS_HAS] = true;
5550 allowed_access_type[v8::ACCESS_GET] = true;
5551 allowed_access_type[v8::ACCESS_SET] = true;
5552
5553 ExpectString("other.js_accessor_p", "getter");
5554 ExpectObject(
5555 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
5556 ExpectObject(
5557 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
5558 ExpectUndefined(
5559 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
5560
5561 allowed_access_type[v8::ACCESS_SET] = false;
5562 allowed_access_type[v8::ACCESS_GET] = false;
5563 allowed_access_type[v8::ACCESS_HAS] = false;
5564
5565 // Access an element with JS accessor.
5566 CompileRun("other[42] = 2");
5567
5568 ExpectUndefined("other[42]");
5569 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
5570
5571 // Enable ACCESS_HAS.
5572 allowed_access_type[v8::ACCESS_HAS] = true;
5573 ExpectUndefined("other[42]");
5574 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
5575 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
5576 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
5577 allowed_access_type[v8::ACCESS_HAS] = false;
5578
5579 // Enable both ACCESS_HAS and ACCESS_GET.
5580 allowed_access_type[v8::ACCESS_HAS] = true;
5581 allowed_access_type[v8::ACCESS_GET] = true;
5582
5583 ExpectString("other[42]", "el_getter");
5584 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
5585 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
5586 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
5587
5588 allowed_access_type[v8::ACCESS_GET] = false;
5589 allowed_access_type[v8::ACCESS_HAS] = false;
5590
5591 // Enable both ACCESS_HAS and ACCESS_SET.
5592 allowed_access_type[v8::ACCESS_HAS] = true;
5593 allowed_access_type[v8::ACCESS_SET] = true;
5594
5595 ExpectUndefined("other[42]");
5596 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
5597 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
5598 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
5599
5600 allowed_access_type[v8::ACCESS_SET] = false;
5601 allowed_access_type[v8::ACCESS_HAS] = false;
5602
5603 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
5604 allowed_access_type[v8::ACCESS_HAS] = true;
5605 allowed_access_type[v8::ACCESS_GET] = true;
5606 allowed_access_type[v8::ACCESS_SET] = true;
5607
5608 ExpectString("other[42]", "el_getter");
5609 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
5610 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
5611 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
5612
5613 allowed_access_type[v8::ACCESS_SET] = false;
5614 allowed_access_type[v8::ACCESS_GET] = false;
5615 allowed_access_type[v8::ACCESS_HAS] = false;
5616
5617 v8::Handle<Value> value;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005618
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005619 // Access accessible property
antonm@chromium.orgdca01352011-01-31 17:15:05 +00005620 value = CompileRun("other.accessible_prop = 3");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005621 CHECK(value->IsNumber());
5622 CHECK_EQ(3, value->Int32Value());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00005623 CHECK_EQ(3, g_echo_value);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005624
antonm@chromium.orgdca01352011-01-31 17:15:05 +00005625 value = CompileRun("other.accessible_prop");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005626 CHECK(value->IsNumber());
5627 CHECK_EQ(3, value->Int32Value());
5628
antonm@chromium.orgdca01352011-01-31 17:15:05 +00005629 value = CompileRun(
5630 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
5631 CHECK(value->IsNumber());
5632 CHECK_EQ(3, value->Int32Value());
5633
5634 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
ager@chromium.org870a0b62008-11-04 11:43:05 +00005635 CHECK(value->IsTrue());
5636
5637 // Enumeration doesn't enumerate accessors from inaccessible objects in
5638 // the prototype chain even if the accessors are in themselves accessible.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00005639 value =
ager@chromium.org870a0b62008-11-04 11:43:05 +00005640 CompileRun("(function(){var obj = {'__proto__':other};"
5641 "for (var p in obj)"
5642 " if (p == 'accessible_prop' || p == 'blocked_prop') {"
5643 " return false;"
5644 " }"
5645 "return true;})()");
antonm@chromium.orgdca01352011-01-31 17:15:05 +00005646 CHECK(value->IsTrue());
ager@chromium.org870a0b62008-11-04 11:43:05 +00005647
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005648 context1->Exit();
5649 context0->Exit();
5650 context1.Dispose();
5651 context0.Dispose();
5652}
5653
5654
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005655TEST(AccessControlES5) {
ricow@chromium.org65001782011-02-15 13:36:41 +00005656 v8::HandleScope handle_scope;
5657 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
5658
5659 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
5660 IndexedAccessBlocker);
5661
5662 // Add an accessor that is not accessible by cross-domain JS code.
5663 global_template->SetAccessor(v8_str("blocked_prop"),
5664 UnreachableGetter, UnreachableSetter,
5665 v8::Handle<Value>(),
5666 v8::DEFAULT);
5667
5668 // Create an environment
5669 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
5670 context0->Enter();
5671
5672 v8::Handle<v8::Object> global0 = context0->Global();
5673
5674 v8::Persistent<Context> context1 = Context::New();
5675 context1->Enter();
5676 v8::Handle<v8::Object> global1 = context1->Global();
5677 global1->Set(v8_str("other"), global0);
5678
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005679 // Regression test for issue 1154.
ricow@chromium.org65001782011-02-15 13:36:41 +00005680 ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005681
5682 ExpectUndefined("other.blocked_prop");
5683
5684 // Regression test for issue 1027.
5685 CompileRun("Object.defineProperty(\n"
5686 " other, 'blocked_prop', {configurable: false})");
5687 ExpectUndefined("other.blocked_prop");
5688 ExpectUndefined(
5689 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
5690
5691 // Regression test for issue 1171.
5692 ExpectTrue("Object.isExtensible(other)");
5693 CompileRun("Object.preventExtensions(other)");
5694 ExpectTrue("Object.isExtensible(other)");
5695
5696 // Object.seal and Object.freeze.
5697 CompileRun("Object.freeze(other)");
5698 ExpectTrue("Object.isExtensible(other)");
5699
5700 CompileRun("Object.seal(other)");
5701 ExpectTrue("Object.isExtensible(other)");
ricow@chromium.org65001782011-02-15 13:36:41 +00005702}
5703
5704
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005705static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
5706 Local<Value> name,
5707 v8::AccessType type,
5708 Local<Value> data) {
5709 return false;
5710}
5711
5712
5713static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
5714 uint32_t key,
5715 v8::AccessType type,
5716 Local<Value> data) {
5717 return false;
5718}
5719
5720
5721THREADED_TEST(AccessControlGetOwnPropertyNames) {
5722 v8::HandleScope handle_scope;
5723 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
5724
5725 obj_template->Set(v8_str("x"), v8::Integer::New(42));
5726 obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
5727 GetOwnPropertyNamesIndexedBlocker);
5728
5729 // Create an environment
5730 v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
5731 context0->Enter();
5732
5733 v8::Handle<v8::Object> global0 = context0->Global();
5734
5735 v8::HandleScope scope1;
5736
5737 v8::Persistent<Context> context1 = Context::New();
5738 context1->Enter();
5739
5740 v8::Handle<v8::Object> global1 = context1->Global();
5741 global1->Set(v8_str("other"), global0);
5742 global1->Set(v8_str("object"), obj_template->NewInstance());
5743
5744 v8::Handle<Value> value;
5745
5746 // Attempt to get the property names of the other global object and
5747 // of an object that requires access checks. Accessing the other
5748 // global object should be blocked by access checks on the global
5749 // proxy object. Accessing the object that requires access checks
5750 // is blocked by the access checks on the object itself.
5751 value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
5752 CHECK(value->IsTrue());
5753
5754 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
5755 CHECK(value->IsTrue());
5756
5757 context1->Exit();
5758 context0->Exit();
5759 context1.Dispose();
5760 context0.Dispose();
5761}
5762
5763
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00005764static v8::Handle<v8::Array> NamedPropertyEnumerator(const AccessorInfo& info) {
5765 v8::Handle<v8::Array> result = v8::Array::New(1);
5766 result->Set(0, v8_str("x"));
5767 return result;
5768}
5769
5770
5771THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
5772 v8::HandleScope handle_scope;
5773 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
5774
5775 obj_template->Set(v8_str("x"), v8::Integer::New(42));
5776 obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
5777 NamedPropertyEnumerator);
5778
5779 LocalContext context;
5780 v8::Handle<v8::Object> global = context->Global();
5781 global->Set(v8_str("object"), obj_template->NewInstance());
5782
5783 v8::Handle<Value> value =
5784 CompileRun("Object.getOwnPropertyNames(object).join(',')");
5785 CHECK_EQ(v8_str("x"), value);
5786}
5787
5788
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005789static v8::Handle<Value> ConstTenGetter(Local<String> name,
5790 const AccessorInfo& info) {
5791 return v8_num(10);
5792}
5793
5794
5795THREADED_TEST(CrossDomainAccessors) {
5796 v8::HandleScope handle_scope;
5797
5798 v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
5799
5800 v8::Handle<v8::ObjectTemplate> global_template =
5801 func_template->InstanceTemplate();
5802
5803 v8::Handle<v8::ObjectTemplate> proto_template =
5804 func_template->PrototypeTemplate();
5805
5806 // Add an accessor to proto that's accessible by cross-domain JS code.
5807 proto_template->SetAccessor(v8_str("accessible"),
5808 ConstTenGetter, 0,
5809 v8::Handle<Value>(),
5810 v8::ALL_CAN_READ);
5811
5812 // Add an accessor that is not accessible by cross-domain JS code.
5813 global_template->SetAccessor(v8_str("unreachable"),
5814 UnreachableGetter, 0,
5815 v8::Handle<Value>(),
5816 v8::DEFAULT);
5817
5818 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
5819 context0->Enter();
5820
5821 Local<v8::Object> global = context0->Global();
5822 // Add a normal property that shadows 'accessible'
5823 global->Set(v8_str("accessible"), v8_num(11));
5824
5825 // Enter a new context.
5826 v8::HandleScope scope1;
5827 v8::Persistent<Context> context1 = Context::New();
5828 context1->Enter();
5829
5830 v8::Handle<v8::Object> global1 = context1->Global();
5831 global1->Set(v8_str("other"), global);
5832
5833 // Should return 10, instead of 11
5834 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
5835 CHECK(value->IsNumber());
5836 CHECK_EQ(10, value->Int32Value());
5837
5838 value = v8_compile("other.unreachable")->Run();
5839 CHECK(value->IsUndefined());
5840
5841 context1->Exit();
5842 context0->Exit();
5843 context1.Dispose();
5844 context0.Dispose();
5845}
5846
5847
5848static int named_access_count = 0;
5849static int indexed_access_count = 0;
5850
5851static bool NamedAccessCounter(Local<v8::Object> global,
5852 Local<Value> name,
5853 v8::AccessType type,
5854 Local<Value> data) {
5855 named_access_count++;
5856 return true;
5857}
5858
5859
5860static bool IndexedAccessCounter(Local<v8::Object> global,
5861 uint32_t key,
5862 v8::AccessType type,
5863 Local<Value> data) {
5864 indexed_access_count++;
5865 return true;
5866}
5867
5868
5869// This one is too easily disturbed by other tests.
5870TEST(AccessControlIC) {
5871 named_access_count = 0;
5872 indexed_access_count = 0;
5873
5874 v8::HandleScope handle_scope;
5875
5876 // Create an environment.
5877 v8::Persistent<Context> context0 = Context::New();
5878 context0->Enter();
5879
5880 // Create an object that requires access-check functions to be
5881 // called for cross-domain access.
5882 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
5883 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
5884 IndexedAccessCounter);
5885 Local<v8::Object> object = object_template->NewInstance();
5886
5887 v8::HandleScope scope1;
5888
5889 // Create another environment.
5890 v8::Persistent<Context> context1 = Context::New();
5891 context1->Enter();
5892
5893 // Make easy access to the object from the other environment.
5894 v8::Handle<v8::Object> global1 = context1->Global();
5895 global1->Set(v8_str("obj"), object);
5896
5897 v8::Handle<Value> value;
5898
5899 // Check that the named access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00005900 CompileRun("function testProp(obj) {"
5901 " for (var i = 0; i < 10; i++) obj.prop = 1;"
5902 " for (var j = 0; j < 10; j++) obj.prop;"
5903 " return obj.prop"
5904 "}");
5905 value = CompileRun("testProp(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005906 CHECK(value->IsNumber());
5907 CHECK_EQ(1, value->Int32Value());
5908 CHECK_EQ(21, named_access_count);
5909
5910 // Check that the named access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00005911 CompileRun("var p = 'prop';"
5912 "function testKeyed(obj) {"
5913 " for (var i = 0; i < 10; i++) obj[p] = 1;"
5914 " for (var j = 0; j < 10; j++) obj[p];"
5915 " return obj[p];"
5916 "}");
5917 // Use obj which requires access checks. No inline caching is used
5918 // in that case.
5919 value = CompileRun("testKeyed(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005920 CHECK(value->IsNumber());
5921 CHECK_EQ(1, value->Int32Value());
5922 CHECK_EQ(42, named_access_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00005923 // Force the inline caches into generic state and try again.
5924 CompileRun("testKeyed({ a: 0 })");
5925 CompileRun("testKeyed({ b: 0 })");
5926 value = CompileRun("testKeyed(obj)");
5927 CHECK(value->IsNumber());
5928 CHECK_EQ(1, value->Int32Value());
5929 CHECK_EQ(63, named_access_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005930
5931 // Check that the indexed access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00005932 CompileRun("function testIndexed(obj) {"
5933 " for (var i = 0; i < 10; i++) obj[0] = 1;"
5934 " for (var j = 0; j < 10; j++) obj[0];"
5935 " return obj[0]"
5936 "}");
5937 value = CompileRun("testIndexed(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005938 CHECK(value->IsNumber());
5939 CHECK_EQ(1, value->Int32Value());
5940 CHECK_EQ(21, indexed_access_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00005941 // Force the inline caches into generic state.
5942 CompileRun("testIndexed(new Array(1))");
5943 // Test that the indexed access check is called.
5944 value = CompileRun("testIndexed(obj)");
5945 CHECK(value->IsNumber());
5946 CHECK_EQ(1, value->Int32Value());
5947 CHECK_EQ(42, indexed_access_count);
5948
5949 // Check that the named access check is called when invoking
5950 // functions on an object that requires access checks.
5951 CompileRun("obj.f = function() {}");
5952 CompileRun("function testCallNormal(obj) {"
5953 " for (var i = 0; i < 10; i++) obj.f();"
5954 "}");
5955 CompileRun("testCallNormal(obj)");
5956 CHECK_EQ(74, named_access_count);
5957
5958 // Force obj into slow case.
5959 value = CompileRun("delete obj.prop");
5960 CHECK(value->BooleanValue());
5961 // Force inline caches into dictionary probing mode.
5962 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
5963 // Test that the named access check is called.
5964 value = CompileRun("testProp(obj);");
5965 CHECK(value->IsNumber());
5966 CHECK_EQ(1, value->Int32Value());
5967 CHECK_EQ(96, named_access_count);
5968
5969 // Force the call inline cache into dictionary probing mode.
5970 CompileRun("o.f = function() {}; testCallNormal(o)");
5971 // Test that the named access check is still called for each
5972 // invocation of the function.
5973 value = CompileRun("testCallNormal(obj)");
5974 CHECK_EQ(106, named_access_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005975
5976 context1->Exit();
5977 context0->Exit();
5978 context1.Dispose();
5979 context0.Dispose();
5980}
5981
5982
5983static bool NamedAccessFlatten(Local<v8::Object> global,
5984 Local<Value> name,
5985 v8::AccessType type,
5986 Local<Value> data) {
5987 char buf[100];
5988 int len;
5989
5990 CHECK(name->IsString());
5991
5992 memset(buf, 0x1, sizeof(buf));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005993 len = name.As<String>()->WriteAscii(buf);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005994 CHECK_EQ(4, len);
5995
5996 uint16_t buf2[100];
5997
5998 memset(buf, 0x1, sizeof(buf));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005999 len = name.As<String>()->Write(buf2);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006000 CHECK_EQ(4, len);
6001
6002 return true;
6003}
6004
6005
6006static bool IndexedAccessFlatten(Local<v8::Object> global,
6007 uint32_t key,
6008 v8::AccessType type,
6009 Local<Value> data) {
6010 return true;
6011}
6012
6013
6014// Regression test. In access checks, operations that may cause
6015// garbage collection are not allowed. It used to be the case that
6016// using the Write operation on a string could cause a garbage
6017// collection due to flattening of the string. This is no longer the
6018// case.
6019THREADED_TEST(AccessControlFlatten) {
6020 named_access_count = 0;
6021 indexed_access_count = 0;
6022
6023 v8::HandleScope handle_scope;
6024
6025 // Create an environment.
6026 v8::Persistent<Context> context0 = Context::New();
6027 context0->Enter();
6028
6029 // Create an object that requires access-check functions to be
6030 // called for cross-domain access.
6031 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
6032 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
6033 IndexedAccessFlatten);
6034 Local<v8::Object> object = object_template->NewInstance();
6035
6036 v8::HandleScope scope1;
6037
6038 // Create another environment.
6039 v8::Persistent<Context> context1 = Context::New();
6040 context1->Enter();
6041
6042 // Make easy access to the object from the other environment.
6043 v8::Handle<v8::Object> global1 = context1->Global();
6044 global1->Set(v8_str("obj"), object);
6045
6046 v8::Handle<Value> value;
6047
6048 value = v8_compile("var p = 'as' + 'df';")->Run();
6049 value = v8_compile("obj[p];")->Run();
6050
6051 context1->Exit();
6052 context0->Exit();
6053 context1.Dispose();
6054 context0.Dispose();
6055}
6056
6057
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006058static v8::Handle<Value> AccessControlNamedGetter(
6059 Local<String>, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006060 return v8::Integer::New(42);
6061}
6062
6063
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006064static v8::Handle<Value> AccessControlNamedSetter(
6065 Local<String>, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006066 return value;
6067}
6068
6069
6070static v8::Handle<Value> AccessControlIndexedGetter(
6071 uint32_t index,
6072 const AccessorInfo& info) {
6073 return v8_num(42);
6074}
6075
6076
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006077static v8::Handle<Value> AccessControlIndexedSetter(
6078 uint32_t, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006079 return value;
6080}
6081
6082
6083THREADED_TEST(AccessControlInterceptorIC) {
6084 named_access_count = 0;
6085 indexed_access_count = 0;
6086
6087 v8::HandleScope handle_scope;
6088
6089 // Create an environment.
6090 v8::Persistent<Context> context0 = Context::New();
6091 context0->Enter();
6092
6093 // Create an object that requires access-check functions to be
6094 // called for cross-domain access. The object also has interceptors
6095 // interceptor.
6096 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
6097 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
6098 IndexedAccessCounter);
6099 object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
6100 AccessControlNamedSetter);
6101 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
6102 AccessControlIndexedSetter);
6103 Local<v8::Object> object = object_template->NewInstance();
6104
6105 v8::HandleScope scope1;
6106
6107 // Create another environment.
6108 v8::Persistent<Context> context1 = Context::New();
6109 context1->Enter();
6110
6111 // Make easy access to the object from the other environment.
6112 v8::Handle<v8::Object> global1 = context1->Global();
6113 global1->Set(v8_str("obj"), object);
6114
6115 v8::Handle<Value> value;
6116
6117 // Check that the named access-control function is called every time
6118 // eventhough there is an interceptor on the object.
6119 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
6120 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
6121 "obj.x")->Run();
6122 CHECK(value->IsNumber());
6123 CHECK_EQ(42, value->Int32Value());
6124 CHECK_EQ(21, named_access_count);
6125
6126 value = v8_compile("var p = 'x';")->Run();
6127 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
6128 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
6129 "obj[p]")->Run();
6130 CHECK(value->IsNumber());
6131 CHECK_EQ(42, value->Int32Value());
6132 CHECK_EQ(42, named_access_count);
6133
6134 // Check that the indexed access-control function is called every
6135 // time eventhough there is an interceptor on the object.
6136 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
6137 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
6138 "obj[0]")->Run();
6139 CHECK(value->IsNumber());
6140 CHECK_EQ(42, value->Int32Value());
6141 CHECK_EQ(21, indexed_access_count);
6142
6143 context1->Exit();
6144 context0->Exit();
6145 context1.Dispose();
6146 context0.Dispose();
6147}
6148
6149
6150THREADED_TEST(Version) {
6151 v8::V8::GetVersion();
6152}
6153
6154
6155static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
6156 ApiTestFuzzer::Fuzz();
6157 return v8_num(12);
6158}
6159
6160
6161THREADED_TEST(InstanceProperties) {
6162 v8::HandleScope handle_scope;
6163 LocalContext context;
6164
6165 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6166 Local<ObjectTemplate> instance = t->InstanceTemplate();
6167
6168 instance->Set(v8_str("x"), v8_num(42));
6169 instance->Set(v8_str("f"),
6170 v8::FunctionTemplate::New(InstanceFunctionCallback));
6171
6172 Local<Value> o = t->GetFunction()->NewInstance();
6173
6174 context->Global()->Set(v8_str("i"), o);
6175 Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
6176 CHECK_EQ(42, value->Int32Value());
6177
6178 value = Script::Compile(v8_str("i.f()"))->Run();
6179 CHECK_EQ(12, value->Int32Value());
6180}
6181
6182
6183static v8::Handle<Value>
6184GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
6185 ApiTestFuzzer::Fuzz();
6186 return v8::Handle<Value>();
6187}
6188
6189
6190THREADED_TEST(GlobalObjectInstanceProperties) {
6191 v8::HandleScope handle_scope;
6192
6193 Local<Value> global_object;
6194
6195 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6196 t->InstanceTemplate()->SetNamedPropertyHandler(
6197 GlobalObjectInstancePropertiesGet);
6198 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
6199 instance_template->Set(v8_str("x"), v8_num(42));
6200 instance_template->Set(v8_str("f"),
6201 v8::FunctionTemplate::New(InstanceFunctionCallback));
6202
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006203 // The script to check how Crankshaft compiles missing global function
6204 // invocations. function g is not defined and should throw on call.
6205 const char* script =
6206 "function wrapper(call) {"
6207 " var x = 0, y = 1;"
6208 " for (var i = 0; i < 1000; i++) {"
6209 " x += i * 100;"
6210 " y += i * 100;"
6211 " }"
6212 " if (call) g();"
6213 "}"
6214 "for (var i = 0; i < 17; i++) wrapper(false);"
6215 "var thrown = 0;"
6216 "try { wrapper(true); } catch (e) { thrown = 1; };"
6217 "thrown";
6218
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006219 {
6220 LocalContext env(NULL, instance_template);
6221 // Hold on to the global object so it can be used again in another
6222 // environment initialization.
6223 global_object = env->Global();
6224
6225 Local<Value> value = Script::Compile(v8_str("x"))->Run();
6226 CHECK_EQ(42, value->Int32Value());
6227 value = Script::Compile(v8_str("f()"))->Run();
6228 CHECK_EQ(12, value->Int32Value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006229 value = Script::Compile(v8_str(script))->Run();
6230 CHECK_EQ(1, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006231 }
6232
6233 {
6234 // Create new environment reusing the global object.
6235 LocalContext env(NULL, instance_template, global_object);
6236 Local<Value> value = Script::Compile(v8_str("x"))->Run();
6237 CHECK_EQ(42, value->Int32Value());
6238 value = Script::Compile(v8_str("f()"))->Run();
6239 CHECK_EQ(12, value->Int32Value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006240 value = Script::Compile(v8_str(script))->Run();
6241 CHECK_EQ(1, value->Int32Value());
6242 }
6243}
6244
6245
6246THREADED_TEST(CallKnownGlobalReceiver) {
6247 v8::HandleScope handle_scope;
6248
6249 Local<Value> global_object;
6250
6251 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6252 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
6253
6254 // The script to check that we leave global object not
6255 // global object proxy on stack when we deoptimize from inside
6256 // arguments evaluation.
6257 // To provoke error we need to both force deoptimization
6258 // from arguments evaluation and to force CallIC to take
6259 // CallIC_Miss code path that can't cope with global proxy.
6260 const char* script =
6261 "function bar(x, y) { try { } finally { } }"
6262 "function baz(x) { try { } finally { } }"
6263 "function bom(x) { try { } finally { } }"
6264 "function foo(x) { bar([x], bom(2)); }"
6265 "for (var i = 0; i < 10000; i++) foo(1);"
6266 "foo";
6267
6268 Local<Value> foo;
6269 {
6270 LocalContext env(NULL, instance_template);
6271 // Hold on to the global object so it can be used again in another
6272 // environment initialization.
6273 global_object = env->Global();
6274 foo = Script::Compile(v8_str(script))->Run();
6275 }
6276
6277 {
6278 // Create new environment reusing the global object.
6279 LocalContext env(NULL, instance_template, global_object);
6280 env->Global()->Set(v8_str("foo"), foo);
6281 Local<Value> value = Script::Compile(v8_str("foo()"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006282 }
6283}
6284
6285
6286static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
6287 ApiTestFuzzer::Fuzz();
6288 return v8_num(42);
6289}
6290
6291
6292static int shadow_y;
6293static int shadow_y_setter_call_count;
6294static int shadow_y_getter_call_count;
6295
6296
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006297static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006298 shadow_y_setter_call_count++;
6299 shadow_y = 42;
6300}
6301
6302
6303static v8::Handle<Value> ShadowYGetter(Local<String> name,
6304 const AccessorInfo& info) {
6305 ApiTestFuzzer::Fuzz();
6306 shadow_y_getter_call_count++;
6307 return v8_num(shadow_y);
6308}
6309
6310
6311static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
6312 const AccessorInfo& info) {
6313 return v8::Handle<Value>();
6314}
6315
6316
6317static v8::Handle<Value> ShadowNamedGet(Local<String> key,
6318 const AccessorInfo&) {
6319 return v8::Handle<Value>();
6320}
6321
6322
6323THREADED_TEST(ShadowObject) {
6324 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
6325 v8::HandleScope handle_scope;
6326
6327 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
6328 LocalContext context(NULL, global_template);
6329
6330 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6331 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
6332 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
6333 Local<ObjectTemplate> proto = t->PrototypeTemplate();
6334 Local<ObjectTemplate> instance = t->InstanceTemplate();
6335
6336 // Only allow calls of f on instances of t.
6337 Local<v8::Signature> signature = v8::Signature::New(t);
6338 proto->Set(v8_str("f"),
6339 v8::FunctionTemplate::New(ShadowFunctionCallback,
6340 Local<Value>(),
6341 signature));
6342 proto->Set(v8_str("x"), v8_num(12));
6343
6344 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
6345
6346 Local<Value> o = t->GetFunction()->NewInstance();
6347 context->Global()->Set(v8_str("__proto__"), o);
6348
6349 Local<Value> value =
6350 Script::Compile(v8_str("propertyIsEnumerable(0)"))->Run();
6351 CHECK(value->IsBoolean());
6352 CHECK(!value->BooleanValue());
6353
6354 value = Script::Compile(v8_str("x"))->Run();
6355 CHECK_EQ(12, value->Int32Value());
6356
6357 value = Script::Compile(v8_str("f()"))->Run();
6358 CHECK_EQ(42, value->Int32Value());
6359
6360 Script::Compile(v8_str("y = 42"))->Run();
6361 CHECK_EQ(1, shadow_y_setter_call_count);
6362 value = Script::Compile(v8_str("y"))->Run();
6363 CHECK_EQ(1, shadow_y_getter_call_count);
6364 CHECK_EQ(42, value->Int32Value());
6365}
6366
6367
6368THREADED_TEST(HiddenPrototype) {
6369 v8::HandleScope handle_scope;
6370 LocalContext context;
6371
6372 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
6373 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
6374 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
6375 t1->SetHiddenPrototype(true);
6376 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
6377 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
6378 t2->SetHiddenPrototype(true);
6379 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
6380 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
6381 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
6382
6383 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
6384 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
6385 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
6386 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
6387
6388 // Setting the prototype on an object skips hidden prototypes.
6389 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6390 o0->Set(v8_str("__proto__"), o1);
6391 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6392 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6393 o0->Set(v8_str("__proto__"), o2);
6394 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6395 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6396 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6397 o0->Set(v8_str("__proto__"), o3);
6398 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6399 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6400 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6401 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
6402
6403 // Getting the prototype of o0 should get the first visible one
6404 // which is o3. Therefore, z should not be defined on the prototype
6405 // object.
6406 Local<Value> proto = o0->Get(v8_str("__proto__"));
6407 CHECK(proto->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006408 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006409}
6410
6411
ager@chromium.org5c838252010-02-19 08:53:10 +00006412THREADED_TEST(SetPrototype) {
6413 v8::HandleScope handle_scope;
6414 LocalContext context;
6415
6416 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
6417 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
6418 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
6419 t1->SetHiddenPrototype(true);
6420 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
6421 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
6422 t2->SetHiddenPrototype(true);
6423 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
6424 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
6425 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
6426
6427 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
6428 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
6429 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
6430 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
6431
6432 // Setting the prototype on an object does not skip hidden prototypes.
6433 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6434 CHECK(o0->SetPrototype(o1));
6435 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6436 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6437 CHECK(o1->SetPrototype(o2));
6438 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6439 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6440 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6441 CHECK(o2->SetPrototype(o3));
6442 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6443 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6444 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6445 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
6446
6447 // Getting the prototype of o0 should get the first visible one
6448 // which is o3. Therefore, z should not be defined on the prototype
6449 // object.
6450 Local<Value> proto = o0->Get(v8_str("__proto__"));
6451 CHECK(proto->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006452 CHECK_EQ(proto.As<v8::Object>(), o3);
ager@chromium.org5c838252010-02-19 08:53:10 +00006453
6454 // However, Object::GetPrototype ignores hidden prototype.
6455 Local<Value> proto0 = o0->GetPrototype();
6456 CHECK(proto0->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006457 CHECK_EQ(proto0.As<v8::Object>(), o1);
ager@chromium.org5c838252010-02-19 08:53:10 +00006458
6459 Local<Value> proto1 = o1->GetPrototype();
6460 CHECK(proto1->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006461 CHECK_EQ(proto1.As<v8::Object>(), o2);
ager@chromium.org5c838252010-02-19 08:53:10 +00006462
6463 Local<Value> proto2 = o2->GetPrototype();
6464 CHECK(proto2->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006465 CHECK_EQ(proto2.As<v8::Object>(), o3);
ager@chromium.org5c838252010-02-19 08:53:10 +00006466}
6467
6468
6469THREADED_TEST(SetPrototypeThrows) {
6470 v8::HandleScope handle_scope;
6471 LocalContext context;
6472
6473 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6474
6475 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
6476 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
6477
6478 CHECK(o0->SetPrototype(o1));
6479 // If setting the prototype leads to the cycle, SetPrototype should
6480 // return false and keep VM in sane state.
6481 v8::TryCatch try_catch;
6482 CHECK(!o1->SetPrototype(o0));
6483 CHECK(!try_catch.HasCaught());
6484 ASSERT(!i::Top::has_pending_exception());
6485
6486 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
6487}
6488
6489
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006490THREADED_TEST(GetterSetterExceptions) {
6491 v8::HandleScope handle_scope;
6492 LocalContext context;
6493 CompileRun(
6494 "function Foo() { };"
6495 "function Throw() { throw 5; };"
6496 "var x = { };"
6497 "x.__defineSetter__('set', Throw);"
6498 "x.__defineGetter__('get', Throw);");
6499 Local<v8::Object> x =
6500 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
6501 v8::TryCatch try_catch;
6502 x->Set(v8_str("set"), v8::Integer::New(8));
6503 x->Get(v8_str("get"));
6504 x->Set(v8_str("set"), v8::Integer::New(8));
6505 x->Get(v8_str("get"));
6506 x->Set(v8_str("set"), v8::Integer::New(8));
6507 x->Get(v8_str("get"));
6508 x->Set(v8_str("set"), v8::Integer::New(8));
6509 x->Get(v8_str("get"));
6510}
6511
6512
6513THREADED_TEST(Constructor) {
6514 v8::HandleScope handle_scope;
6515 LocalContext context;
6516 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
6517 templ->SetClassName(v8_str("Fun"));
6518 Local<Function> cons = templ->GetFunction();
6519 context->Global()->Set(v8_str("Fun"), cons);
6520 Local<v8::Object> inst = cons->NewInstance();
6521 i::Handle<i::JSObject> obj = v8::Utils::OpenHandle(*inst);
6522 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
6523 CHECK(value->BooleanValue());
6524}
6525
6526THREADED_TEST(FunctionDescriptorException) {
6527 v8::HandleScope handle_scope;
6528 LocalContext context;
6529 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
6530 templ->SetClassName(v8_str("Fun"));
6531 Local<Function> cons = templ->GetFunction();
6532 context->Global()->Set(v8_str("Fun"), cons);
6533 Local<Value> value = CompileRun(
6534 "function test() {"
6535 " try {"
6536 " (new Fun()).blah()"
6537 " } catch (e) {"
6538 " var str = String(e);"
6539 " if (str.indexOf('TypeError') == -1) return 1;"
6540 " if (str.indexOf('[object Fun]') != -1) return 2;"
whesse@chromium.org7a392b32011-01-31 11:30:36 +00006541 " if (str.indexOf('#<Fun>') == -1) return 3;"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006542 " return 0;"
6543 " }"
6544 " return 4;"
6545 "}"
6546 "test();");
6547 CHECK_EQ(0, value->Int32Value());
6548}
6549
6550
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006551THREADED_TEST(EvalAliasedDynamic) {
6552 v8::HandleScope scope;
6553 LocalContext current;
6554
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006555 // Tests where aliased eval can only be resolved dynamically.
6556 Local<Script> script =
6557 Script::Compile(v8_str("function f(x) { "
6558 " var foo = 2;"
6559 " with (x) { return eval('foo'); }"
6560 "}"
6561 "foo = 0;"
6562 "result1 = f(new Object());"
ager@chromium.orge2902be2009-06-08 12:21:35 +00006563 "result2 = f(this);"
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006564 "var x = new Object();"
6565 "x.eval = function(x) { return 1; };"
6566 "result3 = f(x);"));
6567 script->Run();
6568 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
6569 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
6570 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
6571
6572 v8::TryCatch try_catch;
6573 script =
6574 Script::Compile(v8_str("function f(x) { "
6575 " var bar = 2;"
6576 " with (x) { return eval('bar'); }"
6577 "}"
ager@chromium.orge2902be2009-06-08 12:21:35 +00006578 "f(this)"));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006579 script->Run();
6580 CHECK(try_catch.HasCaught());
6581 try_catch.Reset();
6582}
6583
6584
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006585THREADED_TEST(CrossEval) {
6586 v8::HandleScope scope;
6587 LocalContext other;
6588 LocalContext current;
6589
6590 Local<String> token = v8_str("<security token>");
6591 other->SetSecurityToken(token);
6592 current->SetSecurityToken(token);
6593
6594 // Setup reference from current to other.
6595 current->Global()->Set(v8_str("other"), other->Global());
6596
6597 // Check that new variables are introduced in other context.
6598 Local<Script> script =
6599 Script::Compile(v8_str("other.eval('var foo = 1234')"));
6600 script->Run();
6601 Local<Value> foo = other->Global()->Get(v8_str("foo"));
6602 CHECK_EQ(1234, foo->Int32Value());
6603 CHECK(!current->Global()->Has(v8_str("foo")));
6604
6605 // Check that writing to non-existing properties introduces them in
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006606 // the other context.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006607 script =
6608 Script::Compile(v8_str("other.eval('na = 1234')"));
6609 script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006610 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
6611 CHECK(!current->Global()->Has(v8_str("na")));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006612
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006613 // Check that global variables in current context are not visible in other
6614 // context.
6615 v8::TryCatch try_catch;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006616 script =
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006617 Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006618 Local<Value> result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006619 CHECK(try_catch.HasCaught());
6620 try_catch.Reset();
6621
6622 // Check that local variables in current context are not visible in other
6623 // context.
6624 script =
6625 Script::Compile(v8_str("(function() { "
6626 " var baz = 87;"
6627 " return other.eval('baz');"
6628 "})();"));
6629 result = script->Run();
6630 CHECK(try_catch.HasCaught());
6631 try_catch.Reset();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006632
6633 // Check that global variables in the other environment are visible
6634 // when evaluting code.
6635 other->Global()->Set(v8_str("bis"), v8_num(1234));
6636 script = Script::Compile(v8_str("other.eval('bis')"));
6637 CHECK_EQ(1234, script->Run()->Int32Value());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006638 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006639
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006640 // Check that the 'this' pointer points to the global object evaluating
6641 // code.
6642 other->Global()->Set(v8_str("t"), other->Global());
6643 script = Script::Compile(v8_str("other.eval('this == t')"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006644 result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006645 CHECK(result->IsTrue());
6646 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006647
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006648 // Check that variables introduced in with-statement are not visible in
6649 // other context.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006650 script =
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006651 Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006652 result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006653 CHECK(try_catch.HasCaught());
6654 try_catch.Reset();
ager@chromium.org3bf7b912008-11-17 09:09:45 +00006655
6656 // Check that you cannot use 'eval.call' with another object than the
6657 // current global object.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00006658 script =
6659 Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
6660 result = script->Run();
6661 CHECK(try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006662}
6663
6664
ager@chromium.orge2902be2009-06-08 12:21:35 +00006665// Test that calling eval in a context which has been detached from
6666// its global throws an exception. This behavior is consistent with
6667// other JavaScript implementations.
6668THREADED_TEST(EvalInDetachedGlobal) {
6669 v8::HandleScope scope;
6670
6671 v8::Persistent<Context> context0 = Context::New();
6672 v8::Persistent<Context> context1 = Context::New();
6673
6674 // Setup function in context0 that uses eval from context0.
6675 context0->Enter();
6676 v8::Handle<v8::Value> fun =
6677 CompileRun("var x = 42;"
6678 "(function() {"
6679 " var e = eval;"
6680 " return function(s) { return e(s); }"
6681 "})()");
6682 context0->Exit();
6683
6684 // Put the function into context1 and call it before and after
6685 // detaching the global. Before detaching, the call succeeds and
6686 // after detaching and exception is thrown.
6687 context1->Enter();
6688 context1->Global()->Set(v8_str("fun"), fun);
6689 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
6690 CHECK_EQ(42, x_value->Int32Value());
6691 context0->DetachGlobal();
6692 v8::TryCatch catcher;
6693 x_value = CompileRun("fun('x')");
6694 CHECK(x_value.IsEmpty());
6695 CHECK(catcher.HasCaught());
6696 context1->Exit();
6697
6698 context1.Dispose();
6699 context0.Dispose();
6700}
6701
6702
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006703THREADED_TEST(CrossLazyLoad) {
6704 v8::HandleScope scope;
6705 LocalContext other;
6706 LocalContext current;
6707
6708 Local<String> token = v8_str("<security token>");
6709 other->SetSecurityToken(token);
6710 current->SetSecurityToken(token);
6711
6712 // Setup reference from current to other.
6713 current->Global()->Set(v8_str("other"), other->Global());
6714
6715 // Trigger lazy loading in other context.
6716 Local<Script> script =
6717 Script::Compile(v8_str("other.eval('new Date(42)')"));
6718 Local<Value> value = script->Run();
6719 CHECK_EQ(42.0, value->NumberValue());
6720}
6721
6722
6723static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
6724 ApiTestFuzzer::Fuzz();
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00006725 if (args.IsConstructCall()) {
6726 if (args[0]->IsInt32()) {
6727 return v8_num(-args[0]->Int32Value());
6728 }
6729 }
6730
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006731 return args[0];
6732}
6733
6734
6735// Test that a call handler can be set for objects which will allow
6736// non-function objects created through the API to be called as
6737// functions.
6738THREADED_TEST(CallAsFunction) {
6739 v8::HandleScope scope;
6740 LocalContext context;
6741
6742 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6743 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
6744 instance_template->SetCallAsFunctionHandler(call_as_function);
6745 Local<v8::Object> instance = t->GetFunction()->NewInstance();
6746 context->Global()->Set(v8_str("obj"), instance);
6747 v8::TryCatch try_catch;
6748 Local<Value> value;
6749 CHECK(!try_catch.HasCaught());
6750
ager@chromium.org9085a012009-05-11 19:22:57 +00006751 value = CompileRun("obj(42)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006752 CHECK(!try_catch.HasCaught());
6753 CHECK_EQ(42, value->Int32Value());
6754
ager@chromium.org9085a012009-05-11 19:22:57 +00006755 value = CompileRun("(function(o){return o(49)})(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006756 CHECK(!try_catch.HasCaught());
6757 CHECK_EQ(49, value->Int32Value());
6758
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006759 // test special case of call as function
ager@chromium.org9085a012009-05-11 19:22:57 +00006760 value = CompileRun("[obj]['0'](45)");
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006761 CHECK(!try_catch.HasCaught());
6762 CHECK_EQ(45, value->Int32Value());
6763
ager@chromium.org9085a012009-05-11 19:22:57 +00006764 value = CompileRun("obj.call = Function.prototype.call;"
6765 "obj.call(null, 87)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006766 CHECK(!try_catch.HasCaught());
6767 CHECK_EQ(87, value->Int32Value());
6768
6769 // Regression tests for bug #1116356: Calling call through call/apply
6770 // must work for non-function receivers.
6771 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
ager@chromium.org9085a012009-05-11 19:22:57 +00006772 value = CompileRun(apply_99);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006773 CHECK(!try_catch.HasCaught());
6774 CHECK_EQ(99, value->Int32Value());
6775
6776 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
ager@chromium.org9085a012009-05-11 19:22:57 +00006777 value = CompileRun(call_17);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006778 CHECK(!try_catch.HasCaught());
6779 CHECK_EQ(17, value->Int32Value());
ager@chromium.org9085a012009-05-11 19:22:57 +00006780
6781 // Check that the call-as-function handler can be called through
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006782 // new.
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00006783 value = CompileRun("new obj(43)");
ager@chromium.org9085a012009-05-11 19:22:57 +00006784 CHECK(!try_catch.HasCaught());
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00006785 CHECK_EQ(-43, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006786}
6787
6788
6789static int CountHandles() {
6790 return v8::HandleScope::NumberOfHandles();
6791}
6792
6793
6794static int Recurse(int depth, int iterations) {
6795 v8::HandleScope scope;
6796 if (depth == 0) return CountHandles();
6797 for (int i = 0; i < iterations; i++) {
6798 Local<v8::Number> n = v8::Integer::New(42);
6799 }
6800 return Recurse(depth - 1, iterations);
6801}
6802
6803
6804THREADED_TEST(HandleIteration) {
6805 static const int kIterations = 500;
6806 static const int kNesting = 200;
6807 CHECK_EQ(0, CountHandles());
6808 {
6809 v8::HandleScope scope1;
6810 CHECK_EQ(0, CountHandles());
6811 for (int i = 0; i < kIterations; i++) {
6812 Local<v8::Number> n = v8::Integer::New(42);
6813 CHECK_EQ(i + 1, CountHandles());
6814 }
6815
6816 CHECK_EQ(kIterations, CountHandles());
6817 {
6818 v8::HandleScope scope2;
6819 for (int j = 0; j < kIterations; j++) {
6820 Local<v8::Number> n = v8::Integer::New(42);
6821 CHECK_EQ(j + 1 + kIterations, CountHandles());
6822 }
6823 }
6824 CHECK_EQ(kIterations, CountHandles());
6825 }
6826 CHECK_EQ(0, CountHandles());
6827 CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
6828}
6829
6830
6831static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
6832 Local<String> name,
6833 const AccessorInfo& info) {
6834 ApiTestFuzzer::Fuzz();
6835 return v8::Handle<Value>();
6836}
6837
6838
6839THREADED_TEST(InterceptorHasOwnProperty) {
6840 v8::HandleScope scope;
6841 LocalContext context;
6842 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6843 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
6844 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
6845 Local<Function> function = fun_templ->GetFunction();
6846 context->Global()->Set(v8_str("constructor"), function);
6847 v8::Handle<Value> value = CompileRun(
6848 "var o = new constructor();"
6849 "o.hasOwnProperty('ostehaps');");
6850 CHECK_EQ(false, value->BooleanValue());
6851 value = CompileRun(
6852 "o.ostehaps = 42;"
6853 "o.hasOwnProperty('ostehaps');");
6854 CHECK_EQ(true, value->BooleanValue());
6855 value = CompileRun(
6856 "var p = new constructor();"
6857 "p.hasOwnProperty('ostehaps');");
6858 CHECK_EQ(false, value->BooleanValue());
6859}
6860
6861
ager@chromium.org9085a012009-05-11 19:22:57 +00006862static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
6863 Local<String> name,
6864 const AccessorInfo& info) {
6865 ApiTestFuzzer::Fuzz();
ager@chromium.orgab99eea2009-08-25 07:05:41 +00006866 i::Heap::CollectAllGarbage(false);
ager@chromium.org9085a012009-05-11 19:22:57 +00006867 return v8::Handle<Value>();
6868}
6869
6870
6871THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
6872 v8::HandleScope scope;
6873 LocalContext context;
6874 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6875 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
6876 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
6877 Local<Function> function = fun_templ->GetFunction();
6878 context->Global()->Set(v8_str("constructor"), function);
6879 // Let's first make some stuff so we can be sure to get a good GC.
6880 CompileRun(
6881 "function makestr(size) {"
6882 " switch (size) {"
6883 " case 1: return 'f';"
6884 " case 2: return 'fo';"
6885 " case 3: return 'foo';"
6886 " }"
6887 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
6888 "}"
6889 "var x = makestr(12345);"
6890 "x = makestr(31415);"
6891 "x = makestr(23456);");
6892 v8::Handle<Value> value = CompileRun(
6893 "var o = new constructor();"
6894 "o.__proto__ = new String(x);"
6895 "o.hasOwnProperty('ostehaps');");
6896 CHECK_EQ(false, value->BooleanValue());
6897}
6898
6899
ager@chromium.orge2902be2009-06-08 12:21:35 +00006900typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
6901 const AccessorInfo& info);
6902
6903
6904static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
6905 const char* source,
6906 int expected) {
6907 v8::HandleScope scope;
6908 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006909 templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
ager@chromium.orge2902be2009-06-08 12:21:35 +00006910 LocalContext context;
6911 context->Global()->Set(v8_str("o"), templ->NewInstance());
6912 v8::Handle<Value> value = CompileRun(source);
6913 CHECK_EQ(expected, value->Int32Value());
6914}
6915
6916
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006917static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
6918 const AccessorInfo& info) {
6919 ApiTestFuzzer::Fuzz();
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006920 CHECK_EQ(v8_str("data"), info.Data());
6921 CHECK_EQ(v8_str("x"), name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006922 return v8::Integer::New(42);
6923}
6924
6925
6926// This test should hit the load IC for the interceptor case.
6927THREADED_TEST(InterceptorLoadIC) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00006928 CheckInterceptorLoadIC(InterceptorLoadICGetter,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006929 "var result = 0;"
6930 "for (var i = 0; i < 1000; i++) {"
6931 " result = o.x;"
ager@chromium.orge2902be2009-06-08 12:21:35 +00006932 "}",
6933 42);
6934}
6935
6936
6937// Below go several tests which verify that JITing for various
6938// configurations of interceptor and explicit fields works fine
6939// (those cases are special cased to get better performance).
6940
6941static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
6942 const AccessorInfo& info) {
6943 ApiTestFuzzer::Fuzz();
6944 return v8_str("x")->Equals(name)
6945 ? v8::Integer::New(42) : v8::Handle<v8::Value>();
6946}
6947
6948
6949THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
6950 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6951 "var result = 0;"
6952 "o.y = 239;"
6953 "for (var i = 0; i < 1000; i++) {"
6954 " result = o.y;"
6955 "}",
6956 239);
6957}
6958
6959
6960THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
6961 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6962 "var result = 0;"
6963 "o.__proto__ = { 'y': 239 };"
6964 "for (var i = 0; i < 1000; i++) {"
6965 " result = o.y + o.x;"
6966 "}",
6967 239 + 42);
6968}
6969
6970
6971THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
6972 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6973 "var result = 0;"
6974 "o.__proto__.y = 239;"
6975 "for (var i = 0; i < 1000; i++) {"
6976 " result = o.y + o.x;"
6977 "}",
6978 239 + 42);
6979}
6980
6981
6982THREADED_TEST(InterceptorLoadICUndefined) {
6983 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6984 "var result = 0;"
6985 "for (var i = 0; i < 1000; i++) {"
6986 " result = (o.y == undefined) ? 239 : 42;"
6987 "}",
6988 239);
6989}
6990
6991
6992THREADED_TEST(InterceptorLoadICWithOverride) {
6993 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6994 "fst = new Object(); fst.__proto__ = o;"
6995 "snd = new Object(); snd.__proto__ = fst;"
6996 "var result1 = 0;"
6997 "for (var i = 0; i < 1000; i++) {"
6998 " result1 = snd.x;"
6999 "}"
7000 "fst.x = 239;"
7001 "var result = 0;"
7002 "for (var i = 0; i < 1000; i++) {"
7003 " result = snd.x;"
7004 "}"
7005 "result + result1",
7006 239 + 42);
7007}
7008
7009
kasperl@chromium.orge959c182009-07-27 08:59:04 +00007010// Test the case when we stored field into
7011// a stub, but interceptor produced value on its own.
7012THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
7013 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7014 "proto = new Object();"
7015 "o.__proto__ = proto;"
7016 "proto.x = 239;"
7017 "for (var i = 0; i < 1000; i++) {"
7018 " o.x;"
7019 // Now it should be ICed and keep a reference to x defined on proto
7020 "}"
7021 "var result = 0;"
7022 "for (var i = 0; i < 1000; i++) {"
7023 " result += o.x;"
7024 "}"
7025 "result;",
7026 42 * 1000);
7027}
7028
7029
7030// Test the case when we stored field into
7031// a stub, but it got invalidated later on.
7032THREADED_TEST(InterceptorLoadICInvalidatedField) {
7033 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7034 "proto1 = new Object();"
7035 "proto2 = new Object();"
7036 "o.__proto__ = proto1;"
7037 "proto1.__proto__ = proto2;"
7038 "proto2.y = 239;"
7039 "for (var i = 0; i < 1000; i++) {"
7040 " o.y;"
7041 // Now it should be ICed and keep a reference to y defined on proto2
7042 "}"
7043 "proto1.y = 42;"
7044 "var result = 0;"
7045 "for (var i = 0; i < 1000; i++) {"
7046 " result += o.y;"
7047 "}"
7048 "result;",
7049 42 * 1000);
7050}
7051
7052
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00007053static int interceptor_load_not_handled_calls = 0;
7054static v8::Handle<Value> InterceptorLoadNotHandled(Local<String> name,
7055 const AccessorInfo& info) {
7056 ++interceptor_load_not_handled_calls;
7057 return v8::Handle<v8::Value>();
7058}
7059
7060
7061// Test how post-interceptor lookups are done in the non-cacheable
7062// case: the interceptor should not be invoked during this lookup.
7063THREADED_TEST(InterceptorLoadICPostInterceptor) {
7064 interceptor_load_not_handled_calls = 0;
7065 CheckInterceptorLoadIC(InterceptorLoadNotHandled,
7066 "receiver = new Object();"
7067 "receiver.__proto__ = o;"
7068 "proto = new Object();"
7069 "/* Make proto a slow-case object. */"
7070 "for (var i = 0; i < 1000; i++) {"
7071 " proto[\"xxxxxxxx\" + i] = [];"
7072 "}"
7073 "proto.x = 17;"
7074 "o.__proto__ = proto;"
7075 "var result = 0;"
7076 "for (var i = 0; i < 1000; i++) {"
7077 " result += receiver.x;"
7078 "}"
7079 "result;",
7080 17 * 1000);
7081 CHECK_EQ(1000, interceptor_load_not_handled_calls);
7082}
7083
7084
kasperl@chromium.orge959c182009-07-27 08:59:04 +00007085// Test the case when we stored field into
7086// a stub, but it got invalidated later on due to override on
7087// global object which is between interceptor and fields' holders.
7088THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
7089 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7090 "o.__proto__ = this;" // set a global to be a proto of o.
7091 "this.__proto__.y = 239;"
7092 "for (var i = 0; i < 10; i++) {"
7093 " if (o.y != 239) throw 'oops: ' + o.y;"
7094 // Now it should be ICed and keep a reference to y defined on field_holder.
7095 "}"
7096 "this.y = 42;" // Assign on a global.
7097 "var result = 0;"
7098 "for (var i = 0; i < 10; i++) {"
7099 " result += o.y;"
7100 "}"
7101 "result;",
7102 42 * 10);
7103}
7104
7105
kasperl@chromium.orge959c182009-07-27 08:59:04 +00007106static void SetOnThis(Local<String> name,
7107 Local<Value> value,
7108 const AccessorInfo& info) {
7109 info.This()->ForceSet(name, value);
7110}
7111
7112
7113THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
7114 v8::HandleScope scope;
7115 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7116 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7117 templ->SetAccessor(v8_str("y"), Return239);
7118 LocalContext context;
7119 context->Global()->Set(v8_str("o"), templ->NewInstance());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007120
7121 // Check the case when receiver and interceptor's holder
7122 // are the same objects.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00007123 v8::Handle<Value> value = CompileRun(
7124 "var result = 0;"
7125 "for (var i = 0; i < 7; i++) {"
7126 " result = o.y;"
7127 "}");
7128 CHECK_EQ(239, value->Int32Value());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007129
7130 // Check the case when interceptor's holder is in proto chain
7131 // of receiver.
7132 value = CompileRun(
7133 "r = { __proto__: o };"
7134 "var result = 0;"
7135 "for (var i = 0; i < 7; i++) {"
7136 " result = r.y;"
7137 "}");
7138 CHECK_EQ(239, value->Int32Value());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00007139}
7140
7141
7142THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
7143 v8::HandleScope scope;
7144 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7145 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7146 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
7147 templ_p->SetAccessor(v8_str("y"), Return239);
7148
7149 LocalContext context;
7150 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7151 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
7152
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007153 // Check the case when receiver and interceptor's holder
7154 // are the same objects.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00007155 v8::Handle<Value> value = CompileRun(
7156 "o.__proto__ = p;"
7157 "var result = 0;"
7158 "for (var i = 0; i < 7; i++) {"
7159 " result = o.x + o.y;"
7160 "}");
7161 CHECK_EQ(239 + 42, value->Int32Value());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007162
7163 // Check the case when interceptor's holder is in proto chain
7164 // of receiver.
7165 value = CompileRun(
7166 "r = { __proto__: o };"
7167 "var result = 0;"
7168 "for (var i = 0; i < 7; i++) {"
7169 " result = r.x + r.y;"
7170 "}");
7171 CHECK_EQ(239 + 42, value->Int32Value());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00007172}
7173
7174
7175THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
7176 v8::HandleScope scope;
7177 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7178 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7179 templ->SetAccessor(v8_str("y"), Return239);
7180
7181 LocalContext context;
7182 context->Global()->Set(v8_str("o"), templ->NewInstance());
7183
7184 v8::Handle<Value> value = CompileRun(
7185 "fst = new Object(); fst.__proto__ = o;"
7186 "snd = new Object(); snd.__proto__ = fst;"
7187 "var result1 = 0;"
7188 "for (var i = 0; i < 7; i++) {"
7189 " result1 = snd.x;"
7190 "}"
7191 "fst.x = 239;"
7192 "var result = 0;"
7193 "for (var i = 0; i < 7; i++) {"
7194 " result = snd.x;"
7195 "}"
7196 "result + result1");
7197 CHECK_EQ(239 + 42, value->Int32Value());
7198}
7199
7200
7201// Test the case when we stored callback into
7202// a stub, but interceptor produced value on its own.
7203THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
7204 v8::HandleScope scope;
7205 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7206 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7207 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
7208 templ_p->SetAccessor(v8_str("y"), Return239);
7209
7210 LocalContext context;
7211 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7212 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
7213
7214 v8::Handle<Value> value = CompileRun(
7215 "o.__proto__ = p;"
7216 "for (var i = 0; i < 7; i++) {"
7217 " o.x;"
7218 // Now it should be ICed and keep a reference to x defined on p
7219 "}"
7220 "var result = 0;"
7221 "for (var i = 0; i < 7; i++) {"
7222 " result += o.x;"
7223 "}"
7224 "result");
7225 CHECK_EQ(42 * 7, value->Int32Value());
7226}
7227
7228
7229// Test the case when we stored callback into
7230// a stub, but it got invalidated later on.
7231THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
7232 v8::HandleScope scope;
7233 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7234 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7235 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
7236 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
7237
7238 LocalContext context;
7239 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7240 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
7241
7242 v8::Handle<Value> value = CompileRun(
7243 "inbetween = new Object();"
7244 "o.__proto__ = inbetween;"
7245 "inbetween.__proto__ = p;"
7246 "for (var i = 0; i < 10; i++) {"
7247 " o.y;"
7248 // Now it should be ICed and keep a reference to y defined on p
7249 "}"
7250 "inbetween.y = 42;"
7251 "var result = 0;"
7252 "for (var i = 0; i < 10; i++) {"
7253 " result += o.y;"
7254 "}"
7255 "result");
7256 CHECK_EQ(42 * 10, value->Int32Value());
7257}
7258
7259
7260// Test the case when we stored callback into
7261// a stub, but it got invalidated later on due to override on
7262// global object which is between interceptor and callbacks' holders.
7263THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
7264 v8::HandleScope scope;
7265 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7266 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7267 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
7268 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
7269
7270 LocalContext context;
7271 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7272 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
7273
7274 v8::Handle<Value> value = CompileRun(
7275 "o.__proto__ = this;"
7276 "this.__proto__ = p;"
7277 "for (var i = 0; i < 10; i++) {"
7278 " if (o.y != 239) throw 'oops: ' + o.y;"
7279 // Now it should be ICed and keep a reference to y defined on p
7280 "}"
7281 "this.y = 42;"
7282 "var result = 0;"
7283 "for (var i = 0; i < 10; i++) {"
7284 " result += o.y;"
7285 "}"
7286 "result");
7287 CHECK_EQ(42 * 10, value->Int32Value());
7288}
7289
7290
ager@chromium.orge2902be2009-06-08 12:21:35 +00007291static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
7292 const AccessorInfo& info) {
7293 ApiTestFuzzer::Fuzz();
7294 CHECK(v8_str("x")->Equals(name));
7295 return v8::Integer::New(0);
7296}
7297
7298
7299THREADED_TEST(InterceptorReturningZero) {
7300 CheckInterceptorLoadIC(InterceptorLoadICGetter0,
7301 "o.x == undefined ? 1 : 0",
7302 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007303}
7304
7305
7306static v8::Handle<Value> InterceptorStoreICSetter(
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007307 Local<String> key, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007308 CHECK(v8_str("x")->Equals(key));
7309 CHECK_EQ(42, value->Int32Value());
7310 return value;
7311}
7312
7313
7314// This test should hit the store IC for the interceptor case.
7315THREADED_TEST(InterceptorStoreIC) {
7316 v8::HandleScope scope;
7317 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7318 templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007319 InterceptorStoreICSetter,
7320 0, 0, 0, v8_str("data"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007321 LocalContext context;
7322 context->Global()->Set(v8_str("o"), templ->NewInstance());
7323 v8::Handle<Value> value = CompileRun(
7324 "for (var i = 0; i < 1000; i++) {"
7325 " o.x = 42;"
7326 "}");
7327}
7328
7329
ager@chromium.orgeadaf222009-06-16 09:43:10 +00007330THREADED_TEST(InterceptorStoreICWithNoSetter) {
7331 v8::HandleScope scope;
7332 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7333 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7334 LocalContext context;
7335 context->Global()->Set(v8_str("o"), templ->NewInstance());
7336 v8::Handle<Value> value = CompileRun(
7337 "for (var i = 0; i < 1000; i++) {"
7338 " o.y = 239;"
7339 "}"
7340 "42 + o.y");
7341 CHECK_EQ(239 + 42, value->Int32Value());
7342}
7343
7344
7345
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007346
7347v8::Handle<Value> call_ic_function;
7348v8::Handle<Value> call_ic_function2;
7349v8::Handle<Value> call_ic_function3;
7350
7351static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
7352 const AccessorInfo& info) {
7353 ApiTestFuzzer::Fuzz();
7354 CHECK(v8_str("x")->Equals(name));
7355 return call_ic_function;
7356}
7357
7358
7359// This test should hit the call IC for the interceptor case.
7360THREADED_TEST(InterceptorCallIC) {
7361 v8::HandleScope scope;
7362 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7363 templ->SetNamedPropertyHandler(InterceptorCallICGetter);
7364 LocalContext context;
7365 context->Global()->Set(v8_str("o"), templ->NewInstance());
7366 call_ic_function =
7367 v8_compile("function f(x) { return x + 1; }; f")->Run();
7368 v8::Handle<Value> value = CompileRun(
7369 "var result = 0;"
7370 "for (var i = 0; i < 1000; i++) {"
7371 " result = o.x(41);"
7372 "}");
7373 CHECK_EQ(42, value->Int32Value());
7374}
7375
kasperl@chromium.orge959c182009-07-27 08:59:04 +00007376
7377// This test checks that if interceptor doesn't provide
7378// a value, we can fetch regular value.
7379THREADED_TEST(InterceptorCallICSeesOthers) {
7380 v8::HandleScope scope;
7381 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7382 templ->SetNamedPropertyHandler(NoBlockGetterX);
7383 LocalContext context;
7384 context->Global()->Set(v8_str("o"), templ->NewInstance());
7385 v8::Handle<Value> value = CompileRun(
7386 "o.x = function f(x) { return x + 1; };"
7387 "var result = 0;"
7388 "for (var i = 0; i < 7; i++) {"
7389 " result = o.x(41);"
7390 "}");
7391 CHECK_EQ(42, value->Int32Value());
7392}
7393
7394
7395static v8::Handle<Value> call_ic_function4;
7396static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
7397 const AccessorInfo& info) {
7398 ApiTestFuzzer::Fuzz();
7399 CHECK(v8_str("x")->Equals(name));
7400 return call_ic_function4;
7401}
7402
7403
7404// This test checks that if interceptor provides a function,
7405// even if we cached shadowed variant, interceptor's function
7406// is invoked
7407THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
7408 v8::HandleScope scope;
7409 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7410 templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
7411 LocalContext context;
7412 context->Global()->Set(v8_str("o"), templ->NewInstance());
7413 call_ic_function4 =
7414 v8_compile("function f(x) { return x - 1; }; f")->Run();
7415 v8::Handle<Value> value = CompileRun(
7416 "o.__proto__.x = function(x) { return x + 1; };"
7417 "var result = 0;"
7418 "for (var i = 0; i < 1000; i++) {"
7419 " result = o.x(42);"
7420 "}");
7421 CHECK_EQ(41, value->Int32Value());
7422}
7423
7424
7425// Test the case when we stored cacheable lookup into
7426// a stub, but it got invalidated later on
7427THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
7428 v8::HandleScope scope;
7429 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7430 templ->SetNamedPropertyHandler(NoBlockGetterX);
7431 LocalContext context;
7432 context->Global()->Set(v8_str("o"), templ->NewInstance());
7433 v8::Handle<Value> value = CompileRun(
7434 "proto1 = new Object();"
7435 "proto2 = new Object();"
7436 "o.__proto__ = proto1;"
7437 "proto1.__proto__ = proto2;"
7438 "proto2.y = function(x) { return x + 1; };"
7439 // Invoke it many times to compile a stub
7440 "for (var i = 0; i < 7; i++) {"
7441 " o.y(42);"
7442 "}"
7443 "proto1.y = function(x) { return x - 1; };"
7444 "var result = 0;"
7445 "for (var i = 0; i < 7; i++) {"
7446 " result += o.y(42);"
7447 "}");
7448 CHECK_EQ(41 * 7, value->Int32Value());
7449}
7450
7451
7452static v8::Handle<Value> call_ic_function5;
7453static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
7454 const AccessorInfo& info) {
7455 ApiTestFuzzer::Fuzz();
7456 if (v8_str("x")->Equals(name))
7457 return call_ic_function5;
7458 else
7459 return Local<Value>();
7460}
7461
7462
7463// This test checks that if interceptor doesn't provide a function,
7464// cached constant function is used
7465THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
7466 v8::HandleScope scope;
7467 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7468 templ->SetNamedPropertyHandler(NoBlockGetterX);
7469 LocalContext context;
7470 context->Global()->Set(v8_str("o"), templ->NewInstance());
7471 v8::Handle<Value> value = CompileRun(
7472 "function inc(x) { return x + 1; };"
7473 "inc(1);"
7474 "o.x = inc;"
7475 "var result = 0;"
7476 "for (var i = 0; i < 1000; i++) {"
7477 " result = o.x(42);"
7478 "}");
7479 CHECK_EQ(43, value->Int32Value());
7480}
7481
7482
7483// This test checks that if interceptor provides a function,
7484// even if we cached constant function, interceptor's function
7485// is invoked
7486THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
7487 v8::HandleScope scope;
7488 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7489 templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
7490 LocalContext context;
7491 context->Global()->Set(v8_str("o"), templ->NewInstance());
7492 call_ic_function5 =
7493 v8_compile("function f(x) { return x - 1; }; f")->Run();
7494 v8::Handle<Value> value = CompileRun(
7495 "function inc(x) { return x + 1; };"
7496 "inc(1);"
7497 "o.x = inc;"
7498 "var result = 0;"
7499 "for (var i = 0; i < 1000; i++) {"
7500 " result = o.x(42);"
7501 "}");
7502 CHECK_EQ(41, value->Int32Value());
7503}
7504
7505
7506// Test the case when we stored constant function into
7507// a stub, but it got invalidated later on
7508THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
7509 v8::HandleScope scope;
7510 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7511 templ->SetNamedPropertyHandler(NoBlockGetterX);
7512 LocalContext context;
7513 context->Global()->Set(v8_str("o"), templ->NewInstance());
7514 v8::Handle<Value> value = CompileRun(
7515 "function inc(x) { return x + 1; };"
7516 "inc(1);"
7517 "proto1 = new Object();"
7518 "proto2 = new Object();"
7519 "o.__proto__ = proto1;"
7520 "proto1.__proto__ = proto2;"
7521 "proto2.y = inc;"
7522 // Invoke it many times to compile a stub
7523 "for (var i = 0; i < 7; i++) {"
7524 " o.y(42);"
7525 "}"
7526 "proto1.y = function(x) { return x - 1; };"
7527 "var result = 0;"
7528 "for (var i = 0; i < 7; i++) {"
7529 " result += o.y(42);"
7530 "}");
7531 CHECK_EQ(41 * 7, value->Int32Value());
7532}
7533
7534
7535// Test the case when we stored constant function into
7536// a stub, but it got invalidated later on due to override on
7537// global object which is between interceptor and constant function' holders.
7538THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
7539 v8::HandleScope scope;
7540 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7541 templ->SetNamedPropertyHandler(NoBlockGetterX);
7542 LocalContext context;
7543 context->Global()->Set(v8_str("o"), templ->NewInstance());
7544 v8::Handle<Value> value = CompileRun(
7545 "function inc(x) { return x + 1; };"
7546 "inc(1);"
7547 "o.__proto__ = this;"
7548 "this.__proto__.y = inc;"
7549 // Invoke it many times to compile a stub
7550 "for (var i = 0; i < 7; i++) {"
7551 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
7552 "}"
7553 "this.y = function(x) { return x - 1; };"
7554 "var result = 0;"
7555 "for (var i = 0; i < 7; i++) {"
7556 " result += o.y(42);"
7557 "}");
7558 CHECK_EQ(41 * 7, value->Int32Value());
7559}
7560
7561
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007562// Test the case when actual function to call sits on global object.
7563THREADED_TEST(InterceptorCallICCachedFromGlobal) {
7564 v8::HandleScope scope;
7565 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7566 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
7567
7568 LocalContext context;
7569 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7570
7571 v8::Handle<Value> value = CompileRun(
7572 "try {"
7573 " o.__proto__ = this;"
7574 " for (var i = 0; i < 10; i++) {"
7575 " var v = o.parseFloat('239');"
7576 " if (v != 239) throw v;"
7577 // Now it should be ICed and keep a reference to parseFloat.
7578 " }"
7579 " var result = 0;"
7580 " for (var i = 0; i < 10; i++) {"
7581 " result += o.parseFloat('239');"
7582 " }"
7583 " result"
7584 "} catch(e) {"
7585 " e"
7586 "};");
7587 CHECK_EQ(239 * 10, value->Int32Value());
7588}
7589
ager@chromium.org5c838252010-02-19 08:53:10 +00007590static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
7591 const AccessorInfo& info) {
7592 ApiTestFuzzer::Fuzz();
7593 int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data()));
7594 ++(*call_count);
7595 if ((*call_count) % 20 == 0) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +00007596 i::Heap::CollectAllGarbage(true);
ager@chromium.org5c838252010-02-19 08:53:10 +00007597 }
7598 return v8::Handle<Value>();
7599}
7600
7601static v8::Handle<Value> FastApiCallback_TrivialSignature(
7602 const v8::Arguments& args) {
7603 ApiTestFuzzer::Fuzz();
7604 CHECK_EQ(args.This(), args.Holder());
7605 CHECK(args.Data()->Equals(v8_str("method_data")));
7606 return v8::Integer::New(args[0]->Int32Value() + 1);
7607}
7608
7609static v8::Handle<Value> FastApiCallback_SimpleSignature(
7610 const v8::Arguments& args) {
7611 ApiTestFuzzer::Fuzz();
7612 CHECK_EQ(args.This()->GetPrototype(), args.Holder());
7613 CHECK(args.Data()->Equals(v8_str("method_data")));
7614 // Note, we're using HasRealNamedProperty instead of Has to avoid
7615 // invoking the interceptor again.
7616 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
7617 return v8::Integer::New(args[0]->Int32Value() + 1);
7618}
7619
7620// Helper to maximize the odds of object moving.
7621static void GenerateSomeGarbage() {
7622 CompileRun(
7623 "var garbage;"
7624 "for (var i = 0; i < 1000; i++) {"
7625 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
7626 "}"
7627 "garbage = undefined;");
7628}
7629
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007630
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007631v8::Handle<v8::Value> DirectApiCallback(const v8::Arguments& args) {
7632 static int count = 0;
7633 if (count++ % 3 == 0) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007634 i::Heap::CollectAllGarbage(true); // This should move the stub
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007635 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
7636 }
7637 return v8::Handle<v8::Value>();
7638}
7639
7640
7641THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
7642 v8::HandleScope scope;
7643 LocalContext context;
7644 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
7645 nativeobject_templ->Set("callback",
7646 v8::FunctionTemplate::New(DirectApiCallback));
7647 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
7648 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
7649 // call the api function multiple times to ensure direct call stub creation.
7650 CompileRun(
7651 "function f() {"
7652 " for (var i = 1; i <= 30; i++) {"
7653 " nativeobject.callback();"
7654 " }"
7655 "}"
7656 "f();");
7657}
7658
7659
7660v8::Handle<v8::Value> ThrowingDirectApiCallback(const v8::Arguments& args) {
7661 return v8::ThrowException(v8_str("g"));
7662}
7663
7664
7665THREADED_TEST(CallICFastApi_DirectCall_Throw) {
7666 v8::HandleScope scope;
7667 LocalContext context;
7668 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
7669 nativeobject_templ->Set("callback",
7670 v8::FunctionTemplate::New(ThrowingDirectApiCallback));
7671 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
7672 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
7673 // call the api function multiple times to ensure direct call stub creation.
7674 v8::Handle<Value> result = CompileRun(
7675 "var result = '';"
7676 "function f() {"
7677 " for (var i = 1; i <= 5; i++) {"
7678 " try { nativeobject.callback(); } catch (e) { result += e; }"
7679 " }"
7680 "}"
7681 "f(); result;");
7682 CHECK_EQ(v8_str("ggggg"), result);
7683}
7684
7685
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007686v8::Handle<v8::Value> DirectGetterCallback(Local<String> name,
7687 const v8::AccessorInfo& info) {
7688 if (++p_getter_count % 3 == 0) {
7689 i::Heap::CollectAllGarbage(true);
7690 GenerateSomeGarbage();
7691 }
7692 return v8::Handle<v8::Value>();
7693}
7694
7695
7696THREADED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
7697 v8::HandleScope scope;
7698 LocalContext context;
7699 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
7700 obj->SetAccessor(v8_str("p1"), DirectGetterCallback);
7701 context->Global()->Set(v8_str("o1"), obj->NewInstance());
7702 p_getter_count = 0;
7703 CompileRun(
7704 "function f() {"
7705 " for (var i = 0; i < 30; i++) o1.p1;"
7706 "}"
7707 "f();");
7708 CHECK_EQ(30, p_getter_count);
7709}
7710
7711
7712v8::Handle<v8::Value> ThrowingDirectGetterCallback(
7713 Local<String> name, const v8::AccessorInfo& info) {
7714 return v8::ThrowException(v8_str("g"));
7715}
7716
7717
7718THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
7719 v8::HandleScope scope;
7720 LocalContext context;
7721 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
7722 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
7723 context->Global()->Set(v8_str("o1"), obj->NewInstance());
7724 v8::Handle<Value> result = CompileRun(
7725 "var result = '';"
7726 "for (var i = 0; i < 5; i++) {"
7727 " try { o1.p1; } catch (e) { result += e; }"
7728 "}"
7729 "result;");
7730 CHECK_EQ(v8_str("ggggg"), result);
7731}
7732
7733
ager@chromium.org5c838252010-02-19 08:53:10 +00007734THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
7735 int interceptor_call_count = 0;
7736 v8::HandleScope scope;
7737 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7738 v8::Handle<v8::FunctionTemplate> method_templ =
7739 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
7740 v8_str("method_data"),
7741 v8::Handle<v8::Signature>());
7742 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7743 proto_templ->Set(v8_str("method"), method_templ);
7744 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7745 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7746 NULL, NULL, NULL, NULL,
7747 v8::External::Wrap(&interceptor_call_count));
7748 LocalContext context;
7749 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7750 GenerateSomeGarbage();
7751 context->Global()->Set(v8_str("o"), fun->NewInstance());
7752 v8::Handle<Value> value = CompileRun(
7753 "var result = 0;"
7754 "for (var i = 0; i < 100; i++) {"
7755 " result = o.method(41);"
7756 "}");
7757 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
7758 CHECK_EQ(100, interceptor_call_count);
7759}
7760
7761THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
7762 int interceptor_call_count = 0;
7763 v8::HandleScope scope;
7764 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7765 v8::Handle<v8::FunctionTemplate> method_templ =
7766 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7767 v8_str("method_data"),
7768 v8::Signature::New(fun_templ));
7769 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7770 proto_templ->Set(v8_str("method"), method_templ);
7771 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7772 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7773 NULL, NULL, NULL, NULL,
7774 v8::External::Wrap(&interceptor_call_count));
7775 LocalContext context;
7776 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7777 GenerateSomeGarbage();
7778 context->Global()->Set(v8_str("o"), fun->NewInstance());
7779 v8::Handle<Value> value = CompileRun(
7780 "o.foo = 17;"
7781 "var receiver = {};"
7782 "receiver.__proto__ = o;"
7783 "var result = 0;"
7784 "for (var i = 0; i < 100; i++) {"
7785 " result = receiver.method(41);"
7786 "}");
7787 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
7788 CHECK_EQ(100, interceptor_call_count);
7789}
7790
7791THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
7792 int interceptor_call_count = 0;
7793 v8::HandleScope scope;
7794 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7795 v8::Handle<v8::FunctionTemplate> method_templ =
7796 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7797 v8_str("method_data"),
7798 v8::Signature::New(fun_templ));
7799 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7800 proto_templ->Set(v8_str("method"), method_templ);
7801 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7802 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7803 NULL, NULL, NULL, NULL,
7804 v8::External::Wrap(&interceptor_call_count));
7805 LocalContext context;
7806 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7807 GenerateSomeGarbage();
7808 context->Global()->Set(v8_str("o"), fun->NewInstance());
7809 v8::Handle<Value> value = CompileRun(
7810 "o.foo = 17;"
7811 "var receiver = {};"
7812 "receiver.__proto__ = o;"
7813 "var result = 0;"
7814 "var saved_result = 0;"
7815 "for (var i = 0; i < 100; i++) {"
7816 " result = receiver.method(41);"
7817 " if (i == 50) {"
7818 " saved_result = result;"
7819 " receiver = {method: function(x) { return x - 1 }};"
7820 " }"
7821 "}");
7822 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
7823 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7824 CHECK_GE(interceptor_call_count, 50);
7825}
7826
7827THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
7828 int interceptor_call_count = 0;
7829 v8::HandleScope scope;
7830 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7831 v8::Handle<v8::FunctionTemplate> method_templ =
7832 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7833 v8_str("method_data"),
7834 v8::Signature::New(fun_templ));
7835 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7836 proto_templ->Set(v8_str("method"), method_templ);
7837 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7838 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7839 NULL, NULL, NULL, NULL,
7840 v8::External::Wrap(&interceptor_call_count));
7841 LocalContext context;
7842 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7843 GenerateSomeGarbage();
7844 context->Global()->Set(v8_str("o"), fun->NewInstance());
7845 v8::Handle<Value> value = CompileRun(
7846 "o.foo = 17;"
7847 "var receiver = {};"
7848 "receiver.__proto__ = o;"
7849 "var result = 0;"
7850 "var saved_result = 0;"
7851 "for (var i = 0; i < 100; i++) {"
7852 " result = receiver.method(41);"
7853 " if (i == 50) {"
7854 " saved_result = result;"
7855 " o.method = function(x) { return x - 1 };"
7856 " }"
7857 "}");
7858 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
7859 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7860 CHECK_GE(interceptor_call_count, 50);
7861}
7862
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00007863THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
7864 int interceptor_call_count = 0;
7865 v8::HandleScope scope;
7866 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7867 v8::Handle<v8::FunctionTemplate> method_templ =
7868 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7869 v8_str("method_data"),
7870 v8::Signature::New(fun_templ));
7871 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7872 proto_templ->Set(v8_str("method"), method_templ);
7873 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7874 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7875 NULL, NULL, NULL, NULL,
7876 v8::External::Wrap(&interceptor_call_count));
7877 LocalContext context;
7878 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7879 GenerateSomeGarbage();
7880 context->Global()->Set(v8_str("o"), fun->NewInstance());
7881 v8::TryCatch try_catch;
7882 v8::Handle<Value> value = CompileRun(
7883 "o.foo = 17;"
7884 "var receiver = {};"
7885 "receiver.__proto__ = o;"
7886 "var result = 0;"
7887 "var saved_result = 0;"
7888 "for (var i = 0; i < 100; i++) {"
7889 " result = receiver.method(41);"
7890 " if (i == 50) {"
7891 " saved_result = result;"
7892 " receiver = 333;"
7893 " }"
7894 "}");
7895 CHECK(try_catch.HasCaught());
7896 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
7897 try_catch.Exception()->ToString());
7898 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7899 CHECK_GE(interceptor_call_count, 50);
7900}
7901
ager@chromium.org5c838252010-02-19 08:53:10 +00007902THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
7903 int interceptor_call_count = 0;
7904 v8::HandleScope scope;
7905 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7906 v8::Handle<v8::FunctionTemplate> method_templ =
7907 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7908 v8_str("method_data"),
7909 v8::Signature::New(fun_templ));
7910 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7911 proto_templ->Set(v8_str("method"), method_templ);
7912 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7913 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7914 NULL, NULL, NULL, NULL,
7915 v8::External::Wrap(&interceptor_call_count));
7916 LocalContext context;
7917 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7918 GenerateSomeGarbage();
7919 context->Global()->Set(v8_str("o"), fun->NewInstance());
7920 v8::TryCatch try_catch;
7921 v8::Handle<Value> value = CompileRun(
7922 "o.foo = 17;"
7923 "var receiver = {};"
7924 "receiver.__proto__ = o;"
7925 "var result = 0;"
7926 "var saved_result = 0;"
7927 "for (var i = 0; i < 100; i++) {"
7928 " result = receiver.method(41);"
7929 " if (i == 50) {"
7930 " saved_result = result;"
7931 " receiver = {method: receiver.method};"
7932 " }"
7933 "}");
7934 CHECK(try_catch.HasCaught());
7935 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
7936 try_catch.Exception()->ToString());
7937 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7938 CHECK_GE(interceptor_call_count, 50);
7939}
7940
7941THREADED_TEST(CallICFastApi_TrivialSignature) {
7942 v8::HandleScope scope;
7943 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7944 v8::Handle<v8::FunctionTemplate> method_templ =
7945 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
7946 v8_str("method_data"),
7947 v8::Handle<v8::Signature>());
7948 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7949 proto_templ->Set(v8_str("method"), method_templ);
7950 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7951 LocalContext context;
7952 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7953 GenerateSomeGarbage();
7954 context->Global()->Set(v8_str("o"), fun->NewInstance());
7955 v8::Handle<Value> value = CompileRun(
7956 "var result = 0;"
7957 "for (var i = 0; i < 100; i++) {"
7958 " result = o.method(41);"
7959 "}");
7960
7961 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
7962}
7963
7964THREADED_TEST(CallICFastApi_SimpleSignature) {
7965 v8::HandleScope scope;
7966 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7967 v8::Handle<v8::FunctionTemplate> method_templ =
7968 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7969 v8_str("method_data"),
7970 v8::Signature::New(fun_templ));
7971 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7972 proto_templ->Set(v8_str("method"), method_templ);
7973 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7974 LocalContext context;
7975 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7976 GenerateSomeGarbage();
7977 context->Global()->Set(v8_str("o"), fun->NewInstance());
7978 v8::Handle<Value> value = CompileRun(
7979 "o.foo = 17;"
7980 "var receiver = {};"
7981 "receiver.__proto__ = o;"
7982 "var result = 0;"
7983 "for (var i = 0; i < 100; i++) {"
7984 " result = receiver.method(41);"
7985 "}");
7986
7987 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
7988}
7989
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00007990THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) {
ager@chromium.org5c838252010-02-19 08:53:10 +00007991 v8::HandleScope scope;
7992 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7993 v8::Handle<v8::FunctionTemplate> method_templ =
7994 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7995 v8_str("method_data"),
7996 v8::Signature::New(fun_templ));
7997 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7998 proto_templ->Set(v8_str("method"), method_templ);
7999 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8000 LocalContext context;
8001 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8002 GenerateSomeGarbage();
8003 context->Global()->Set(v8_str("o"), fun->NewInstance());
8004 v8::Handle<Value> value = CompileRun(
8005 "o.foo = 17;"
8006 "var receiver = {};"
8007 "receiver.__proto__ = o;"
8008 "var result = 0;"
8009 "var saved_result = 0;"
8010 "for (var i = 0; i < 100; i++) {"
8011 " result = receiver.method(41);"
8012 " if (i == 50) {"
8013 " saved_result = result;"
8014 " receiver = {method: function(x) { return x - 1 }};"
8015 " }"
8016 "}");
8017 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
8018 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8019}
8020
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00008021THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) {
8022 v8::HandleScope scope;
8023 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8024 v8::Handle<v8::FunctionTemplate> method_templ =
8025 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8026 v8_str("method_data"),
8027 v8::Signature::New(fun_templ));
8028 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8029 proto_templ->Set(v8_str("method"), method_templ);
8030 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8031 LocalContext context;
8032 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8033 GenerateSomeGarbage();
8034 context->Global()->Set(v8_str("o"), fun->NewInstance());
8035 v8::TryCatch try_catch;
8036 v8::Handle<Value> value = CompileRun(
8037 "o.foo = 17;"
8038 "var receiver = {};"
8039 "receiver.__proto__ = o;"
8040 "var result = 0;"
8041 "var saved_result = 0;"
8042 "for (var i = 0; i < 100; i++) {"
8043 " result = receiver.method(41);"
8044 " if (i == 50) {"
8045 " saved_result = result;"
8046 " receiver = 333;"
8047 " }"
8048 "}");
8049 CHECK(try_catch.HasCaught());
8050 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
8051 try_catch.Exception()->ToString());
8052 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8053}
8054
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008055
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008056v8::Handle<Value> keyed_call_ic_function;
8057
8058static v8::Handle<Value> InterceptorKeyedCallICGetter(
8059 Local<String> name, const AccessorInfo& info) {
8060 ApiTestFuzzer::Fuzz();
8061 if (v8_str("x")->Equals(name)) {
8062 return keyed_call_ic_function;
8063 }
8064 return v8::Handle<Value>();
8065}
8066
8067
8068// Test the case when we stored cacheable lookup into
8069// a stub, but the function name changed (to another cacheable function).
8070THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
8071 v8::HandleScope scope;
8072 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8073 templ->SetNamedPropertyHandler(NoBlockGetterX);
8074 LocalContext context;
8075 context->Global()->Set(v8_str("o"), templ->NewInstance());
8076 v8::Handle<Value> value = CompileRun(
8077 "proto = new Object();"
8078 "proto.y = function(x) { return x + 1; };"
8079 "proto.z = function(x) { return x - 1; };"
8080 "o.__proto__ = proto;"
8081 "var result = 0;"
8082 "var method = 'y';"
8083 "for (var i = 0; i < 10; i++) {"
8084 " if (i == 5) { method = 'z'; };"
8085 " result += o[method](41);"
8086 "}");
8087 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
8088}
8089
8090
8091// Test the case when we stored cacheable lookup into
8092// a stub, but the function name changed (and the new function is present
8093// both before and after the interceptor in the prototype chain).
8094THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
8095 v8::HandleScope scope;
8096 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8097 templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
8098 LocalContext context;
8099 context->Global()->Set(v8_str("proto1"), templ->NewInstance());
8100 keyed_call_ic_function =
8101 v8_compile("function f(x) { return x - 1; }; f")->Run();
8102 v8::Handle<Value> value = CompileRun(
8103 "o = new Object();"
8104 "proto2 = new Object();"
8105 "o.y = function(x) { return x + 1; };"
8106 "proto2.y = function(x) { return x + 2; };"
8107 "o.__proto__ = proto1;"
8108 "proto1.__proto__ = proto2;"
8109 "var result = 0;"
8110 "var method = 'x';"
8111 "for (var i = 0; i < 10; i++) {"
8112 " if (i == 5) { method = 'y'; };"
8113 " result += o[method](41);"
8114 "}");
8115 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
8116}
8117
8118
8119// Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
8120// on the global object.
8121THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
8122 v8::HandleScope scope;
8123 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8124 templ->SetNamedPropertyHandler(NoBlockGetterX);
8125 LocalContext context;
8126 context->Global()->Set(v8_str("o"), templ->NewInstance());
8127 v8::Handle<Value> value = CompileRun(
8128 "function inc(x) { return x + 1; };"
8129 "inc(1);"
8130 "function dec(x) { return x - 1; };"
8131 "dec(1);"
8132 "o.__proto__ = this;"
8133 "this.__proto__.x = inc;"
8134 "this.__proto__.y = dec;"
8135 "var result = 0;"
8136 "var method = 'x';"
8137 "for (var i = 0; i < 10; i++) {"
8138 " if (i == 5) { method = 'y'; };"
8139 " result += o[method](41);"
8140 "}");
8141 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
8142}
8143
8144
8145// Test the case when actual function to call sits on global object.
8146THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
8147 v8::HandleScope scope;
8148 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8149 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
8150 LocalContext context;
8151 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8152
8153 v8::Handle<Value> value = CompileRun(
8154 "function len(x) { return x.length; };"
8155 "o.__proto__ = this;"
8156 "var m = 'parseFloat';"
8157 "var result = 0;"
8158 "for (var i = 0; i < 10; i++) {"
8159 " if (i == 5) {"
8160 " m = 'len';"
8161 " saved_result = result;"
8162 " };"
8163 " result = o[m]('239');"
8164 "}");
8165 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
8166 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8167}
8168
8169// Test the map transition before the interceptor.
8170THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
8171 v8::HandleScope scope;
8172 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8173 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
8174 LocalContext context;
8175 context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
8176
8177 v8::Handle<Value> value = CompileRun(
8178 "var o = new Object();"
8179 "o.__proto__ = proto;"
8180 "o.method = function(x) { return x + 1; };"
8181 "var m = 'method';"
8182 "var result = 0;"
8183 "for (var i = 0; i < 10; i++) {"
8184 " if (i == 5) { o.method = function(x) { return x - 1; }; };"
8185 " result += o[m](41);"
8186 "}");
8187 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
8188}
8189
8190
8191// Test the map transition after the interceptor.
8192THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
8193 v8::HandleScope scope;
8194 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8195 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
8196 LocalContext context;
8197 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8198
8199 v8::Handle<Value> value = CompileRun(
8200 "var proto = new Object();"
8201 "o.__proto__ = proto;"
8202 "proto.method = function(x) { return x + 1; };"
8203 "var m = 'method';"
8204 "var result = 0;"
8205 "for (var i = 0; i < 10; i++) {"
8206 " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
8207 " result += o[m](41);"
8208 "}");
8209 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
8210}
8211
8212
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008213static int interceptor_call_count = 0;
8214
8215static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
8216 const AccessorInfo& info) {
8217 ApiTestFuzzer::Fuzz();
8218 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
8219 return call_ic_function2;
8220 }
8221 return v8::Handle<Value>();
8222}
8223
8224
8225// This test should hit load and call ICs for the interceptor case.
8226// Once in a while, the interceptor will reply that a property was not
8227// found in which case we should get a reference error.
8228THREADED_TEST(InterceptorICReferenceErrors) {
8229 v8::HandleScope scope;
8230 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8231 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
8232 LocalContext context(0, templ, v8::Handle<Value>());
8233 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
8234 v8::Handle<Value> value = CompileRun(
8235 "function f() {"
8236 " for (var i = 0; i < 1000; i++) {"
8237 " try { x; } catch(e) { return true; }"
8238 " }"
8239 " return false;"
8240 "};"
8241 "f();");
8242 CHECK_EQ(true, value->BooleanValue());
8243 interceptor_call_count = 0;
8244 value = CompileRun(
8245 "function g() {"
8246 " for (var i = 0; i < 1000; i++) {"
8247 " try { x(42); } catch(e) { return true; }"
8248 " }"
8249 " return false;"
8250 "};"
8251 "g();");
8252 CHECK_EQ(true, value->BooleanValue());
8253}
8254
8255
8256static int interceptor_ic_exception_get_count = 0;
8257
8258static v8::Handle<Value> InterceptorICExceptionGetter(
8259 Local<String> name,
8260 const AccessorInfo& info) {
8261 ApiTestFuzzer::Fuzz();
8262 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
8263 return call_ic_function3;
8264 }
8265 if (interceptor_ic_exception_get_count == 20) {
8266 return v8::ThrowException(v8_num(42));
8267 }
8268 // Do not handle get for properties other than x.
8269 return v8::Handle<Value>();
8270}
8271
8272// Test interceptor load/call IC where the interceptor throws an
8273// exception once in a while.
8274THREADED_TEST(InterceptorICGetterExceptions) {
8275 interceptor_ic_exception_get_count = 0;
8276 v8::HandleScope scope;
8277 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8278 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
8279 LocalContext context(0, templ, v8::Handle<Value>());
8280 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
8281 v8::Handle<Value> value = CompileRun(
8282 "function f() {"
8283 " for (var i = 0; i < 100; i++) {"
8284 " try { x; } catch(e) { return true; }"
8285 " }"
8286 " return false;"
8287 "};"
8288 "f();");
8289 CHECK_EQ(true, value->BooleanValue());
8290 interceptor_ic_exception_get_count = 0;
8291 value = CompileRun(
8292 "function f() {"
8293 " for (var i = 0; i < 100; i++) {"
8294 " try { x(42); } catch(e) { return true; }"
8295 " }"
8296 " return false;"
8297 "};"
8298 "f();");
8299 CHECK_EQ(true, value->BooleanValue());
8300}
8301
8302
8303static int interceptor_ic_exception_set_count = 0;
8304
8305static v8::Handle<Value> InterceptorICExceptionSetter(
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008306 Local<String> key, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008307 ApiTestFuzzer::Fuzz();
8308 if (++interceptor_ic_exception_set_count > 20) {
8309 return v8::ThrowException(v8_num(42));
8310 }
8311 // Do not actually handle setting.
8312 return v8::Handle<Value>();
8313}
8314
8315// Test interceptor store IC where the interceptor throws an exception
8316// once in a while.
8317THREADED_TEST(InterceptorICSetterExceptions) {
8318 interceptor_ic_exception_set_count = 0;
8319 v8::HandleScope scope;
8320 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8321 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
8322 LocalContext context(0, templ, v8::Handle<Value>());
8323 v8::Handle<Value> value = CompileRun(
8324 "function f() {"
8325 " for (var i = 0; i < 100; i++) {"
8326 " try { x = 42; } catch(e) { return true; }"
8327 " }"
8328 " return false;"
8329 "};"
8330 "f();");
8331 CHECK_EQ(true, value->BooleanValue());
8332}
8333
8334
8335// Test that we ignore null interceptors.
8336THREADED_TEST(NullNamedInterceptor) {
8337 v8::HandleScope scope;
8338 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8339 templ->SetNamedPropertyHandler(0);
8340 LocalContext context;
8341 templ->Set("x", v8_num(42));
8342 v8::Handle<v8::Object> obj = templ->NewInstance();
8343 context->Global()->Set(v8_str("obj"), obj);
8344 v8::Handle<Value> value = CompileRun("obj.x");
8345 CHECK(value->IsInt32());
8346 CHECK_EQ(42, value->Int32Value());
8347}
8348
8349
8350// Test that we ignore null interceptors.
8351THREADED_TEST(NullIndexedInterceptor) {
8352 v8::HandleScope scope;
8353 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8354 templ->SetIndexedPropertyHandler(0);
8355 LocalContext context;
8356 templ->Set("42", v8_num(42));
8357 v8::Handle<v8::Object> obj = templ->NewInstance();
8358 context->Global()->Set(v8_str("obj"), obj);
8359 v8::Handle<Value> value = CompileRun("obj[42]");
8360 CHECK(value->IsInt32());
8361 CHECK_EQ(42, value->Int32Value());
8362}
8363
8364
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008365THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
8366 v8::HandleScope scope;
8367 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
8368 templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8369 LocalContext env;
8370 env->Global()->Set(v8_str("obj"),
8371 templ->GetFunction()->NewInstance());
8372 ExpectTrue("obj.x === 42");
8373 ExpectTrue("!obj.propertyIsEnumerable('x')");
8374}
8375
8376
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008377static v8::Handle<Value> ParentGetter(Local<String> name,
8378 const AccessorInfo& info) {
8379 ApiTestFuzzer::Fuzz();
8380 return v8_num(1);
8381}
8382
8383
8384static v8::Handle<Value> ChildGetter(Local<String> name,
8385 const AccessorInfo& info) {
8386 ApiTestFuzzer::Fuzz();
8387 return v8_num(42);
8388}
8389
8390
8391THREADED_TEST(Overriding) {
8392 v8::HandleScope scope;
8393 LocalContext context;
8394
8395 // Parent template.
8396 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
8397 Local<ObjectTemplate> parent_instance_templ =
8398 parent_templ->InstanceTemplate();
8399 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
8400
8401 // Template that inherits from the parent template.
8402 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
8403 Local<ObjectTemplate> child_instance_templ =
8404 child_templ->InstanceTemplate();
8405 child_templ->Inherit(parent_templ);
8406 // Override 'f'. The child version of 'f' should get called for child
8407 // instances.
8408 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
8409 // Add 'g' twice. The 'g' added last should get called for instances.
8410 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
8411 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
8412
8413 // Add 'h' as an accessor to the proto template with ReadOnly attributes
8414 // so 'h' can be shadowed on the instance object.
8415 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
8416 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
8417 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
8418
8419 // Add 'i' as an accessor to the instance template with ReadOnly attributes
8420 // but the attribute does not have effect because it is duplicated with
8421 // NULL setter.
8422 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
8423 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
8424
8425
8426
8427 // Instantiate the child template.
8428 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
8429
8430 // Check that the child function overrides the parent one.
8431 context->Global()->Set(v8_str("o"), instance);
8432 Local<Value> value = v8_compile("o.f")->Run();
8433 // Check that the 'g' that was added last is hit.
8434 CHECK_EQ(42, value->Int32Value());
8435 value = v8_compile("o.g")->Run();
8436 CHECK_EQ(42, value->Int32Value());
8437
8438 // Check 'h' can be shadowed.
8439 value = v8_compile("o.h = 3; o.h")->Run();
8440 CHECK_EQ(3, value->Int32Value());
8441
8442 // Check 'i' is cannot be shadowed or changed.
8443 value = v8_compile("o.i = 3; o.i")->Run();
8444 CHECK_EQ(42, value->Int32Value());
8445}
8446
8447
8448static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
8449 ApiTestFuzzer::Fuzz();
8450 if (args.IsConstructCall()) {
8451 return v8::Boolean::New(true);
8452 }
8453 return v8::Boolean::New(false);
8454}
8455
8456
8457THREADED_TEST(IsConstructCall) {
8458 v8::HandleScope scope;
8459
8460 // Function template with call handler.
8461 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
8462 templ->SetCallHandler(IsConstructHandler);
8463
8464 LocalContext context;
8465
8466 context->Global()->Set(v8_str("f"), templ->GetFunction());
8467 Local<Value> value = v8_compile("f()")->Run();
8468 CHECK(!value->BooleanValue());
8469 value = v8_compile("new f()")->Run();
8470 CHECK(value->BooleanValue());
8471}
8472
8473
8474THREADED_TEST(ObjectProtoToString) {
8475 v8::HandleScope scope;
8476 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
8477 templ->SetClassName(v8_str("MyClass"));
8478
8479 LocalContext context;
8480
8481 Local<String> customized_tostring = v8_str("customized toString");
8482
8483 // Replace Object.prototype.toString
8484 v8_compile("Object.prototype.toString = function() {"
8485 " return 'customized toString';"
8486 "}")->Run();
8487
8488 // Normal ToString call should call replaced Object.prototype.toString
8489 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
8490 Local<String> value = instance->ToString();
8491 CHECK(value->IsString() && value->Equals(customized_tostring));
8492
8493 // ObjectProtoToString should not call replace toString function.
8494 value = instance->ObjectProtoToString();
8495 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
8496
8497 // Check global
8498 value = context->Global()->ObjectProtoToString();
8499 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
8500
8501 // Check ordinary object
8502 Local<Value> object = v8_compile("new Object()")->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008503 value = object.As<v8::Object>()->ObjectProtoToString();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008504 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
8505}
8506
8507
ager@chromium.orgbeb25712010-11-29 08:02:25 +00008508THREADED_TEST(ObjectGetConstructorName) {
8509 v8::HandleScope scope;
8510 LocalContext context;
8511 v8_compile("function Parent() {};"
8512 "function Child() {};"
8513 "Child.prototype = new Parent();"
8514 "var outer = { inner: function() { } };"
8515 "var p = new Parent();"
8516 "var c = new Child();"
8517 "var x = new outer.inner();")->Run();
8518
8519 Local<v8::Value> p = context->Global()->Get(v8_str("p"));
8520 CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
8521 v8_str("Parent")));
8522
8523 Local<v8::Value> c = context->Global()->Get(v8_str("c"));
8524 CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
8525 v8_str("Child")));
8526
8527 Local<v8::Value> x = context->Global()->Get(v8_str("x"));
8528 CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
8529 v8_str("outer.inner")));
8530}
8531
8532
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008533bool ApiTestFuzzer::fuzzing_ = false;
lrn@chromium.org32d961d2010-06-30 09:09:34 +00008534i::Semaphore* ApiTestFuzzer::all_tests_done_=
8535 i::OS::CreateSemaphore(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008536int ApiTestFuzzer::active_tests_;
8537int ApiTestFuzzer::tests_being_run_;
8538int ApiTestFuzzer::current_;
8539
8540
8541// We are in a callback and want to switch to another thread (if we
8542// are currently running the thread fuzzing test).
8543void ApiTestFuzzer::Fuzz() {
8544 if (!fuzzing_) return;
8545 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
8546 test->ContextSwitch();
8547}
8548
8549
8550// Let the next thread go. Since it is also waiting on the V8 lock it may
8551// not start immediately.
8552bool ApiTestFuzzer::NextThread() {
8553 int test_position = GetNextTestNumber();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008554 const char* test_name = RegisterThreadedTest::nth(current_)->name();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008555 if (test_position == current_) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008556 if (kLogThreading)
8557 printf("Stay with %s\n", test_name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008558 return false;
8559 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008560 if (kLogThreading) {
8561 printf("Switch from %s to %s\n",
8562 test_name,
8563 RegisterThreadedTest::nth(test_position)->name());
8564 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008565 current_ = test_position;
8566 RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
8567 return true;
8568}
8569
8570
8571void ApiTestFuzzer::Run() {
8572 // When it is our turn...
8573 gate_->Wait();
8574 {
8575 // ... get the V8 lock and start running the test.
8576 v8::Locker locker;
8577 CallTest();
8578 }
8579 // This test finished.
8580 active_ = false;
8581 active_tests_--;
8582 // If it was the last then signal that fact.
8583 if (active_tests_ == 0) {
8584 all_tests_done_->Signal();
8585 } else {
8586 // Otherwise select a new test and start that.
8587 NextThread();
8588 }
8589}
8590
8591
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008592static unsigned linear_congruential_generator;
8593
8594
8595void ApiTestFuzzer::Setup(PartOfTest part) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008596 linear_congruential_generator = i::FLAG_testing_prng_seed;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008597 fuzzing_ = true;
8598 int start = (part == FIRST_PART) ? 0 : (RegisterThreadedTest::count() >> 1);
8599 int end = (part == FIRST_PART)
8600 ? (RegisterThreadedTest::count() >> 1)
8601 : RegisterThreadedTest::count();
8602 active_tests_ = tests_being_run_ = end - start;
8603 for (int i = 0; i < tests_being_run_; i++) {
8604 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
8605 }
8606 for (int i = 0; i < active_tests_; i++) {
8607 RegisterThreadedTest::nth(i)->fuzzer_->Start();
8608 }
8609}
8610
8611
8612static void CallTestNumber(int test_number) {
8613 (RegisterThreadedTest::nth(test_number)->callback())();
8614}
8615
8616
8617void ApiTestFuzzer::RunAllTests() {
8618 // Set off the first test.
8619 current_ = -1;
8620 NextThread();
8621 // Wait till they are all done.
8622 all_tests_done_->Wait();
8623}
8624
8625
8626int ApiTestFuzzer::GetNextTestNumber() {
8627 int next_test;
8628 do {
8629 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
8630 linear_congruential_generator *= 1664525u;
8631 linear_congruential_generator += 1013904223u;
8632 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
8633 return next_test;
8634}
8635
8636
8637void ApiTestFuzzer::ContextSwitch() {
8638 // If the new thread is the same as the current thread there is nothing to do.
8639 if (NextThread()) {
8640 // Now it can start.
8641 v8::Unlocker unlocker;
8642 // Wait till someone starts us again.
8643 gate_->Wait();
8644 // And we're off.
8645 }
8646}
8647
8648
8649void ApiTestFuzzer::TearDown() {
8650 fuzzing_ = false;
ager@chromium.org41826e72009-03-30 13:30:57 +00008651 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
8652 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
8653 if (fuzzer != NULL) fuzzer->Join();
8654 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008655}
8656
8657
8658// Lets not be needlessly self-referential.
8659TEST(Threading) {
8660 ApiTestFuzzer::Setup(ApiTestFuzzer::FIRST_PART);
8661 ApiTestFuzzer::RunAllTests();
8662 ApiTestFuzzer::TearDown();
8663}
8664
8665TEST(Threading2) {
8666 ApiTestFuzzer::Setup(ApiTestFuzzer::SECOND_PART);
8667 ApiTestFuzzer::RunAllTests();
8668 ApiTestFuzzer::TearDown();
8669}
8670
8671
8672void ApiTestFuzzer::CallTest() {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008673 if (kLogThreading)
8674 printf("Start test %d\n", test_number_);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008675 CallTestNumber(test_number_);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008676 if (kLogThreading)
8677 printf("End test %d\n", test_number_);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008678}
8679
8680
8681static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008682 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008683 ApiTestFuzzer::Fuzz();
8684 v8::Unlocker unlocker;
8685 const char* code = "throw 7;";
8686 {
8687 v8::Locker nested_locker;
8688 v8::HandleScope scope;
8689 v8::Handle<Value> exception;
8690 { v8::TryCatch try_catch;
8691 v8::Handle<Value> value = CompileRun(code);
8692 CHECK(value.IsEmpty());
8693 CHECK(try_catch.HasCaught());
8694 // Make sure to wrap the exception in a new handle because
8695 // the handle returned from the TryCatch is destroyed
8696 // when the TryCatch is destroyed.
8697 exception = Local<Value>::New(try_catch.Exception());
8698 }
8699 return v8::ThrowException(exception);
8700 }
8701}
8702
8703
8704static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008705 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008706 ApiTestFuzzer::Fuzz();
8707 v8::Unlocker unlocker;
8708 const char* code = "throw 7;";
8709 {
8710 v8::Locker nested_locker;
8711 v8::HandleScope scope;
8712 v8::Handle<Value> value = CompileRun(code);
8713 CHECK(value.IsEmpty());
8714 return v8_str("foo");
8715 }
8716}
8717
8718
8719// These are locking tests that don't need to be run again
8720// as part of the locking aggregation tests.
8721TEST(NestedLockers) {
8722 v8::Locker locker;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008723 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008724 v8::HandleScope scope;
8725 LocalContext env;
8726 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
8727 Local<Function> fun = fun_templ->GetFunction();
8728 env->Global()->Set(v8_str("throw_in_js"), fun);
8729 Local<Script> script = v8_compile("(function () {"
8730 " try {"
8731 " throw_in_js();"
8732 " return 42;"
8733 " } catch (e) {"
8734 " return e * 13;"
8735 " }"
8736 "})();");
8737 CHECK_EQ(91, script->Run()->Int32Value());
8738}
8739
8740
8741// These are locking tests that don't need to be run again
8742// as part of the locking aggregation tests.
8743TEST(NestedLockersNoTryCatch) {
8744 v8::Locker locker;
8745 v8::HandleScope scope;
8746 LocalContext env;
8747 Local<v8::FunctionTemplate> fun_templ =
8748 v8::FunctionTemplate::New(ThrowInJSNoCatch);
8749 Local<Function> fun = fun_templ->GetFunction();
8750 env->Global()->Set(v8_str("throw_in_js"), fun);
8751 Local<Script> script = v8_compile("(function () {"
8752 " try {"
8753 " throw_in_js();"
8754 " return 42;"
8755 " } catch (e) {"
8756 " return e * 13;"
8757 " }"
8758 "})();");
8759 CHECK_EQ(91, script->Run()->Int32Value());
8760}
8761
8762
8763THREADED_TEST(RecursiveLocking) {
8764 v8::Locker locker;
8765 {
8766 v8::Locker locker2;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008767 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008768 }
8769}
8770
8771
8772static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
8773 ApiTestFuzzer::Fuzz();
8774 v8::Unlocker unlocker;
8775 return v8::Undefined();
8776}
8777
8778
8779THREADED_TEST(LockUnlockLock) {
8780 {
8781 v8::Locker locker;
8782 v8::HandleScope scope;
8783 LocalContext env;
8784 Local<v8::FunctionTemplate> fun_templ =
8785 v8::FunctionTemplate::New(UnlockForAMoment);
8786 Local<Function> fun = fun_templ->GetFunction();
8787 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
8788 Local<Script> script = v8_compile("(function () {"
8789 " unlock_for_a_moment();"
8790 " return 42;"
8791 "})();");
8792 CHECK_EQ(42, script->Run()->Int32Value());
8793 }
8794 {
8795 v8::Locker locker;
8796 v8::HandleScope scope;
8797 LocalContext env;
8798 Local<v8::FunctionTemplate> fun_templ =
8799 v8::FunctionTemplate::New(UnlockForAMoment);
8800 Local<Function> fun = fun_templ->GetFunction();
8801 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
8802 Local<Script> script = v8_compile("(function () {"
8803 " unlock_for_a_moment();"
8804 " return 42;"
8805 "})();");
8806 CHECK_EQ(42, script->Run()->Int32Value());
8807 }
8808}
8809
8810
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008811static int GetGlobalObjectsCount() {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008812 int count = 0;
lrn@chromium.org32d961d2010-06-30 09:09:34 +00008813 i::HeapIterator it;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008814 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
8815 if (object->IsJSGlobalObject()) count++;
8816 return count;
8817}
8818
8819
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00008820static void CheckSurvivingGlobalObjectsCount(int expected) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008821 // We need to collect all garbage twice to be sure that everything
8822 // has been collected. This is because inline caches are cleared in
8823 // the first garbage collection but some of the maps have already
8824 // been marked at that point. Therefore some of the maps are not
8825 // collected until the second garbage collection.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00008826 i::Heap::CollectAllGarbage(false);
8827 i::Heap::CollectAllGarbage(false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008828 int count = GetGlobalObjectsCount();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008829#ifdef DEBUG
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00008830 if (count != expected) i::Heap::TracePathToGlobal();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008831#endif
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00008832 CHECK_EQ(expected, count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008833}
8834
8835
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008836TEST(DontLeakGlobalObjects) {
8837 // Regression test for issues 1139850 and 1174891.
8838
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008839 v8::V8::Initialize();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008840
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008841 for (int i = 0; i < 5; i++) {
8842 { v8::HandleScope scope;
8843 LocalContext context;
8844 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00008845 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008846
8847 { v8::HandleScope scope;
8848 LocalContext context;
8849 v8_compile("Date")->Run();
8850 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00008851 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008852
8853 { v8::HandleScope scope;
8854 LocalContext context;
8855 v8_compile("/aaa/")->Run();
8856 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00008857 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008858
8859 { v8::HandleScope scope;
8860 const char* extension_list[] = { "v8/gc" };
8861 v8::ExtensionConfiguration extensions(1, extension_list);
8862 LocalContext context(&extensions);
8863 v8_compile("gc();")->Run();
8864 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00008865 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008866 }
8867}
8868
8869
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00008870v8::Persistent<v8::Object> some_object;
8871v8::Persistent<v8::Object> bad_handle;
8872
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00008873void NewPersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) {
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00008874 v8::HandleScope scope;
8875 bad_handle = v8::Persistent<v8::Object>::New(some_object);
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00008876 handle.Dispose();
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00008877}
8878
8879
8880THREADED_TEST(NewPersistentHandleFromWeakCallback) {
8881 LocalContext context;
8882
8883 v8::Persistent<v8::Object> handle1, handle2;
8884 {
8885 v8::HandleScope scope;
8886 some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
8887 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
8888 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
8889 }
8890 // Note: order is implementation dependent alas: currently
8891 // global handle nodes are processed by PostGarbageCollectionProcessing
8892 // in reverse allocation order, so if second allocated handle is deleted,
8893 // weak callback of the first handle would be able to 'reallocate' it.
8894 handle1.MakeWeak(NULL, NewPersistentHandleCallback);
8895 handle2.Dispose();
ager@chromium.orgab99eea2009-08-25 07:05:41 +00008896 i::Heap::CollectAllGarbage(false);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00008897}
8898
8899
8900v8::Persistent<v8::Object> to_be_disposed;
8901
8902void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
8903 to_be_disposed.Dispose();
ager@chromium.orgab99eea2009-08-25 07:05:41 +00008904 i::Heap::CollectAllGarbage(false);
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00008905 handle.Dispose();
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00008906}
8907
8908
8909THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
8910 LocalContext context;
8911
8912 v8::Persistent<v8::Object> handle1, handle2;
8913 {
8914 v8::HandleScope scope;
8915 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
8916 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
8917 }
8918 handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
8919 to_be_disposed = handle2;
ager@chromium.orgab99eea2009-08-25 07:05:41 +00008920 i::Heap::CollectAllGarbage(false);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00008921}
8922
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008923void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
8924 handle.Dispose();
8925}
8926
8927void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
8928 v8::HandleScope scope;
8929 v8::Persistent<v8::Object>::New(v8::Object::New());
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00008930 handle.Dispose();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008931}
8932
8933
8934THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
8935 LocalContext context;
8936
8937 v8::Persistent<v8::Object> handle1, handle2, handle3;
8938 {
8939 v8::HandleScope scope;
8940 handle3 = v8::Persistent<v8::Object>::New(v8::Object::New());
8941 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
8942 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
8943 }
8944 handle2.MakeWeak(NULL, DisposingCallback);
8945 handle3.MakeWeak(NULL, HandleCreatingCallback);
8946 i::Heap::CollectAllGarbage(false);
8947}
8948
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00008949
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008950THREADED_TEST(CheckForCrossContextObjectLiterals) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008951 v8::V8::Initialize();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008952
8953 const int nof = 2;
8954 const char* sources[nof] = {
8955 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
8956 "Object()"
8957 };
8958
8959 for (int i = 0; i < nof; i++) {
8960 const char* source = sources[i];
8961 { v8::HandleScope scope;
8962 LocalContext context;
8963 CompileRun(source);
8964 }
8965 { v8::HandleScope scope;
8966 LocalContext context;
8967 CompileRun(source);
8968 }
8969 }
8970}
8971
8972
8973static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
8974 v8::HandleScope inner;
8975 env->Enter();
8976 v8::Handle<Value> three = v8_num(3);
8977 v8::Handle<Value> value = inner.Close(three);
8978 env->Exit();
8979 return value;
8980}
8981
8982
8983THREADED_TEST(NestedHandleScopeAndContexts) {
8984 v8::HandleScope outer;
8985 v8::Persistent<Context> env = Context::New();
8986 env->Enter();
8987 v8::Handle<Value> value = NestedScope(env);
8988 v8::Handle<String> str = value->ToString();
8989 env->Exit();
8990 env.Dispose();
8991}
8992
8993
8994THREADED_TEST(ExternalAllocatedMemory) {
8995 v8::HandleScope outer;
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008996 v8::Persistent<Context> env = Context::New();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008997 const int kSize = 1024*1024;
8998 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
8999 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
9000}
9001
9002
9003THREADED_TEST(DisposeEnteredContext) {
9004 v8::HandleScope scope;
9005 LocalContext outer;
9006 { v8::Persistent<v8::Context> inner = v8::Context::New();
9007 inner->Enter();
9008 inner.Dispose();
9009 inner.Clear();
9010 inner->Exit();
9011 }
9012}
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009013
9014
9015// Regression test for issue 54, object templates with internal fields
9016// but no accessors or interceptors did not get their internal field
9017// count set on instances.
9018THREADED_TEST(Regress54) {
9019 v8::HandleScope outer;
9020 LocalContext context;
9021 static v8::Persistent<v8::ObjectTemplate> templ;
9022 if (templ.IsEmpty()) {
9023 v8::HandleScope inner;
9024 v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
9025 local->SetInternalFieldCount(1);
9026 templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
9027 }
9028 v8::Handle<v8::Object> result = templ->NewInstance();
9029 CHECK_EQ(1, result->InternalFieldCount());
9030}
9031
9032
9033// If part of the threaded tests, this test makes ThreadingTest fail
9034// on mac.
9035TEST(CatchStackOverflow) {
9036 v8::HandleScope scope;
9037 LocalContext context;
9038 v8::TryCatch try_catch;
9039 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
9040 "function f() {"
9041 " return f();"
9042 "}"
9043 ""
9044 "f();"));
9045 v8::Handle<v8::Value> result = script->Run();
9046 CHECK(result.IsEmpty());
9047}
9048
9049
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00009050static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
9051 const char* resource_name,
9052 int line_offset) {
9053 v8::HandleScope scope;
9054 v8::TryCatch try_catch;
9055 v8::Handle<v8::Value> result = script->Run();
9056 CHECK(result.IsEmpty());
9057 CHECK(try_catch.HasCaught());
9058 v8::Handle<v8::Message> message = try_catch.Message();
9059 CHECK(!message.IsEmpty());
9060 CHECK_EQ(10 + line_offset, message->GetLineNumber());
9061 CHECK_EQ(91, message->GetStartPosition());
9062 CHECK_EQ(92, message->GetEndPosition());
9063 CHECK_EQ(2, message->GetStartColumn());
9064 CHECK_EQ(3, message->GetEndColumn());
9065 v8::String::AsciiValue line(message->GetSourceLine());
9066 CHECK_EQ(" throw 'nirk';", *line);
9067 v8::String::AsciiValue name(message->GetScriptResourceName());
9068 CHECK_EQ(resource_name, *name);
9069}
9070
9071
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009072THREADED_TEST(TryCatchSourceInfo) {
9073 v8::HandleScope scope;
9074 LocalContext context;
9075 v8::Handle<v8::String> source = v8::String::New(
9076 "function Foo() {\n"
9077 " return Bar();\n"
9078 "}\n"
9079 "\n"
9080 "function Bar() {\n"
9081 " return Baz();\n"
9082 "}\n"
9083 "\n"
9084 "function Baz() {\n"
9085 " throw 'nirk';\n"
9086 "}\n"
9087 "\n"
9088 "Foo();\n");
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00009089
9090 const char* resource_name;
9091 v8::Handle<v8::Script> script;
9092 resource_name = "test.js";
9093 script = v8::Script::Compile(source, v8::String::New(resource_name));
9094 CheckTryCatchSourceInfo(script, resource_name, 0);
9095
9096 resource_name = "test1.js";
9097 v8::ScriptOrigin origin1(v8::String::New(resource_name));
9098 script = v8::Script::Compile(source, &origin1);
9099 CheckTryCatchSourceInfo(script, resource_name, 0);
9100
9101 resource_name = "test2.js";
9102 v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
9103 script = v8::Script::Compile(source, &origin2);
9104 CheckTryCatchSourceInfo(script, resource_name, 7);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009105}
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00009106
9107
9108THREADED_TEST(CompilationCache) {
9109 v8::HandleScope scope;
9110 LocalContext context;
9111 v8::Handle<v8::String> source0 = v8::String::New("1234");
9112 v8::Handle<v8::String> source1 = v8::String::New("1234");
9113 v8::Handle<v8::Script> script0 =
9114 v8::Script::Compile(source0, v8::String::New("test.js"));
9115 v8::Handle<v8::Script> script1 =
9116 v8::Script::Compile(source1, v8::String::New("test.js"));
9117 v8::Handle<v8::Script> script2 =
9118 v8::Script::Compile(source0); // different origin
9119 CHECK_EQ(1234, script0->Run()->Int32Value());
9120 CHECK_EQ(1234, script1->Run()->Int32Value());
9121 CHECK_EQ(1234, script2->Run()->Int32Value());
9122}
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00009123
9124
9125static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
9126 ApiTestFuzzer::Fuzz();
9127 return v8_num(42);
9128}
9129
9130
9131THREADED_TEST(CallbackFunctionName) {
9132 v8::HandleScope scope;
9133 LocalContext context;
9134 Local<ObjectTemplate> t = ObjectTemplate::New();
9135 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
9136 context->Global()->Set(v8_str("obj"), t->NewInstance());
9137 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
9138 CHECK(value->IsString());
9139 v8::String::AsciiValue name(value);
9140 CHECK_EQ("asdf", *name);
9141}
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009142
9143
9144THREADED_TEST(DateAccess) {
9145 v8::HandleScope scope;
9146 LocalContext context;
9147 v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
9148 CHECK(date->IsDate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009149 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009150}
9151
9152
9153void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009154 v8::Handle<v8::Object> obj = val.As<v8::Object>();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009155 v8::Handle<v8::Array> props = obj->GetPropertyNames();
9156 CHECK_EQ(elmc, props->Length());
9157 for (int i = 0; i < elmc; i++) {
9158 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
9159 CHECK_EQ(elmv[i], *elm);
9160 }
9161}
9162
9163
9164THREADED_TEST(PropertyEnumeration) {
9165 v8::HandleScope scope;
9166 LocalContext context;
9167 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
9168 "var result = [];"
9169 "result[0] = {};"
9170 "result[1] = {a: 1, b: 2};"
9171 "result[2] = [1, 2, 3];"
9172 "var proto = {x: 1, y: 2, z: 3};"
9173 "var x = { __proto__: proto, w: 0, z: 1 };"
9174 "result[3] = x;"
9175 "result;"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009176 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009177 CHECK_EQ(4, elms->Length());
9178 int elmc0 = 0;
9179 const char** elmv0 = NULL;
9180 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
9181 int elmc1 = 2;
9182 const char* elmv1[] = {"a", "b"};
9183 CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
9184 int elmc2 = 3;
9185 const char* elmv2[] = {"0", "1", "2"};
9186 CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
9187 int elmc3 = 4;
9188 const char* elmv3[] = {"w", "z", "x", "y"};
9189 CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
9190}
ager@chromium.org870a0b62008-11-04 11:43:05 +00009191
9192
ager@chromium.org870a0b62008-11-04 11:43:05 +00009193static bool NamedSetAccessBlocker(Local<v8::Object> obj,
9194 Local<Value> name,
9195 v8::AccessType type,
9196 Local<Value> data) {
9197 return type != v8::ACCESS_SET;
9198}
9199
9200
9201static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
9202 uint32_t key,
9203 v8::AccessType type,
9204 Local<Value> data) {
9205 return type != v8::ACCESS_SET;
9206}
9207
9208
9209THREADED_TEST(DisableAccessChecksWhileConfiguring) {
9210 v8::HandleScope scope;
9211 LocalContext context;
9212 Local<ObjectTemplate> templ = ObjectTemplate::New();
9213 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
9214 IndexedSetAccessBlocker);
9215 templ->Set(v8_str("x"), v8::True());
9216 Local<v8::Object> instance = templ->NewInstance();
9217 context->Global()->Set(v8_str("obj"), instance);
9218 Local<Value> value = CompileRun("obj.x");
9219 CHECK(value->BooleanValue());
9220}
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009221
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009222
ager@chromium.org32912102009-01-16 10:38:43 +00009223static bool NamedGetAccessBlocker(Local<v8::Object> obj,
9224 Local<Value> name,
9225 v8::AccessType type,
9226 Local<Value> data) {
9227 return false;
9228}
9229
9230
9231static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
9232 uint32_t key,
9233 v8::AccessType type,
9234 Local<Value> data) {
9235 return false;
9236}
9237
9238
9239
9240THREADED_TEST(AccessChecksReenabledCorrectly) {
9241 v8::HandleScope scope;
9242 LocalContext context;
9243 Local<ObjectTemplate> templ = ObjectTemplate::New();
9244 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
9245 IndexedGetAccessBlocker);
9246 templ->Set(v8_str("a"), v8_str("a"));
9247 // Add more than 8 (see kMaxFastProperties) properties
9248 // so that the constructor will force copying map.
9249 // Cannot sprintf, gcc complains unsafety.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009250 char buf[4];
ager@chromium.org32912102009-01-16 10:38:43 +00009251 for (char i = '0'; i <= '9' ; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009252 buf[0] = i;
ager@chromium.org32912102009-01-16 10:38:43 +00009253 for (char j = '0'; j <= '9'; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009254 buf[1] = j;
ager@chromium.org32912102009-01-16 10:38:43 +00009255 for (char k = '0'; k <= '9'; k++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009256 buf[2] = k;
9257 buf[3] = 0;
ager@chromium.org32912102009-01-16 10:38:43 +00009258 templ->Set(v8_str(buf), v8::Number::New(k));
9259 }
9260 }
9261 }
9262
9263 Local<v8::Object> instance_1 = templ->NewInstance();
9264 context->Global()->Set(v8_str("obj_1"), instance_1);
9265
9266 Local<Value> value_1 = CompileRun("obj_1.a");
9267 CHECK(value_1->IsUndefined());
9268
9269 Local<v8::Object> instance_2 = templ->NewInstance();
9270 context->Global()->Set(v8_str("obj_2"), instance_2);
9271
9272 Local<Value> value_2 = CompileRun("obj_2.a");
9273 CHECK(value_2->IsUndefined());
9274}
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009275
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009276
ager@chromium.org8bb60582008-12-11 12:02:20 +00009277// This tests that access check information remains on the global
9278// object template when creating contexts.
9279THREADED_TEST(AccessControlRepeatedContextCreation) {
9280 v8::HandleScope handle_scope;
9281 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
9282 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
9283 IndexedSetAccessBlocker);
9284 i::Handle<i::ObjectTemplateInfo> internal_template =
9285 v8::Utils::OpenHandle(*global_template);
9286 CHECK(!internal_template->constructor()->IsUndefined());
9287 i::Handle<i::FunctionTemplateInfo> constructor(
9288 i::FunctionTemplateInfo::cast(internal_template->constructor()));
9289 CHECK(!constructor->access_check_info()->IsUndefined());
9290 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
9291 CHECK(!constructor->access_check_info()->IsUndefined());
9292}
9293
9294
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009295THREADED_TEST(TurnOnAccessCheck) {
9296 v8::HandleScope handle_scope;
9297
9298 // Create an environment with access check to the global object disabled by
9299 // default.
9300 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
9301 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
9302 IndexedGetAccessBlocker,
9303 v8::Handle<v8::Value>(),
9304 false);
9305 v8::Persistent<Context> context = Context::New(NULL, global_template);
9306 Context::Scope context_scope(context);
9307
9308 // Set up a property and a number of functions.
9309 context->Global()->Set(v8_str("a"), v8_num(1));
9310 CompileRun("function f1() {return a;}"
9311 "function f2() {return a;}"
9312 "function g1() {return h();}"
9313 "function g2() {return h();}"
9314 "function h() {return 1;}");
9315 Local<Function> f1 =
9316 Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
9317 Local<Function> f2 =
9318 Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
9319 Local<Function> g1 =
9320 Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
9321 Local<Function> g2 =
9322 Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
9323 Local<Function> h =
9324 Local<Function>::Cast(context->Global()->Get(v8_str("h")));
9325
9326 // Get the global object.
9327 v8::Handle<v8::Object> global = context->Global();
9328
9329 // Call f1 one time and f2 a number of times. This will ensure that f1 still
9330 // uses the runtime system to retreive property a whereas f2 uses global load
9331 // inline cache.
9332 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
9333 for (int i = 0; i < 4; i++) {
9334 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
9335 }
9336
9337 // Same for g1 and g2.
9338 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
9339 for (int i = 0; i < 4; i++) {
9340 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
9341 }
9342
9343 // Detach the global and turn on access check.
9344 context->DetachGlobal();
9345 context->Global()->TurnOnAccessCheck();
9346
9347 // Failing access check to property get results in undefined.
9348 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
9349 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
9350
9351 // Failing access check to function call results in exception.
9352 CHECK(g1->Call(global, 0, NULL).IsEmpty());
9353 CHECK(g2->Call(global, 0, NULL).IsEmpty());
9354
9355 // No failing access check when just returning a constant.
9356 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
9357}
9358
9359
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009360v8::Handle<v8::String> a;
9361v8::Handle<v8::String> h;
9362
9363static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
9364 Local<Value> name,
9365 v8::AccessType type,
9366 Local<Value> data) {
9367 return !(name->Equals(a) || name->Equals(h));
9368}
9369
9370
9371THREADED_TEST(TurnOnAccessCheckAndRecompile) {
9372 v8::HandleScope handle_scope;
9373
9374 // Create an environment with access check to the global object disabled by
9375 // default. When the registered access checker will block access to properties
9376 // a and h
9377 a = v8_str("a");
9378 h = v8_str("h");
9379 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
9380 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
9381 IndexedGetAccessBlocker,
9382 v8::Handle<v8::Value>(),
9383 false);
9384 v8::Persistent<Context> context = Context::New(NULL, global_template);
9385 Context::Scope context_scope(context);
9386
9387 // Set up a property and a number of functions.
9388 context->Global()->Set(v8_str("a"), v8_num(1));
9389 static const char* source = "function f1() {return a;}"
9390 "function f2() {return a;}"
9391 "function g1() {return h();}"
9392 "function g2() {return h();}"
9393 "function h() {return 1;}";
9394
9395 CompileRun(source);
9396 Local<Function> f1;
9397 Local<Function> f2;
9398 Local<Function> g1;
9399 Local<Function> g2;
9400 Local<Function> h;
9401 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
9402 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
9403 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
9404 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
9405 h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
9406
9407 // Get the global object.
9408 v8::Handle<v8::Object> global = context->Global();
9409
9410 // Call f1 one time and f2 a number of times. This will ensure that f1 still
9411 // uses the runtime system to retreive property a whereas f2 uses global load
9412 // inline cache.
9413 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
9414 for (int i = 0; i < 4; i++) {
9415 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
9416 }
9417
9418 // Same for g1 and g2.
9419 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
9420 for (int i = 0; i < 4; i++) {
9421 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
9422 }
9423
9424 // Detach the global and turn on access check now blocking access to property
9425 // a and function h.
9426 context->DetachGlobal();
9427 context->Global()->TurnOnAccessCheck();
9428
9429 // Failing access check to property get results in undefined.
9430 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
9431 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
9432
9433 // Failing access check to function call results in exception.
9434 CHECK(g1->Call(global, 0, NULL).IsEmpty());
9435 CHECK(g2->Call(global, 0, NULL).IsEmpty());
9436
9437 // No failing access check when just returning a constant.
9438 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
9439
9440 // Now compile the source again. And get the newly compiled functions, except
9441 // for h for which access is blocked.
9442 CompileRun(source);
9443 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
9444 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
9445 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
9446 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
9447 CHECK(context->Global()->Get(v8_str("h"))->IsUndefined());
9448
9449 // Failing access check to property get results in undefined.
9450 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
9451 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
9452
9453 // Failing access check to function call results in exception.
9454 CHECK(g1->Call(global, 0, NULL).IsEmpty());
9455 CHECK(g2->Call(global, 0, NULL).IsEmpty());
9456}
9457
9458
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009459// This test verifies that pre-compilation (aka preparsing) can be called
9460// without initializing the whole VM. Thus we cannot run this test in a
9461// multi-threaded setup.
9462TEST(PreCompile) {
9463 // TODO(155): This test would break without the initialization of V8. This is
9464 // a workaround for now to make this test not fail.
9465 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009466 const char* script = "function foo(a) { return a+1; }";
9467 v8::ScriptData* sd =
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009468 v8::ScriptData::PreCompile(script, i::StrLength(script));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009469 CHECK_NE(sd->Length(), 0);
9470 CHECK_NE(sd->Data(), NULL);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009471 CHECK(!sd->HasError());
9472 delete sd;
9473}
9474
9475
9476TEST(PreCompileWithError) {
9477 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009478 const char* script = "function foo(a) { return 1 * * 2; }";
9479 v8::ScriptData* sd =
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009480 v8::ScriptData::PreCompile(script, i::StrLength(script));
9481 CHECK(sd->HasError());
9482 delete sd;
9483}
9484
9485
9486TEST(Regress31661) {
9487 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009488 const char* script = " The Definintive Guide";
9489 v8::ScriptData* sd =
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009490 v8::ScriptData::PreCompile(script, i::StrLength(script));
9491 CHECK(sd->HasError());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009492 delete sd;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009493}
9494
9495
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009496// Tests that ScriptData can be serialized and deserialized.
9497TEST(PreCompileSerialization) {
9498 v8::V8::Initialize();
9499 const char* script = "function foo(a) { return a+1; }";
9500 v8::ScriptData* sd =
9501 v8::ScriptData::PreCompile(script, i::StrLength(script));
9502
9503 // Serialize.
9504 int serialized_data_length = sd->Length();
9505 char* serialized_data = i::NewArray<char>(serialized_data_length);
9506 memcpy(serialized_data, sd->Data(), serialized_data_length);
9507
9508 // Deserialize.
9509 v8::ScriptData* deserialized_sd =
9510 v8::ScriptData::New(serialized_data, serialized_data_length);
9511
9512 // Verify that the original is the same as the deserialized.
9513 CHECK_EQ(sd->Length(), deserialized_sd->Length());
9514 CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
9515 CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
9516
9517 delete sd;
9518 delete deserialized_sd;
9519}
9520
9521
9522// Attempts to deserialize bad data.
9523TEST(PreCompileDeserializationError) {
9524 v8::V8::Initialize();
9525 const char* data = "DONT CARE";
9526 int invalid_size = 3;
9527 v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
9528
9529 CHECK_EQ(0, sd->Length());
9530
9531 delete sd;
9532}
9533
9534
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00009535// Attempts to deserialize bad data.
9536TEST(PreCompileInvalidPreparseDataError) {
9537 v8::V8::Initialize();
9538 v8::HandleScope scope;
9539 LocalContext context;
9540
9541 const char* script = "function foo(){ return 5;}\n"
9542 "function bar(){ return 6 + 7;} foo();";
9543 v8::ScriptData* sd =
9544 v8::ScriptData::PreCompile(script, i::StrLength(script));
9545 CHECK(!sd->HasError());
9546 // ScriptDataImpl private implementation details
ager@chromium.orgbeb25712010-11-29 08:02:25 +00009547 const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00009548 const int kFunctionEntrySize = i::FunctionEntry::kSize;
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00009549 const int kFunctionEntryStartOffset = 0;
9550 const int kFunctionEntryEndOffset = 1;
9551 unsigned* sd_data =
9552 reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00009553
9554 // Overwrite function bar's end position with 0.
9555 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
9556 v8::TryCatch try_catch;
9557
9558 Local<String> source = String::New(script);
9559 Local<Script> compiled_script = Script::New(source, NULL, sd);
9560 CHECK(try_catch.HasCaught());
9561 String::AsciiValue exception_value(try_catch.Message()->Get());
9562 CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
9563 *exception_value);
9564
9565 try_catch.Reset();
9566 // Overwrite function bar's start position with 200. The function entry
9567 // will not be found when searching for it by position.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00009568 sd = v8::ScriptData::PreCompile(script, i::StrLength(script));
9569 sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00009570 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
9571 200;
9572 compiled_script = Script::New(source, NULL, sd);
9573 CHECK(try_catch.HasCaught());
9574 String::AsciiValue second_exception_value(try_catch.Message()->Get());
9575 CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
9576 *second_exception_value);
9577
9578 delete sd;
9579}
9580
9581
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00009582// Verifies that the Handle<String> and const char* versions of the API produce
9583// the same results (at least for one trivial case).
9584TEST(PreCompileAPIVariationsAreSame) {
9585 v8::V8::Initialize();
9586 v8::HandleScope scope;
9587
9588 const char* cstring = "function foo(a) { return a+1; }";
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009589
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00009590 v8::ScriptData* sd_from_cstring =
9591 v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
9592
9593 TestAsciiResource* resource = new TestAsciiResource(cstring);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009594 v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile(
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00009595 v8::String::NewExternal(resource));
9596
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009597 v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile(
9598 v8::String::New(cstring));
9599
9600 CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00009601 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009602 sd_from_external_string->Data(),
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00009603 sd_from_cstring->Length()));
9604
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009605 CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length());
9606 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
9607 sd_from_string->Data(),
9608 sd_from_cstring->Length()));
9609
9610
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00009611 delete sd_from_cstring;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009612 delete sd_from_external_string;
9613 delete sd_from_string;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00009614}
9615
9616
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009617// This tests that we do not allow dictionary load/call inline caches
9618// to use functions that have not yet been compiled. The potential
9619// problem of loading a function that has not yet been compiled can
9620// arise because we share code between contexts via the compilation
9621// cache.
9622THREADED_TEST(DictionaryICLoadedFunction) {
9623 v8::HandleScope scope;
9624 // Test LoadIC.
9625 for (int i = 0; i < 2; i++) {
9626 LocalContext context;
9627 context->Global()->Set(v8_str("tmp"), v8::True());
9628 context->Global()->Delete(v8_str("tmp"));
9629 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
9630 }
9631 // Test CallIC.
9632 for (int i = 0; i < 2; i++) {
9633 LocalContext context;
9634 context->Global()->Set(v8_str("tmp"), v8::True());
9635 context->Global()->Delete(v8_str("tmp"));
9636 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
9637 }
9638}
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009639
9640
9641// Test that cross-context new calls use the context of the callee to
9642// create the new JavaScript object.
9643THREADED_TEST(CrossContextNew) {
9644 v8::HandleScope scope;
9645 v8::Persistent<Context> context0 = Context::New();
9646 v8::Persistent<Context> context1 = Context::New();
9647
9648 // Allow cross-domain access.
9649 Local<String> token = v8_str("<security token>");
9650 context0->SetSecurityToken(token);
9651 context1->SetSecurityToken(token);
9652
9653 // Set an 'x' property on the Object prototype and define a
9654 // constructor function in context0.
9655 context0->Enter();
9656 CompileRun("Object.prototype.x = 42; function C() {};");
9657 context0->Exit();
9658
9659 // Call the constructor function from context0 and check that the
9660 // result has the 'x' property.
9661 context1->Enter();
9662 context1->Global()->Set(v8_str("other"), context0->Global());
9663 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
9664 CHECK(value->IsInt32());
9665 CHECK_EQ(42, value->Int32Value());
9666 context1->Exit();
9667
9668 // Dispose the contexts to allow them to be garbage collected.
9669 context0.Dispose();
9670 context1.Dispose();
9671}
ager@chromium.org381abbb2009-02-25 13:23:22 +00009672
9673
9674class RegExpInterruptTest {
9675 public:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009676 RegExpInterruptTest() : block_(NULL) {}
9677 ~RegExpInterruptTest() { delete block_; }
ager@chromium.org381abbb2009-02-25 13:23:22 +00009678 void RunTest() {
9679 block_ = i::OS::CreateSemaphore(0);
9680 gc_count_ = 0;
9681 gc_during_regexp_ = 0;
9682 regexp_success_ = false;
9683 gc_success_ = false;
9684 GCThread gc_thread(this);
9685 gc_thread.Start();
9686 v8::Locker::StartPreemption(1);
9687
9688 LongRunningRegExp();
9689 {
9690 v8::Unlocker unlock;
9691 gc_thread.Join();
9692 }
9693 v8::Locker::StopPreemption();
9694 CHECK(regexp_success_);
9695 CHECK(gc_success_);
9696 }
9697 private:
9698 // Number of garbage collections required.
9699 static const int kRequiredGCs = 5;
9700
9701 class GCThread : public i::Thread {
9702 public:
9703 explicit GCThread(RegExpInterruptTest* test)
9704 : test_(test) {}
9705 virtual void Run() {
9706 test_->CollectGarbage();
9707 }
9708 private:
9709 RegExpInterruptTest* test_;
9710 };
9711
9712 void CollectGarbage() {
9713 block_->Wait();
9714 while (gc_during_regexp_ < kRequiredGCs) {
9715 {
9716 v8::Locker lock;
9717 // TODO(lrn): Perhaps create some garbage before collecting.
ager@chromium.orgab99eea2009-08-25 07:05:41 +00009718 i::Heap::CollectAllGarbage(false);
ager@chromium.org381abbb2009-02-25 13:23:22 +00009719 gc_count_++;
9720 }
9721 i::OS::Sleep(1);
9722 }
9723 gc_success_ = true;
9724 }
9725
9726 void LongRunningRegExp() {
9727 block_->Signal(); // Enable garbage collection thread on next preemption.
9728 int rounds = 0;
9729 while (gc_during_regexp_ < kRequiredGCs) {
9730 int gc_before = gc_count_;
9731 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009732 // Match 15-30 "a"'s against 14 and a "b".
ager@chromium.org381abbb2009-02-25 13:23:22 +00009733 const char* c_source =
9734 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
9735 ".exec('aaaaaaaaaaaaaaab') === null";
9736 Local<String> source = String::New(c_source);
9737 Local<Script> script = Script::Compile(source);
9738 Local<Value> result = script->Run();
9739 if (!result->BooleanValue()) {
9740 gc_during_regexp_ = kRequiredGCs; // Allow gc thread to exit.
9741 return;
9742 }
9743 }
9744 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009745 // Match 15-30 "a"'s against 15 and a "b".
ager@chromium.org381abbb2009-02-25 13:23:22 +00009746 const char* c_source =
9747 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
9748 ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
9749 Local<String> source = String::New(c_source);
9750 Local<Script> script = Script::Compile(source);
9751 Local<Value> result = script->Run();
9752 if (!result->BooleanValue()) {
9753 gc_during_regexp_ = kRequiredGCs;
9754 return;
9755 }
9756 }
9757 int gc_after = gc_count_;
9758 gc_during_regexp_ += gc_after - gc_before;
9759 rounds++;
9760 i::OS::Sleep(1);
9761 }
9762 regexp_success_ = true;
9763 }
9764
9765 i::Semaphore* block_;
9766 int gc_count_;
9767 int gc_during_regexp_;
9768 bool regexp_success_;
9769 bool gc_success_;
9770};
9771
9772
9773// Test that a regular expression execution can be interrupted and
9774// survive a garbage collection.
9775TEST(RegExpInterruption) {
9776 v8::Locker lock;
9777 v8::V8::Initialize();
9778 v8::HandleScope scope;
9779 Local<Context> local_env;
9780 {
9781 LocalContext env;
9782 local_env = env.local();
9783 }
9784
9785 // Local context should still be live.
9786 CHECK(!local_env.IsEmpty());
9787 local_env->Enter();
9788
9789 // Should complete without problems.
9790 RegExpInterruptTest().RunTest();
9791
9792 local_env->Exit();
9793}
ager@chromium.org3b45ab52009-03-19 22:21:34 +00009794
9795
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009796class ApplyInterruptTest {
9797 public:
9798 ApplyInterruptTest() : block_(NULL) {}
9799 ~ApplyInterruptTest() { delete block_; }
9800 void RunTest() {
9801 block_ = i::OS::CreateSemaphore(0);
9802 gc_count_ = 0;
9803 gc_during_apply_ = 0;
9804 apply_success_ = false;
9805 gc_success_ = false;
9806 GCThread gc_thread(this);
9807 gc_thread.Start();
9808 v8::Locker::StartPreemption(1);
9809
9810 LongRunningApply();
9811 {
9812 v8::Unlocker unlock;
9813 gc_thread.Join();
9814 }
9815 v8::Locker::StopPreemption();
9816 CHECK(apply_success_);
9817 CHECK(gc_success_);
9818 }
9819 private:
9820 // Number of garbage collections required.
9821 static const int kRequiredGCs = 2;
9822
9823 class GCThread : public i::Thread {
9824 public:
9825 explicit GCThread(ApplyInterruptTest* test)
9826 : test_(test) {}
9827 virtual void Run() {
9828 test_->CollectGarbage();
9829 }
9830 private:
9831 ApplyInterruptTest* test_;
9832 };
9833
9834 void CollectGarbage() {
9835 block_->Wait();
9836 while (gc_during_apply_ < kRequiredGCs) {
9837 {
9838 v8::Locker lock;
ager@chromium.orgab99eea2009-08-25 07:05:41 +00009839 i::Heap::CollectAllGarbage(false);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009840 gc_count_++;
9841 }
9842 i::OS::Sleep(1);
9843 }
9844 gc_success_ = true;
9845 }
9846
9847 void LongRunningApply() {
9848 block_->Signal();
9849 int rounds = 0;
9850 while (gc_during_apply_ < kRequiredGCs) {
9851 int gc_before = gc_count_;
9852 {
9853 const char* c_source =
9854 "function do_very_little(bar) {"
9855 " this.foo = bar;"
9856 "}"
9857 "for (var i = 0; i < 100000; i++) {"
9858 " do_very_little.apply(this, ['bar']);"
9859 "}";
9860 Local<String> source = String::New(c_source);
9861 Local<Script> script = Script::Compile(source);
9862 Local<Value> result = script->Run();
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00009863 // Check that no exception was thrown.
9864 CHECK(!result.IsEmpty());
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009865 }
9866 int gc_after = gc_count_;
9867 gc_during_apply_ += gc_after - gc_before;
9868 rounds++;
9869 }
9870 apply_success_ = true;
9871 }
9872
9873 i::Semaphore* block_;
9874 int gc_count_;
9875 int gc_during_apply_;
9876 bool apply_success_;
9877 bool gc_success_;
9878};
9879
9880
9881// Test that nothing bad happens if we get a preemption just when we were
9882// about to do an apply().
9883TEST(ApplyInterruption) {
9884 v8::Locker lock;
9885 v8::V8::Initialize();
9886 v8::HandleScope scope;
9887 Local<Context> local_env;
9888 {
9889 LocalContext env;
9890 local_env = env.local();
9891 }
9892
9893 // Local context should still be live.
9894 CHECK(!local_env.IsEmpty());
9895 local_env->Enter();
9896
9897 // Should complete without problems.
9898 ApplyInterruptTest().RunTest();
9899
9900 local_env->Exit();
9901}
9902
9903
ager@chromium.org3b45ab52009-03-19 22:21:34 +00009904// Verify that we can clone an object
9905TEST(ObjectClone) {
9906 v8::HandleScope scope;
9907 LocalContext env;
9908
9909 const char* sample =
9910 "var rv = {};" \
9911 "rv.alpha = 'hello';" \
9912 "rv.beta = 123;" \
9913 "rv;";
9914
9915 // Create an object, verify basics.
9916 Local<Value> val = CompileRun(sample);
9917 CHECK(val->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009918 Local<v8::Object> obj = val.As<v8::Object>();
ager@chromium.org3b45ab52009-03-19 22:21:34 +00009919 obj->Set(v8_str("gamma"), v8_str("cloneme"));
9920
9921 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
9922 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
9923 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
9924
9925 // Clone it.
9926 Local<v8::Object> clone = obj->Clone();
9927 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
9928 CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
9929 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
9930
9931 // Set a property on the clone, verify each object.
9932 clone->Set(v8_str("beta"), v8::Integer::New(456));
9933 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
9934 CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
9935}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009936
9937
ager@chromium.org5ec48922009-05-05 07:25:34 +00009938class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
9939 public:
9940 explicit AsciiVectorResource(i::Vector<const char> vector)
9941 : data_(vector) {}
9942 virtual ~AsciiVectorResource() {}
9943 virtual size_t length() const { return data_.length(); }
9944 virtual const char* data() const { return data_.start(); }
9945 private:
9946 i::Vector<const char> data_;
9947};
9948
9949
9950class UC16VectorResource : public v8::String::ExternalStringResource {
9951 public:
9952 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
9953 : data_(vector) {}
9954 virtual ~UC16VectorResource() {}
9955 virtual size_t length() const { return data_.length(); }
9956 virtual const i::uc16* data() const { return data_.start(); }
9957 private:
9958 i::Vector<const i::uc16> data_;
9959};
9960
9961
9962static void MorphAString(i::String* string,
9963 AsciiVectorResource* ascii_resource,
9964 UC16VectorResource* uc16_resource) {
9965 CHECK(i::StringShape(string).IsExternal());
9966 if (string->IsAsciiRepresentation()) {
9967 // Check old map is not symbol or long.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009968 CHECK(string->map() == i::Heap::external_ascii_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009969 // Morph external string to be TwoByte string.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009970 string->set_map(i::Heap::external_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009971 i::ExternalTwoByteString* morphed =
9972 i::ExternalTwoByteString::cast(string);
9973 morphed->set_resource(uc16_resource);
9974 } else {
9975 // Check old map is not symbol or long.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009976 CHECK(string->map() == i::Heap::external_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009977 // Morph external string to be ASCII string.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009978 string->set_map(i::Heap::external_ascii_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009979 i::ExternalAsciiString* morphed =
9980 i::ExternalAsciiString::cast(string);
9981 morphed->set_resource(ascii_resource);
9982 }
9983}
9984
9985
9986// Test that we can still flatten a string if the components it is built up
9987// from have been turned into 16 bit strings in the mean time.
9988THREADED_TEST(MorphCompositeStringTest) {
9989 const char* c_string = "Now is the time for all good men"
9990 " to come to the aid of the party";
9991 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
9992 {
9993 v8::HandleScope scope;
9994 LocalContext env;
9995 AsciiVectorResource ascii_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009996 i::Vector<const char>(c_string, i::StrLength(c_string)));
ager@chromium.org5ec48922009-05-05 07:25:34 +00009997 UC16VectorResource uc16_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009998 i::Vector<const uint16_t>(two_byte_string,
9999 i::StrLength(c_string)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000010000
10001 Local<String> lhs(v8::Utils::ToLocal(
10002 i::Factory::NewExternalStringFromAscii(&ascii_resource)));
10003 Local<String> rhs(v8::Utils::ToLocal(
10004 i::Factory::NewExternalStringFromAscii(&ascii_resource)));
10005
10006 env->Global()->Set(v8_str("lhs"), lhs);
10007 env->Global()->Set(v8_str("rhs"), rhs);
10008
10009 CompileRun(
10010 "var cons = lhs + rhs;"
10011 "var slice = lhs.substring(1, lhs.length - 1);"
10012 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
10013
10014 MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
10015 MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
10016
10017 // Now do some stuff to make sure the strings are flattened, etc.
10018 CompileRun(
10019 "/[^a-z]/.test(cons);"
10020 "/[^a-z]/.test(slice);"
10021 "/[^a-z]/.test(slice_on_cons);");
10022 const char* expected_cons =
10023 "Now is the time for all good men to come to the aid of the party"
10024 "Now is the time for all good men to come to the aid of the party";
10025 const char* expected_slice =
10026 "ow is the time for all good men to come to the aid of the part";
10027 const char* expected_slice_on_cons =
10028 "ow is the time for all good men to come to the aid of the party"
10029 "Now is the time for all good men to come to the aid of the part";
10030 CHECK_EQ(String::New(expected_cons),
10031 env->Global()->Get(v8_str("cons")));
10032 CHECK_EQ(String::New(expected_slice),
10033 env->Global()->Get(v8_str("slice")));
10034 CHECK_EQ(String::New(expected_slice_on_cons),
10035 env->Global()->Get(v8_str("slice_on_cons")));
10036 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010037 i::DeleteArray(two_byte_string);
ager@chromium.org5ec48922009-05-05 07:25:34 +000010038}
10039
10040
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000010041TEST(CompileExternalTwoByteSource) {
10042 v8::HandleScope scope;
10043 LocalContext context;
10044
10045 // This is a very short list of sources, which currently is to check for a
10046 // regression caused by r2703.
10047 const char* ascii_sources[] = {
10048 "0.5",
10049 "-0.5", // This mainly testes PushBack in the Scanner.
10050 "--0.5", // This mainly testes PushBack in the Scanner.
10051 NULL
10052 };
10053
10054 // Compile the sources as external two byte strings.
10055 for (int i = 0; ascii_sources[i] != NULL; i++) {
10056 uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
10057 UC16VectorResource uc16_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010058 i::Vector<const uint16_t>(two_byte_string,
10059 i::StrLength(ascii_sources[i])));
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000010060 v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
10061 v8::Script::Compile(source);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010062 i::DeleteArray(two_byte_string);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000010063 }
10064}
10065
10066
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010067class RegExpStringModificationTest {
10068 public:
10069 RegExpStringModificationTest()
10070 : block_(i::OS::CreateSemaphore(0)),
10071 morphs_(0),
10072 morphs_during_regexp_(0),
10073 ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
10074 uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
10075 ~RegExpStringModificationTest() { delete block_; }
10076 void RunTest() {
10077 regexp_success_ = false;
10078 morph_success_ = false;
10079
10080 // Initialize the contents of two_byte_content_ to be a uc16 representation
10081 // of "aaaaaaaaaaaaaab".
10082 for (int i = 0; i < 14; i++) {
10083 two_byte_content_[i] = 'a';
10084 }
10085 two_byte_content_[14] = 'b';
10086
10087 // Create the input string for the regexp - the one we are going to change
10088 // properties of.
10089 input_ = i::Factory::NewExternalStringFromAscii(&ascii_resource_);
10090
10091 // Inject the input as a global variable.
10092 i::Handle<i::String> input_name =
10093 i::Factory::NewStringFromAscii(i::Vector<const char>("input", 5));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010094 i::Top::global_context()->global()->SetProperty(*input_name,
10095 *input_,
10096 NONE)->ToObjectChecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010097
10098
10099 MorphThread morph_thread(this);
10100 morph_thread.Start();
10101 v8::Locker::StartPreemption(1);
10102 LongRunningRegExp();
10103 {
10104 v8::Unlocker unlock;
10105 morph_thread.Join();
10106 }
10107 v8::Locker::StopPreemption();
10108 CHECK(regexp_success_);
10109 CHECK(morph_success_);
10110 }
10111 private:
10112
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010113 // Number of string modifications required.
10114 static const int kRequiredModifications = 5;
10115 static const int kMaxModifications = 100;
10116
10117 class MorphThread : public i::Thread {
10118 public:
10119 explicit MorphThread(RegExpStringModificationTest* test)
10120 : test_(test) {}
10121 virtual void Run() {
10122 test_->MorphString();
10123 }
10124 private:
10125 RegExpStringModificationTest* test_;
10126 };
10127
10128 void MorphString() {
10129 block_->Wait();
10130 while (morphs_during_regexp_ < kRequiredModifications &&
10131 morphs_ < kMaxModifications) {
10132 {
10133 v8::Locker lock;
10134 // Swap string between ascii and two-byte representation.
10135 i::String* string = *input_;
ager@chromium.org5ec48922009-05-05 07:25:34 +000010136 MorphAString(string, &ascii_resource_, &uc16_resource_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010137 morphs_++;
10138 }
10139 i::OS::Sleep(1);
10140 }
10141 morph_success_ = true;
10142 }
10143
10144 void LongRunningRegExp() {
10145 block_->Signal(); // Enable morphing thread on next preemption.
10146 while (morphs_during_regexp_ < kRequiredModifications &&
10147 morphs_ < kMaxModifications) {
10148 int morphs_before = morphs_;
10149 {
erik.corry@gmail.com145eff52010-08-23 11:36:18 +000010150 v8::HandleScope scope;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010151 // Match 15-30 "a"'s against 14 and a "b".
10152 const char* c_source =
10153 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
10154 ".exec(input) === null";
10155 Local<String> source = String::New(c_source);
10156 Local<Script> script = Script::Compile(source);
10157 Local<Value> result = script->Run();
10158 CHECK(result->IsTrue());
10159 }
10160 int morphs_after = morphs_;
10161 morphs_during_regexp_ += morphs_after - morphs_before;
10162 }
10163 regexp_success_ = true;
10164 }
10165
10166 i::uc16 two_byte_content_[15];
10167 i::Semaphore* block_;
10168 int morphs_;
10169 int morphs_during_regexp_;
10170 bool regexp_success_;
10171 bool morph_success_;
10172 i::Handle<i::String> input_;
10173 AsciiVectorResource ascii_resource_;
10174 UC16VectorResource uc16_resource_;
10175};
10176
10177
10178// Test that a regular expression execution can be interrupted and
10179// the string changed without failing.
10180TEST(RegExpStringModification) {
10181 v8::Locker lock;
10182 v8::V8::Initialize();
10183 v8::HandleScope scope;
10184 Local<Context> local_env;
10185 {
10186 LocalContext env;
10187 local_env = env.local();
10188 }
10189
10190 // Local context should still be live.
10191 CHECK(!local_env.IsEmpty());
10192 local_env->Enter();
10193
10194 // Should complete without problems.
10195 RegExpStringModificationTest().RunTest();
10196
10197 local_env->Exit();
10198}
10199
10200
10201// Test that we can set a property on the global object even if there
10202// is a read-only property in the prototype chain.
10203TEST(ReadOnlyPropertyInGlobalProto) {
10204 v8::HandleScope scope;
10205 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
10206 LocalContext context(0, templ);
10207 v8::Handle<v8::Object> global = context->Global();
10208 v8::Handle<v8::Object> global_proto =
10209 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
10210 global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
10211 global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
10212 // Check without 'eval' or 'with'.
10213 v8::Handle<v8::Value> res =
10214 CompileRun("function f() { x = 42; return x; }; f()");
10215 // Check with 'eval'.
10216 res = CompileRun("function f() { eval('1'); y = 42; return y; }; f()");
10217 CHECK_EQ(v8::Integer::New(42), res);
10218 // Check with 'with'.
10219 res = CompileRun("function f() { with (this) { y = 42 }; return y; }; f()");
10220 CHECK_EQ(v8::Integer::New(42), res);
10221}
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010222
10223static int force_set_set_count = 0;
10224static int force_set_get_count = 0;
10225bool pass_on_get = false;
10226
10227static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
10228 const v8::AccessorInfo& info) {
10229 force_set_get_count++;
10230 if (pass_on_get) {
10231 return v8::Handle<v8::Value>();
10232 } else {
10233 return v8::Int32::New(3);
10234 }
10235}
10236
10237static void ForceSetSetter(v8::Local<v8::String> name,
10238 v8::Local<v8::Value> value,
10239 const v8::AccessorInfo& info) {
10240 force_set_set_count++;
10241}
10242
10243static v8::Handle<v8::Value> ForceSetInterceptSetter(
10244 v8::Local<v8::String> name,
10245 v8::Local<v8::Value> value,
10246 const v8::AccessorInfo& info) {
10247 force_set_set_count++;
10248 return v8::Undefined();
10249}
10250
10251TEST(ForceSet) {
10252 force_set_get_count = 0;
10253 force_set_set_count = 0;
10254 pass_on_get = false;
10255
10256 v8::HandleScope scope;
10257 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
10258 v8::Handle<v8::String> access_property = v8::String::New("a");
10259 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
10260 LocalContext context(NULL, templ);
10261 v8::Handle<v8::Object> global = context->Global();
10262
10263 // Ordinary properties
10264 v8::Handle<v8::String> simple_property = v8::String::New("p");
10265 global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
10266 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
10267 // This should fail because the property is read-only
10268 global->Set(simple_property, v8::Int32::New(5));
10269 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
10270 // This should succeed even though the property is read-only
10271 global->ForceSet(simple_property, v8::Int32::New(6));
10272 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
10273
10274 // Accessors
10275 CHECK_EQ(0, force_set_set_count);
10276 CHECK_EQ(0, force_set_get_count);
10277 CHECK_EQ(3, global->Get(access_property)->Int32Value());
10278 // CHECK_EQ the property shouldn't override it, just call the setter
10279 // which in this case does nothing.
10280 global->Set(access_property, v8::Int32::New(7));
10281 CHECK_EQ(3, global->Get(access_property)->Int32Value());
10282 CHECK_EQ(1, force_set_set_count);
10283 CHECK_EQ(2, force_set_get_count);
10284 // Forcing the property to be set should override the accessor without
10285 // calling it
10286 global->ForceSet(access_property, v8::Int32::New(8));
10287 CHECK_EQ(8, global->Get(access_property)->Int32Value());
10288 CHECK_EQ(1, force_set_set_count);
10289 CHECK_EQ(2, force_set_get_count);
10290}
10291
10292TEST(ForceSetWithInterceptor) {
10293 force_set_get_count = 0;
10294 force_set_set_count = 0;
10295 pass_on_get = false;
10296
10297 v8::HandleScope scope;
10298 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
10299 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
10300 LocalContext context(NULL, templ);
10301 v8::Handle<v8::Object> global = context->Global();
10302
10303 v8::Handle<v8::String> some_property = v8::String::New("a");
10304 CHECK_EQ(0, force_set_set_count);
10305 CHECK_EQ(0, force_set_get_count);
10306 CHECK_EQ(3, global->Get(some_property)->Int32Value());
10307 // Setting the property shouldn't override it, just call the setter
10308 // which in this case does nothing.
10309 global->Set(some_property, v8::Int32::New(7));
10310 CHECK_EQ(3, global->Get(some_property)->Int32Value());
10311 CHECK_EQ(1, force_set_set_count);
10312 CHECK_EQ(2, force_set_get_count);
10313 // Getting the property when the interceptor returns an empty handle
10314 // should yield undefined, since the property isn't present on the
10315 // object itself yet.
10316 pass_on_get = true;
10317 CHECK(global->Get(some_property)->IsUndefined());
10318 CHECK_EQ(1, force_set_set_count);
10319 CHECK_EQ(3, force_set_get_count);
10320 // Forcing the property to be set should cause the value to be
10321 // set locally without calling the interceptor.
10322 global->ForceSet(some_property, v8::Int32::New(8));
10323 CHECK_EQ(8, global->Get(some_property)->Int32Value());
10324 CHECK_EQ(1, force_set_set_count);
10325 CHECK_EQ(4, force_set_get_count);
10326 // Reenabling the interceptor should cause it to take precedence over
10327 // the property
10328 pass_on_get = false;
10329 CHECK_EQ(3, global->Get(some_property)->Int32Value());
10330 CHECK_EQ(1, force_set_set_count);
10331 CHECK_EQ(5, force_set_get_count);
10332 // The interceptor should also work for other properties
10333 CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
10334 CHECK_EQ(1, force_set_set_count);
10335 CHECK_EQ(6, force_set_get_count);
10336}
ager@chromium.org1bf0cd02009-05-20 11:34:19 +000010337
10338
ager@chromium.orge2902be2009-06-08 12:21:35 +000010339THREADED_TEST(ForceDelete) {
10340 v8::HandleScope scope;
10341 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
10342 LocalContext context(NULL, templ);
10343 v8::Handle<v8::Object> global = context->Global();
10344
10345 // Ordinary properties
10346 v8::Handle<v8::String> simple_property = v8::String::New("p");
10347 global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
10348 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
10349 // This should fail because the property is dont-delete.
10350 CHECK(!global->Delete(simple_property));
10351 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
10352 // This should succeed even though the property is dont-delete.
10353 CHECK(global->ForceDelete(simple_property));
10354 CHECK(global->Get(simple_property)->IsUndefined());
10355}
10356
10357
10358static int force_delete_interceptor_count = 0;
10359static bool pass_on_delete = false;
10360
10361
10362static v8::Handle<v8::Boolean> ForceDeleteDeleter(
10363 v8::Local<v8::String> name,
10364 const v8::AccessorInfo& info) {
10365 force_delete_interceptor_count++;
10366 if (pass_on_delete) {
10367 return v8::Handle<v8::Boolean>();
10368 } else {
10369 return v8::True();
10370 }
10371}
10372
10373
10374THREADED_TEST(ForceDeleteWithInterceptor) {
10375 force_delete_interceptor_count = 0;
10376 pass_on_delete = false;
10377
10378 v8::HandleScope scope;
10379 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
10380 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
10381 LocalContext context(NULL, templ);
10382 v8::Handle<v8::Object> global = context->Global();
10383
10384 v8::Handle<v8::String> some_property = v8::String::New("a");
10385 global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
10386
10387 // Deleting a property should get intercepted and nothing should
10388 // happen.
10389 CHECK_EQ(0, force_delete_interceptor_count);
10390 CHECK(global->Delete(some_property));
10391 CHECK_EQ(1, force_delete_interceptor_count);
10392 CHECK_EQ(42, global->Get(some_property)->Int32Value());
10393 // Deleting the property when the interceptor returns an empty
10394 // handle should not delete the property since it is DontDelete.
10395 pass_on_delete = true;
10396 CHECK(!global->Delete(some_property));
10397 CHECK_EQ(2, force_delete_interceptor_count);
10398 CHECK_EQ(42, global->Get(some_property)->Int32Value());
10399 // Forcing the property to be deleted should delete the value
10400 // without calling the interceptor.
10401 CHECK(global->ForceDelete(some_property));
10402 CHECK(global->Get(some_property)->IsUndefined());
10403 CHECK_EQ(2, force_delete_interceptor_count);
10404}
10405
10406
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000010407// Make sure that forcing a delete invalidates any IC stubs, so we
10408// don't read the hole value.
10409THREADED_TEST(ForceDeleteIC) {
10410 v8::HandleScope scope;
10411 LocalContext context;
10412 // Create a DontDelete variable on the global object.
10413 CompileRun("this.__proto__ = { foo: 'horse' };"
10414 "var foo = 'fish';"
10415 "function f() { return foo.length; }");
10416 // Initialize the IC for foo in f.
10417 CompileRun("for (var i = 0; i < 4; i++) f();");
10418 // Make sure the value of foo is correct before the deletion.
10419 CHECK_EQ(4, CompileRun("f()")->Int32Value());
10420 // Force the deletion of foo.
10421 CHECK(context->Global()->ForceDelete(v8_str("foo")));
10422 // Make sure the value for foo is read from the prototype, and that
10423 // we don't get in trouble with reading the deleted cell value
10424 // sentinel.
10425 CHECK_EQ(5, CompileRun("f()")->Int32Value());
10426}
10427
10428
ager@chromium.org1bf0cd02009-05-20 11:34:19 +000010429v8::Persistent<Context> calling_context0;
10430v8::Persistent<Context> calling_context1;
10431v8::Persistent<Context> calling_context2;
10432
10433
10434// Check that the call to the callback is initiated in
10435// calling_context2, the directly calling context is calling_context1
10436// and the callback itself is in calling_context0.
10437static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
10438 ApiTestFuzzer::Fuzz();
10439 CHECK(Context::GetCurrent() == calling_context0);
10440 CHECK(Context::GetCalling() == calling_context1);
10441 CHECK(Context::GetEntered() == calling_context2);
10442 return v8::Integer::New(42);
10443}
10444
10445
10446THREADED_TEST(GetCallingContext) {
10447 v8::HandleScope scope;
10448
10449 calling_context0 = Context::New();
10450 calling_context1 = Context::New();
10451 calling_context2 = Context::New();
10452
10453 // Allow cross-domain access.
10454 Local<String> token = v8_str("<security token>");
10455 calling_context0->SetSecurityToken(token);
10456 calling_context1->SetSecurityToken(token);
10457 calling_context2->SetSecurityToken(token);
10458
10459 // Create an object with a C++ callback in context0.
10460 calling_context0->Enter();
10461 Local<v8::FunctionTemplate> callback_templ =
10462 v8::FunctionTemplate::New(GetCallingContextCallback);
10463 calling_context0->Global()->Set(v8_str("callback"),
10464 callback_templ->GetFunction());
10465 calling_context0->Exit();
10466
10467 // Expose context0 in context1 and setup a function that calls the
10468 // callback function.
10469 calling_context1->Enter();
10470 calling_context1->Global()->Set(v8_str("context0"),
10471 calling_context0->Global());
10472 CompileRun("function f() { context0.callback() }");
10473 calling_context1->Exit();
10474
10475 // Expose context1 in context2 and call the callback function in
10476 // context0 indirectly through f in context1.
10477 calling_context2->Enter();
10478 calling_context2->Global()->Set(v8_str("context1"),
10479 calling_context1->Global());
10480 CompileRun("context1.f()");
10481 calling_context2->Exit();
10482
10483 // Dispose the contexts to allow them to be garbage collected.
10484 calling_context0.Dispose();
10485 calling_context1.Dispose();
10486 calling_context2.Dispose();
10487 calling_context0.Clear();
10488 calling_context1.Clear();
10489 calling_context2.Clear();
10490}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010491
10492
10493// Check that a variable declaration with no explicit initialization
10494// value does not shadow an existing property in the prototype chain.
10495//
10496// This is consistent with Firefox and Safari.
10497//
10498// See http://crbug.com/12548.
10499THREADED_TEST(InitGlobalVarInProtoChain) {
10500 v8::HandleScope scope;
10501 LocalContext context;
10502 // Introduce a variable in the prototype chain.
10503 CompileRun("__proto__.x = 42");
10504 v8::Handle<v8::Value> result = CompileRun("var x; x");
10505 CHECK(!result->IsUndefined());
10506 CHECK_EQ(42, result->Int32Value());
10507}
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000010508
10509
10510// Regression test for issue 398.
10511// If a function is added to an object, creating a constant function
10512// field, and the result is cloned, replacing the constant function on the
10513// original should not affect the clone.
10514// See http://code.google.com/p/v8/issues/detail?id=398
10515THREADED_TEST(ReplaceConstantFunction) {
10516 v8::HandleScope scope;
10517 LocalContext context;
10518 v8::Handle<v8::Object> obj = v8::Object::New();
10519 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
10520 v8::Handle<v8::String> foo_string = v8::String::New("foo");
10521 obj->Set(foo_string, func_templ->GetFunction());
10522 v8::Handle<v8::Object> obj_clone = obj->Clone();
10523 obj_clone->Set(foo_string, v8::String::New("Hello"));
10524 CHECK(!obj->Get(foo_string)->IsUndefined());
10525}
kasperl@chromium.orge959c182009-07-27 08:59:04 +000010526
10527
10528// Regression test for http://crbug.com/16276.
10529THREADED_TEST(Regress16276) {
10530 v8::HandleScope scope;
10531 LocalContext context;
10532 // Force the IC in f to be a dictionary load IC.
10533 CompileRun("function f(obj) { return obj.x; }\n"
10534 "var obj = { x: { foo: 42 }, y: 87 };\n"
10535 "var x = obj.x;\n"
10536 "delete obj.y;\n"
10537 "for (var i = 0; i < 5; i++) f(obj);");
10538 // Detach the global object to make 'this' refer directly to the
10539 // global object (not the proxy), and make sure that the dictionary
10540 // load IC doesn't mess up loading directly from the global object.
10541 context->DetachGlobal();
10542 CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
10543}
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010544
10545
10546THREADED_TEST(PixelArray) {
10547 v8::HandleScope scope;
10548 LocalContext context;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010549 const int kElementCount = 260;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010550 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
10551 i::Handle<i::PixelArray> pixels = i::Factory::NewPixelArray(kElementCount,
10552 pixel_data);
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010553 i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010554 for (int i = 0; i < kElementCount; i++) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010555 pixels->set(i, i % 256);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010556 }
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010557 i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010558 for (int i = 0; i < kElementCount; i++) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010559 CHECK_EQ(i % 256, pixels->get(i));
10560 CHECK_EQ(i % 256, pixel_data[i]);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010561 }
10562
10563 v8::Handle<v8::Object> obj = v8::Object::New();
10564 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
10565 // Set the elements to be the pixels.
10566 // jsobj->set_elements(*pixels);
10567 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010568 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010569 obj->Set(v8_str("field"), v8::Int32::New(1503));
10570 context->Global()->Set(v8_str("pixels"), obj);
10571 v8::Handle<v8::Value> result = CompileRun("pixels.field");
10572 CHECK_EQ(1503, result->Int32Value());
10573 result = CompileRun("pixels[1]");
10574 CHECK_EQ(1, result->Int32Value());
sgjesse@chromium.org9eceac12009-09-30 07:18:41 +000010575
10576 result = CompileRun("var sum = 0;"
10577 "for (var i = 0; i < 8; i++) {"
10578 " sum += pixels[i] = pixels[i] = -i;"
10579 "}"
10580 "sum;");
10581 CHECK_EQ(-28, result->Int32Value());
10582
10583 result = CompileRun("var sum = 0;"
10584 "for (var i = 0; i < 8; i++) {"
10585 " sum += pixels[i] = pixels[i] = 0;"
10586 "}"
10587 "sum;");
10588 CHECK_EQ(0, result->Int32Value());
10589
10590 result = CompileRun("var sum = 0;"
10591 "for (var i = 0; i < 8; i++) {"
10592 " sum += pixels[i] = pixels[i] = 255;"
10593 "}"
10594 "sum;");
10595 CHECK_EQ(8 * 255, result->Int32Value());
10596
10597 result = CompileRun("var sum = 0;"
10598 "for (var i = 0; i < 8; i++) {"
10599 " sum += pixels[i] = pixels[i] = 256 + i;"
10600 "}"
10601 "sum;");
10602 CHECK_EQ(2076, result->Int32Value());
10603
10604 result = CompileRun("var sum = 0;"
10605 "for (var i = 0; i < 8; i++) {"
10606 " sum += pixels[i] = pixels[i] = i;"
10607 "}"
10608 "sum;");
10609 CHECK_EQ(28, result->Int32Value());
10610
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010611 result = CompileRun("var sum = 0;"
10612 "for (var i = 0; i < 8; i++) {"
10613 " sum += pixels[i];"
10614 "}"
10615 "sum;");
10616 CHECK_EQ(28, result->Int32Value());
10617
10618 i::Handle<i::Smi> value(i::Smi::FromInt(2));
10619 i::SetElement(jsobj, 1, value);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010620 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010621 *value.location() = i::Smi::FromInt(256);
10622 i::SetElement(jsobj, 1, value);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010623 CHECK_EQ(255,
10624 i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010625 *value.location() = i::Smi::FromInt(-1);
10626 i::SetElement(jsobj, 1, value);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010627 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010628
10629 result = CompileRun("for (var i = 0; i < 8; i++) {"
10630 " pixels[i] = (i * 65) - 109;"
10631 "}"
10632 "pixels[1] + pixels[6];");
10633 CHECK_EQ(255, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010634 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
10635 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
10636 CHECK_EQ(21,
10637 i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
10638 CHECK_EQ(86,
10639 i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
10640 CHECK_EQ(151,
10641 i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
10642 CHECK_EQ(216,
10643 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
10644 CHECK_EQ(255,
10645 i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
10646 CHECK_EQ(255,
10647 i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010648 result = CompileRun("var sum = 0;"
10649 "for (var i = 0; i < 8; i++) {"
10650 " sum += pixels[i];"
10651 "}"
10652 "sum;");
10653 CHECK_EQ(984, result->Int32Value());
10654
10655 result = CompileRun("for (var i = 0; i < 8; i++) {"
10656 " pixels[i] = (i * 1.1);"
10657 "}"
10658 "pixels[1] + pixels[6];");
10659 CHECK_EQ(8, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010660 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
10661 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
10662 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
10663 CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
10664 CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
10665 CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
10666 CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
10667 CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010668
10669 result = CompileRun("for (var i = 0; i < 8; i++) {"
10670 " pixels[7] = undefined;"
10671 "}"
10672 "pixels[7];");
10673 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010674 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010675
10676 result = CompileRun("for (var i = 0; i < 8; i++) {"
10677 " pixels[6] = '2.3';"
10678 "}"
10679 "pixels[6];");
10680 CHECK_EQ(2, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010681 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010682
10683 result = CompileRun("for (var i = 0; i < 8; i++) {"
10684 " pixels[5] = NaN;"
10685 "}"
10686 "pixels[5];");
10687 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010688 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010689
10690 result = CompileRun("for (var i = 0; i < 8; i++) {"
10691 " pixels[8] = Infinity;"
10692 "}"
10693 "pixels[8];");
10694 CHECK_EQ(255, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010695 CHECK_EQ(255,
10696 i::Smi::cast(jsobj->GetElement(8)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010697
10698 result = CompileRun("for (var i = 0; i < 8; i++) {"
10699 " pixels[9] = -Infinity;"
10700 "}"
10701 "pixels[9];");
10702 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010703 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010704
10705 result = CompileRun("pixels[3] = 33;"
10706 "delete pixels[3];"
10707 "pixels[3];");
10708 CHECK_EQ(33, result->Int32Value());
10709
10710 result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
10711 "pixels[2] = 12; pixels[3] = 13;"
10712 "pixels.__defineGetter__('2',"
10713 "function() { return 120; });"
10714 "pixels[2];");
10715 CHECK_EQ(12, result->Int32Value());
10716
10717 result = CompileRun("var js_array = new Array(40);"
10718 "js_array[0] = 77;"
10719 "js_array;");
10720 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
10721
10722 result = CompileRun("pixels[1] = 23;"
10723 "pixels.__proto__ = [];"
10724 "js_array.__proto__ = pixels;"
10725 "js_array.concat(pixels);");
10726 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
10727 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
10728
sgjesse@chromium.org9eceac12009-09-30 07:18:41 +000010729 result = CompileRun("pixels[1] = 23;");
10730 CHECK_EQ(23, result->Int32Value());
10731
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010732 // Test for index greater than 255. Regression test for:
10733 // http://code.google.com/p/chromium/issues/detail?id=26337.
10734 result = CompileRun("pixels[256] = 255;");
10735 CHECK_EQ(255, result->Int32Value());
10736 result = CompileRun("var i = 0;"
10737 "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
10738 "i");
10739 CHECK_EQ(255, result->Int32Value());
10740
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010741 // Make sure that pixel array ICs recognize when a non-pixel array
10742 // is passed to it.
10743 result = CompileRun("function pa_load(p) {"
10744 " var sum = 0;"
10745 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
10746 " return sum;"
10747 "}"
10748 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
10749 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
10750 "just_ints = new Object();"
10751 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
10752 "for (var i = 0; i < 10; ++i) {"
10753 " result = pa_load(just_ints);"
10754 "}"
10755 "result");
10756 CHECK_EQ(32640, result->Int32Value());
10757
10758 // Make sure that pixel array ICs recognize out-of-bound accesses.
10759 result = CompileRun("function pa_load(p, start) {"
10760 " var sum = 0;"
10761 " for (var j = start; j < 256; j++) { sum += p[j]; }"
10762 " return sum;"
10763 "}"
10764 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
10765 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
10766 "for (var i = 0; i < 10; ++i) {"
10767 " result = pa_load(pixels,-10);"
10768 "}"
10769 "result");
10770 CHECK_EQ(0, result->Int32Value());
10771
10772 // Make sure that generic ICs properly handles a pixel array.
10773 result = CompileRun("function pa_load(p) {"
10774 " var sum = 0;"
10775 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
10776 " return sum;"
10777 "}"
10778 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
10779 "just_ints = new Object();"
10780 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
10781 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
10782 "for (var i = 0; i < 10; ++i) {"
10783 " result = pa_load(pixels);"
10784 "}"
10785 "result");
10786 CHECK_EQ(32640, result->Int32Value());
10787
10788 // Make sure that generic load ICs recognize out-of-bound accesses in
10789 // pixel arrays.
10790 result = CompileRun("function pa_load(p, start) {"
10791 " var sum = 0;"
10792 " for (var j = start; j < 256; j++) { sum += p[j]; }"
10793 " return sum;"
10794 "}"
10795 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
10796 "just_ints = new Object();"
10797 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
10798 "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
10799 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
10800 "for (var i = 0; i < 10; ++i) {"
10801 " result = pa_load(pixels,-10);"
10802 "}"
10803 "result");
10804 CHECK_EQ(0, result->Int32Value());
10805
10806 // Make sure that generic ICs properly handles other types than pixel
10807 // arrays (that the inlined fast pixel array test leaves the right information
10808 // in the right registers).
10809 result = CompileRun("function pa_load(p) {"
10810 " var sum = 0;"
10811 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
10812 " return sum;"
10813 "}"
10814 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
10815 "just_ints = new Object();"
10816 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
10817 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
10818 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
10819 "sparse_array = new Object();"
10820 "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
10821 "sparse_array[1000000] = 3;"
10822 "for (var i = 0; i < 10; ++i) {"
10823 " result = pa_load(sparse_array);"
10824 "}"
10825 "result");
10826 CHECK_EQ(32640, result->Int32Value());
10827
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +000010828 // Make sure that pixel array store ICs clamp values correctly.
10829 result = CompileRun("function pa_store(p) {"
10830 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
10831 "}"
10832 "pa_store(pixels);"
10833 "var sum = 0;"
10834 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
10835 "sum");
10836 CHECK_EQ(48896, result->Int32Value());
10837
10838 // Make sure that pixel array stores correctly handle accesses outside
10839 // of the pixel array..
10840 result = CompileRun("function pa_store(p,start) {"
10841 " for (var j = 0; j < 256; j++) {"
10842 " p[j+start] = j * 2;"
10843 " }"
10844 "}"
10845 "pa_store(pixels,0);"
10846 "pa_store(pixels,-128);"
10847 "var sum = 0;"
10848 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
10849 "sum");
10850 CHECK_EQ(65280, result->Int32Value());
10851
10852 // Make sure that the generic store stub correctly handle accesses outside
10853 // of the pixel array..
10854 result = CompileRun("function pa_store(p,start) {"
10855 " for (var j = 0; j < 256; j++) {"
10856 " p[j+start] = j * 2;"
10857 " }"
10858 "}"
10859 "pa_store(pixels,0);"
10860 "just_ints = new Object();"
10861 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
10862 "pa_store(just_ints, 0);"
10863 "pa_store(pixels,-128);"
10864 "var sum = 0;"
10865 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
10866 "sum");
10867 CHECK_EQ(65280, result->Int32Value());
10868
10869 // Make sure that the generic keyed store stub clamps pixel array values
10870 // correctly.
10871 result = CompileRun("function pa_store(p) {"
10872 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
10873 "}"
10874 "pa_store(pixels);"
10875 "just_ints = new Object();"
10876 "pa_store(just_ints);"
10877 "pa_store(pixels);"
10878 "var sum = 0;"
10879 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
10880 "sum");
10881 CHECK_EQ(48896, result->Int32Value());
10882
10883 // Make sure that pixel array loads are optimized by crankshaft.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010884 result = CompileRun("function pa_load(p) {"
10885 " var sum = 0;"
10886 " for (var i=0; i<256; ++i) {"
10887 " sum += p[i];"
10888 " }"
10889 " return sum; "
10890 "}"
10891 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
10892 "for (var i = 0; i < 10000; ++i) {"
10893 " result = pa_load(pixels);"
10894 "}"
10895 "result");
10896 CHECK_EQ(32640, result->Int32Value());
10897
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000010898 // Make sure that pixel array stores are optimized by crankshaft.
10899 result = CompileRun("function pa_init(p) {"
10900 "for (var i = 0; i < 256; ++i) { p[i] = i; }"
10901 "}"
10902 "function pa_load(p) {"
10903 " var sum = 0;"
10904 " for (var i=0; i<256; ++i) {"
10905 " sum += p[i];"
10906 " }"
10907 " return sum; "
10908 "}"
10909 "for (var i = 0; i < 100000; ++i) {"
10910 " pa_init(pixels);"
10911 "}"
10912 "result = pa_load(pixels);"
10913 "result");
10914 CHECK_EQ(32640, result->Int32Value());
10915
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010916 free(pixel_data);
10917}
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000010918
ager@chromium.org96c75b52009-08-26 09:13:16 +000010919
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000010920THREADED_TEST(PixelArrayInfo) {
10921 v8::HandleScope scope;
10922 LocalContext context;
10923 for (int size = 0; size < 100; size += 10) {
10924 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
10925 v8::Handle<v8::Object> obj = v8::Object::New();
10926 obj->SetIndexedPropertiesToPixelData(pixel_data, size);
10927 CHECK(obj->HasIndexedPropertiesInPixelData());
10928 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
10929 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
10930 free(pixel_data);
10931 }
10932}
10933
10934
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000010935static v8::Handle<Value> NotHandledIndexedPropertyGetter(
10936 uint32_t index,
10937 const AccessorInfo& info) {
10938 ApiTestFuzzer::Fuzz();
10939 return v8::Handle<Value>();
10940}
10941
10942
10943static v8::Handle<Value> NotHandledIndexedPropertySetter(
10944 uint32_t index,
10945 Local<Value> value,
10946 const AccessorInfo& info) {
10947 ApiTestFuzzer::Fuzz();
10948 return v8::Handle<Value>();
10949}
10950
10951
10952THREADED_TEST(PixelArrayWithInterceptor) {
10953 v8::HandleScope scope;
10954 LocalContext context;
10955 const int kElementCount = 260;
10956 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
10957 i::Handle<i::PixelArray> pixels =
10958 i::Factory::NewPixelArray(kElementCount, pixel_data);
10959 for (int i = 0; i < kElementCount; i++) {
10960 pixels->set(i, i % 256);
10961 }
10962 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
10963 templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
10964 NotHandledIndexedPropertySetter);
10965 v8::Handle<v8::Object> obj = templ->NewInstance();
10966 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
10967 context->Global()->Set(v8_str("pixels"), obj);
10968 v8::Handle<v8::Value> result = CompileRun("pixels[1]");
10969 CHECK_EQ(1, result->Int32Value());
10970 result = CompileRun("var sum = 0;"
10971 "for (var i = 0; i < 8; i++) {"
10972 " sum += pixels[i] = pixels[i] = -i;"
10973 "}"
10974 "sum;");
10975 CHECK_EQ(-28, result->Int32Value());
10976 result = CompileRun("pixels.hasOwnProperty('1')");
10977 CHECK(result->BooleanValue());
10978 free(pixel_data);
10979}
10980
10981
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000010982static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
10983 switch (array_type) {
10984 case v8::kExternalByteArray:
10985 case v8::kExternalUnsignedByteArray:
10986 return 1;
10987 break;
10988 case v8::kExternalShortArray:
10989 case v8::kExternalUnsignedShortArray:
10990 return 2;
10991 break;
10992 case v8::kExternalIntArray:
10993 case v8::kExternalUnsignedIntArray:
10994 case v8::kExternalFloatArray:
10995 return 4;
10996 break;
10997 default:
10998 UNREACHABLE();
10999 return -1;
11000 }
11001 UNREACHABLE();
11002 return -1;
11003}
11004
11005
ager@chromium.org3811b432009-10-28 14:53:37 +000011006template <class ExternalArrayClass, class ElementType>
11007static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
11008 int64_t low,
11009 int64_t high) {
11010 v8::HandleScope scope;
11011 LocalContext context;
11012 const int kElementCount = 40;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000011013 int element_size = ExternalArrayElementSize(array_type);
ager@chromium.org3811b432009-10-28 14:53:37 +000011014 ElementType* array_data =
11015 static_cast<ElementType*>(malloc(kElementCount * element_size));
11016 i::Handle<ExternalArrayClass> array =
11017 i::Handle<ExternalArrayClass>::cast(
11018 i::Factory::NewExternalArray(kElementCount, array_type, array_data));
11019 i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
11020 for (int i = 0; i < kElementCount; i++) {
11021 array->set(i, static_cast<ElementType>(i));
11022 }
11023 i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
11024 for (int i = 0; i < kElementCount; i++) {
11025 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array->get(i)));
11026 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
11027 }
11028
11029 v8::Handle<v8::Object> obj = v8::Object::New();
11030 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
11031 // Set the elements to be the external array.
11032 obj->SetIndexedPropertiesToExternalArrayData(array_data,
11033 array_type,
11034 kElementCount);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011035 CHECK_EQ(
11036 1, static_cast<int>(jsobj->GetElement(1)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000011037 obj->Set(v8_str("field"), v8::Int32::New(1503));
11038 context->Global()->Set(v8_str("ext_array"), obj);
11039 v8::Handle<v8::Value> result = CompileRun("ext_array.field");
11040 CHECK_EQ(1503, result->Int32Value());
11041 result = CompileRun("ext_array[1]");
11042 CHECK_EQ(1, result->Int32Value());
11043
11044 // Check pass through of assigned smis
11045 result = CompileRun("var sum = 0;"
11046 "for (var i = 0; i < 8; i++) {"
11047 " sum += ext_array[i] = ext_array[i] = -i;"
11048 "}"
11049 "sum;");
11050 CHECK_EQ(-28, result->Int32Value());
11051
11052 // Check assigned smis
11053 result = CompileRun("for (var i = 0; i < 8; i++) {"
11054 " ext_array[i] = i;"
11055 "}"
11056 "var sum = 0;"
11057 "for (var i = 0; i < 8; i++) {"
11058 " sum += ext_array[i];"
11059 "}"
11060 "sum;");
11061 CHECK_EQ(28, result->Int32Value());
11062
11063 // Check assigned smis in reverse order
11064 result = CompileRun("for (var i = 8; --i >= 0; ) {"
11065 " ext_array[i] = i;"
11066 "}"
11067 "var sum = 0;"
11068 "for (var i = 0; i < 8; i++) {"
11069 " sum += ext_array[i];"
11070 "}"
11071 "sum;");
11072 CHECK_EQ(28, result->Int32Value());
11073
11074 // Check pass through of assigned HeapNumbers
11075 result = CompileRun("var sum = 0;"
11076 "for (var i = 0; i < 16; i+=2) {"
11077 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
11078 "}"
11079 "sum;");
11080 CHECK_EQ(-28, result->Int32Value());
11081
11082 // Check assigned HeapNumbers
11083 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
11084 " ext_array[i] = (i * 0.5);"
11085 "}"
11086 "var sum = 0;"
11087 "for (var i = 0; i < 16; i+=2) {"
11088 " sum += ext_array[i];"
11089 "}"
11090 "sum;");
11091 CHECK_EQ(28, result->Int32Value());
11092
11093 // Check assigned HeapNumbers in reverse order
11094 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
11095 " ext_array[i] = (i * 0.5);"
11096 "}"
11097 "var sum = 0;"
11098 "for (var i = 0; i < 16; i+=2) {"
11099 " sum += ext_array[i];"
11100 "}"
11101 "sum;");
11102 CHECK_EQ(28, result->Int32Value());
11103
11104 i::ScopedVector<char> test_buf(1024);
11105
11106 // Check legal boundary conditions.
11107 // The repeated loads and stores ensure the ICs are exercised.
11108 const char* boundary_program =
11109 "var res = 0;"
11110 "for (var i = 0; i < 16; i++) {"
11111 " ext_array[i] = %lld;"
11112 " if (i > 8) {"
11113 " res = ext_array[i];"
11114 " }"
11115 "}"
11116 "res;";
11117 i::OS::SNPrintF(test_buf,
11118 boundary_program,
11119 low);
11120 result = CompileRun(test_buf.start());
11121 CHECK_EQ(low, result->IntegerValue());
11122
11123 i::OS::SNPrintF(test_buf,
11124 boundary_program,
11125 high);
11126 result = CompileRun(test_buf.start());
11127 CHECK_EQ(high, result->IntegerValue());
11128
11129 // Check misprediction of type in IC.
11130 result = CompileRun("var tmp_array = ext_array;"
11131 "var sum = 0;"
11132 "for (var i = 0; i < 8; i++) {"
11133 " tmp_array[i] = i;"
11134 " sum += tmp_array[i];"
11135 " if (i == 4) {"
11136 " tmp_array = {};"
11137 " }"
11138 "}"
11139 "sum;");
11140 i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
11141 CHECK_EQ(28, result->Int32Value());
11142
11143 // Make sure out-of-range loads do not throw.
11144 i::OS::SNPrintF(test_buf,
11145 "var caught_exception = false;"
11146 "try {"
11147 " ext_array[%d];"
11148 "} catch (e) {"
11149 " caught_exception = true;"
11150 "}"
11151 "caught_exception;",
11152 kElementCount);
11153 result = CompileRun(test_buf.start());
11154 CHECK_EQ(false, result->BooleanValue());
11155
11156 // Make sure out-of-range stores do not throw.
11157 i::OS::SNPrintF(test_buf,
11158 "var caught_exception = false;"
11159 "try {"
11160 " ext_array[%d] = 1;"
11161 "} catch (e) {"
11162 " caught_exception = true;"
11163 "}"
11164 "caught_exception;",
11165 kElementCount);
11166 result = CompileRun(test_buf.start());
11167 CHECK_EQ(false, result->BooleanValue());
11168
11169 // Check other boundary conditions, values and operations.
11170 result = CompileRun("for (var i = 0; i < 8; i++) {"
11171 " ext_array[7] = undefined;"
11172 "}"
11173 "ext_array[7];");
11174 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011175 CHECK_EQ(
11176 0, static_cast<int>(jsobj->GetElement(7)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000011177
11178 result = CompileRun("for (var i = 0; i < 8; i++) {"
11179 " ext_array[6] = '2.3';"
11180 "}"
11181 "ext_array[6];");
11182 CHECK_EQ(2, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011183 CHECK_EQ(
11184 2, static_cast<int>(jsobj->GetElement(6)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000011185
11186 if (array_type != v8::kExternalFloatArray) {
11187 // Though the specification doesn't state it, be explicit about
11188 // converting NaNs and +/-Infinity to zero.
11189 result = CompileRun("for (var i = 0; i < 8; i++) {"
11190 " ext_array[i] = 5;"
11191 "}"
11192 "for (var i = 0; i < 8; i++) {"
11193 " ext_array[i] = NaN;"
11194 "}"
11195 "ext_array[5];");
11196 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011197 CHECK_EQ(0,
11198 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
ager@chromium.org3811b432009-10-28 14:53:37 +000011199
11200 result = CompileRun("for (var i = 0; i < 8; i++) {"
11201 " ext_array[i] = 5;"
11202 "}"
11203 "for (var i = 0; i < 8; i++) {"
11204 " ext_array[i] = Infinity;"
11205 "}"
11206 "ext_array[5];");
11207 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011208 CHECK_EQ(0,
11209 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
ager@chromium.org3811b432009-10-28 14:53:37 +000011210
11211 result = CompileRun("for (var i = 0; i < 8; i++) {"
11212 " ext_array[i] = 5;"
11213 "}"
11214 "for (var i = 0; i < 8; i++) {"
11215 " ext_array[i] = -Infinity;"
11216 "}"
11217 "ext_array[5];");
11218 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011219 CHECK_EQ(0,
11220 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000011221
11222 // Check truncation behavior of integral arrays.
11223 const char* unsigned_data =
11224 "var source_data = [0.6, 10.6];"
11225 "var expected_results = [0, 10];";
11226 const char* signed_data =
11227 "var source_data = [0.6, 10.6, -0.6, -10.6];"
11228 "var expected_results = [0, 10, 0, -10];";
11229 bool is_unsigned =
11230 (array_type == v8::kExternalUnsignedByteArray ||
11231 array_type == v8::kExternalUnsignedShortArray ||
11232 array_type == v8::kExternalUnsignedIntArray);
11233
11234 i::OS::SNPrintF(test_buf,
11235 "%s"
11236 "var all_passed = true;"
11237 "for (var i = 0; i < source_data.length; i++) {"
11238 " for (var j = 0; j < 8; j++) {"
11239 " ext_array[j] = source_data[i];"
11240 " }"
11241 " all_passed = all_passed &&"
11242 " (ext_array[5] == expected_results[i]);"
11243 "}"
11244 "all_passed;",
11245 (is_unsigned ? unsigned_data : signed_data));
11246 result = CompileRun(test_buf.start());
11247 CHECK_EQ(true, result->BooleanValue());
ager@chromium.org3811b432009-10-28 14:53:37 +000011248 }
11249
11250 result = CompileRun("ext_array[3] = 33;"
11251 "delete ext_array[3];"
11252 "ext_array[3];");
11253 CHECK_EQ(33, result->Int32Value());
11254
11255 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
11256 "ext_array[2] = 12; ext_array[3] = 13;"
11257 "ext_array.__defineGetter__('2',"
11258 "function() { return 120; });"
11259 "ext_array[2];");
11260 CHECK_EQ(12, result->Int32Value());
11261
11262 result = CompileRun("var js_array = new Array(40);"
11263 "js_array[0] = 77;"
11264 "js_array;");
11265 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
11266
11267 result = CompileRun("ext_array[1] = 23;"
11268 "ext_array.__proto__ = [];"
11269 "js_array.__proto__ = ext_array;"
11270 "js_array.concat(ext_array);");
11271 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
11272 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
11273
11274 result = CompileRun("ext_array[1] = 23;");
11275 CHECK_EQ(23, result->Int32Value());
11276
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011277 // Test more complex manipulations which cause eax to contain values
11278 // that won't be completely overwritten by loads from the arrays.
11279 // This catches bugs in the instructions used for the KeyedLoadIC
11280 // for byte and word types.
11281 {
11282 const int kXSize = 300;
11283 const int kYSize = 300;
11284 const int kLargeElementCount = kXSize * kYSize * 4;
11285 ElementType* large_array_data =
11286 static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
11287 i::Handle<ExternalArrayClass> large_array =
11288 i::Handle<ExternalArrayClass>::cast(
11289 i::Factory::NewExternalArray(kLargeElementCount,
11290 array_type,
11291 array_data));
11292 v8::Handle<v8::Object> large_obj = v8::Object::New();
11293 // Set the elements to be the external array.
11294 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
11295 array_type,
11296 kLargeElementCount);
11297 context->Global()->Set(v8_str("large_array"), large_obj);
11298 // Initialize contents of a few rows.
11299 for (int x = 0; x < 300; x++) {
11300 int row = 0;
11301 int offset = row * 300 * 4;
11302 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
11303 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
11304 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
11305 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
11306 row = 150;
11307 offset = row * 300 * 4;
11308 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
11309 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
11310 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
11311 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
11312 row = 298;
11313 offset = row * 300 * 4;
11314 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
11315 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
11316 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
11317 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
11318 }
11319 // The goal of the code below is to make "offset" large enough
11320 // that the computation of the index (which goes into eax) has
11321 // high bits set which will not be overwritten by a byte or short
11322 // load.
11323 result = CompileRun("var failed = false;"
11324 "var offset = 0;"
11325 "for (var i = 0; i < 300; i++) {"
11326 " if (large_array[4 * i] != 127 ||"
11327 " large_array[4 * i + 1] != 0 ||"
11328 " large_array[4 * i + 2] != 0 ||"
11329 " large_array[4 * i + 3] != 127) {"
11330 " failed = true;"
11331 " }"
11332 "}"
11333 "offset = 150 * 300 * 4;"
11334 "for (var i = 0; i < 300; i++) {"
11335 " if (large_array[offset + 4 * i] != 127 ||"
11336 " large_array[offset + 4 * i + 1] != 0 ||"
11337 " large_array[offset + 4 * i + 2] != 0 ||"
11338 " large_array[offset + 4 * i + 3] != 127) {"
11339 " failed = true;"
11340 " }"
11341 "}"
11342 "offset = 298 * 300 * 4;"
11343 "for (var i = 0; i < 300; i++) {"
11344 " if (large_array[offset + 4 * i] != 127 ||"
11345 " large_array[offset + 4 * i + 1] != 0 ||"
11346 " large_array[offset + 4 * i + 2] != 0 ||"
11347 " large_array[offset + 4 * i + 3] != 127) {"
11348 " failed = true;"
11349 " }"
11350 "}"
11351 "!failed;");
11352 CHECK_EQ(true, result->BooleanValue());
11353 free(large_array_data);
11354 }
11355
ager@chromium.org3811b432009-10-28 14:53:37 +000011356 free(array_data);
11357}
11358
11359
11360THREADED_TEST(ExternalByteArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011361 ExternalArrayTestHelper<i::ExternalByteArray, int8_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000011362 v8::kExternalByteArray,
11363 -128,
11364 127);
11365}
11366
11367
11368THREADED_TEST(ExternalUnsignedByteArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011369 ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000011370 v8::kExternalUnsignedByteArray,
11371 0,
11372 255);
11373}
11374
11375
11376THREADED_TEST(ExternalShortArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011377 ExternalArrayTestHelper<i::ExternalShortArray, int16_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000011378 v8::kExternalShortArray,
11379 -32768,
11380 32767);
11381}
11382
11383
11384THREADED_TEST(ExternalUnsignedShortArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011385 ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000011386 v8::kExternalUnsignedShortArray,
11387 0,
11388 65535);
11389}
11390
11391
11392THREADED_TEST(ExternalIntArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011393 ExternalArrayTestHelper<i::ExternalIntArray, int32_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000011394 v8::kExternalIntArray,
11395 INT_MIN, // -2147483648
11396 INT_MAX); // 2147483647
11397}
11398
11399
11400THREADED_TEST(ExternalUnsignedIntArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011401 ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000011402 v8::kExternalUnsignedIntArray,
11403 0,
11404 UINT_MAX); // 4294967295
11405}
11406
11407
11408THREADED_TEST(ExternalFloatArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011409 ExternalArrayTestHelper<i::ExternalFloatArray, float>(
ager@chromium.org3811b432009-10-28 14:53:37 +000011410 v8::kExternalFloatArray,
11411 -500,
11412 500);
11413}
11414
11415
11416THREADED_TEST(ExternalArrays) {
11417 TestExternalByteArray();
11418 TestExternalUnsignedByteArray();
11419 TestExternalShortArray();
11420 TestExternalUnsignedShortArray();
11421 TestExternalIntArray();
11422 TestExternalUnsignedIntArray();
11423 TestExternalFloatArray();
11424}
11425
11426
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000011427void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
11428 v8::HandleScope scope;
11429 LocalContext context;
11430 for (int size = 0; size < 100; size += 10) {
11431 int element_size = ExternalArrayElementSize(array_type);
11432 void* external_data = malloc(size * element_size);
11433 v8::Handle<v8::Object> obj = v8::Object::New();
11434 obj->SetIndexedPropertiesToExternalArrayData(
11435 external_data, array_type, size);
11436 CHECK(obj->HasIndexedPropertiesInExternalArrayData());
11437 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
11438 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
11439 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
11440 free(external_data);
11441 }
11442}
11443
11444
11445THREADED_TEST(ExternalArrayInfo) {
11446 ExternalArrayInfoTestHelper(v8::kExternalByteArray);
11447 ExternalArrayInfoTestHelper(v8::kExternalUnsignedByteArray);
11448 ExternalArrayInfoTestHelper(v8::kExternalShortArray);
11449 ExternalArrayInfoTestHelper(v8::kExternalUnsignedShortArray);
11450 ExternalArrayInfoTestHelper(v8::kExternalIntArray);
11451 ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray);
11452 ExternalArrayInfoTestHelper(v8::kExternalFloatArray);
11453}
11454
11455
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000011456THREADED_TEST(ScriptContextDependence) {
11457 v8::HandleScope scope;
11458 LocalContext c1;
11459 const char *source = "foo";
11460 v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
11461 v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
11462 c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
11463 CHECK_EQ(dep->Run()->Int32Value(), 100);
11464 CHECK_EQ(indep->Run()->Int32Value(), 100);
11465 LocalContext c2;
11466 c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
11467 CHECK_EQ(dep->Run()->Int32Value(), 100);
11468 CHECK_EQ(indep->Run()->Int32Value(), 101);
11469}
11470
ager@chromium.org96c75b52009-08-26 09:13:16 +000011471
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000011472THREADED_TEST(StackTrace) {
11473 v8::HandleScope scope;
11474 LocalContext context;
11475 v8::TryCatch try_catch;
11476 const char *source = "function foo() { FAIL.FAIL; }; foo();";
11477 v8::Handle<v8::String> src = v8::String::New(source);
11478 v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
11479 v8::Script::New(src, origin)->Run();
11480 CHECK(try_catch.HasCaught());
11481 v8::String::Utf8Value stack(try_catch.StackTrace());
11482 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
11483}
ager@chromium.org96c75b52009-08-26 09:13:16 +000011484
11485
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000011486// Checks that a StackFrame has certain expected values.
11487void checkStackFrame(const char* expected_script_name,
11488 const char* expected_func_name, int expected_line_number,
11489 int expected_column, bool is_eval, bool is_constructor,
11490 v8::Handle<v8::StackFrame> frame) {
11491 v8::HandleScope scope;
11492 v8::String::Utf8Value func_name(frame->GetFunctionName());
11493 v8::String::Utf8Value script_name(frame->GetScriptName());
11494 if (*script_name == NULL) {
11495 // The situation where there is no associated script, like for evals.
11496 CHECK(expected_script_name == NULL);
11497 } else {
11498 CHECK(strstr(*script_name, expected_script_name) != NULL);
11499 }
11500 CHECK(strstr(*func_name, expected_func_name) != NULL);
11501 CHECK_EQ(expected_line_number, frame->GetLineNumber());
11502 CHECK_EQ(expected_column, frame->GetColumn());
11503 CHECK_EQ(is_eval, frame->IsEval());
11504 CHECK_EQ(is_constructor, frame->IsConstructor());
11505}
11506
11507
11508v8::Handle<Value> AnalyzeStackInNativeCode(const v8::Arguments& args) {
11509 v8::HandleScope scope;
11510 const char* origin = "capture-stack-trace-test";
11511 const int kOverviewTest = 1;
11512 const int kDetailedTest = 2;
11513
11514 ASSERT(args.Length() == 1);
11515
11516 int testGroup = args[0]->Int32Value();
11517 if (testGroup == kOverviewTest) {
11518 v8::Handle<v8::StackTrace> stackTrace =
11519 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
11520 CHECK_EQ(4, stackTrace->GetFrameCount());
11521 checkStackFrame(origin, "bar", 2, 10, false, false,
11522 stackTrace->GetFrame(0));
11523 checkStackFrame(origin, "foo", 6, 3, false, false,
11524 stackTrace->GetFrame(1));
11525 checkStackFrame(NULL, "", 1, 1, false, false,
11526 stackTrace->GetFrame(2));
11527 // The last frame is an anonymous function that has the initial call.
11528 checkStackFrame(origin, "", 8, 7, false, false,
11529 stackTrace->GetFrame(3));
11530
11531 CHECK(stackTrace->AsArray()->IsArray());
11532 } else if (testGroup == kDetailedTest) {
11533 v8::Handle<v8::StackTrace> stackTrace =
11534 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
11535 CHECK_EQ(4, stackTrace->GetFrameCount());
11536 checkStackFrame(origin, "bat", 4, 22, false, false,
11537 stackTrace->GetFrame(0));
11538 checkStackFrame(origin, "baz", 8, 3, false, true,
11539 stackTrace->GetFrame(1));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011540#ifdef ENABLE_DEBUGGER_SUPPORT
11541 bool is_eval = true;
11542#else // ENABLE_DEBUGGER_SUPPORT
11543 bool is_eval = false;
11544#endif // ENABLE_DEBUGGER_SUPPORT
11545
11546 checkStackFrame(NULL, "", 1, 1, is_eval, false,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000011547 stackTrace->GetFrame(2));
11548 // The last frame is an anonymous function that has the initial call to foo.
11549 checkStackFrame(origin, "", 10, 1, false, false,
11550 stackTrace->GetFrame(3));
11551
11552 CHECK(stackTrace->AsArray()->IsArray());
11553 }
11554 return v8::Undefined();
11555}
11556
11557
11558// Tests the C++ StackTrace API.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011559// TODO(3074796): Reenable this as a THREADED_TEST once it passes.
11560// THREADED_TEST(CaptureStackTrace) {
11561TEST(CaptureStackTrace) {
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000011562 v8::HandleScope scope;
11563 v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
11564 Local<ObjectTemplate> templ = ObjectTemplate::New();
11565 templ->Set(v8_str("AnalyzeStackInNativeCode"),
11566 v8::FunctionTemplate::New(AnalyzeStackInNativeCode));
11567 LocalContext context(0, templ);
11568
11569 // Test getting OVERVIEW information. Should ignore information that is not
11570 // script name, function name, line number, and column offset.
11571 const char *overview_source =
11572 "function bar() {\n"
11573 " var y; AnalyzeStackInNativeCode(1);\n"
11574 "}\n"
11575 "function foo() {\n"
11576 "\n"
11577 " bar();\n"
11578 "}\n"
11579 "var x;eval('new foo();');";
11580 v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
11581 v8::Handle<Value> overview_result =
11582 v8::Script::New(overview_src, origin)->Run();
11583 ASSERT(!overview_result.IsEmpty());
11584 ASSERT(overview_result->IsObject());
11585
11586 // Test getting DETAILED information.
11587 const char *detailed_source =
11588 "function bat() {AnalyzeStackInNativeCode(2);\n"
11589 "}\n"
11590 "\n"
11591 "function baz() {\n"
11592 " bat();\n"
11593 "}\n"
11594 "eval('new baz();');";
11595 v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
11596 // Make the script using a non-zero line and column offset.
11597 v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
11598 v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
11599 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
11600 v8::Handle<v8::Script> detailed_script(
11601 v8::Script::New(detailed_src, &detailed_origin));
11602 v8::Handle<Value> detailed_result = detailed_script->Run();
11603 ASSERT(!detailed_result.IsEmpty());
11604 ASSERT(detailed_result->IsObject());
11605}
11606
11607
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011608static void StackTraceForUncaughtExceptionListener(
11609 v8::Handle<v8::Message> message,
11610 v8::Handle<Value>) {
11611 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
11612 CHECK_EQ(2, stack_trace->GetFrameCount());
11613 checkStackFrame("origin", "foo", 2, 3, false, false,
11614 stack_trace->GetFrame(0));
11615 checkStackFrame("origin", "bar", 5, 3, false, false,
11616 stack_trace->GetFrame(1));
11617}
11618
11619TEST(CaptureStackTraceForUncaughtException) {
11620 report_count = 0;
11621 v8::HandleScope scope;
11622 LocalContext env;
11623 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
11624 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
11625
11626 Script::Compile(v8_str("function foo() {\n"
11627 " throw 1;\n"
11628 "};\n"
11629 "function bar() {\n"
11630 " foo();\n"
11631 "};"),
11632 v8_str("origin"))->Run();
11633 v8::Local<v8::Object> global = env->Global();
11634 Local<Value> trouble = global->Get(v8_str("bar"));
11635 CHECK(trouble->IsFunction());
11636 Function::Cast(*trouble)->Call(global, 0, NULL);
11637 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
11638 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
11639}
11640
11641
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011642TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
11643 v8::HandleScope scope;
11644 LocalContext env;
11645 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
11646 1024,
11647 v8::StackTrace::kDetailed);
11648
11649 CompileRun(
11650 "var setters = ['column', 'lineNumber', 'scriptName',\n"
11651 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
11652 " 'isConstructor'];\n"
11653 "for (var i = 0; i < setters.length; i++) {\n"
11654 " var prop = setters[i];\n"
11655 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
11656 "}\n");
11657 CompileRun("throw 'exception';");
11658 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
11659}
11660
11661
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000011662v8::Handle<Value> AnalyzeStackOfEvalWithSourceURL(const v8::Arguments& args) {
11663 v8::HandleScope scope;
11664 v8::Handle<v8::StackTrace> stackTrace =
11665 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
11666 CHECK_EQ(5, stackTrace->GetFrameCount());
11667 v8::Handle<v8::String> url = v8_str("eval_url");
11668 for (int i = 0; i < 3; i++) {
11669 v8::Handle<v8::String> name =
11670 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
11671 CHECK(!name.IsEmpty());
11672 CHECK_EQ(url, name);
11673 }
11674 return v8::Undefined();
11675}
11676
11677
11678TEST(SourceURLInStackTrace) {
11679 v8::HandleScope scope;
11680 Local<ObjectTemplate> templ = ObjectTemplate::New();
11681 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
11682 v8::FunctionTemplate::New(AnalyzeStackOfEvalWithSourceURL));
11683 LocalContext context(0, templ);
11684
11685 const char *source =
11686 "function outer() {\n"
11687 "function bar() {\n"
11688 " AnalyzeStackOfEvalWithSourceURL();\n"
11689 "}\n"
11690 "function foo() {\n"
11691 "\n"
11692 " bar();\n"
11693 "}\n"
11694 "foo();\n"
11695 "}\n"
11696 "eval('(' + outer +')()//@ sourceURL=eval_url');";
11697 CHECK(CompileRun(source)->IsUndefined());
11698}
11699
11700
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000011701// Test that idle notification can be handled and eventually returns true.
ager@chromium.org96c75b52009-08-26 09:13:16 +000011702THREADED_TEST(IdleNotification) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000011703 bool rv = false;
11704 for (int i = 0; i < 100; i++) {
11705 rv = v8::V8::IdleNotification();
11706 if (rv)
11707 break;
11708 }
11709 CHECK(rv == true);
11710}
11711
11712
11713static uint32_t* stack_limit;
11714
11715static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +000011716 stack_limit = reinterpret_cast<uint32_t*>(i::StackGuard::real_climit());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000011717 return v8::Undefined();
11718}
11719
11720
11721// Uses the address of a local variable to determine the stack top now.
11722// Given a size, returns an address that is that far from the current
11723// top of stack.
11724static uint32_t* ComputeStackLimit(uint32_t size) {
11725 uint32_t* answer = &size - (size / sizeof(size));
11726 // If the size is very large and the stack is very near the bottom of
11727 // memory then the calculation above may wrap around and give an address
11728 // that is above the (downwards-growing) stack. In that case we return
11729 // a very low address.
11730 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
11731 return answer;
11732}
11733
11734
11735TEST(SetResourceConstraints) {
11736 static const int K = 1024;
11737 uint32_t* set_limit = ComputeStackLimit(128 * K);
11738
11739 // Set stack limit.
11740 v8::ResourceConstraints constraints;
11741 constraints.set_stack_limit(set_limit);
11742 CHECK(v8::SetResourceConstraints(&constraints));
11743
11744 // Execute a script.
11745 v8::HandleScope scope;
11746 LocalContext env;
11747 Local<v8::FunctionTemplate> fun_templ =
11748 v8::FunctionTemplate::New(GetStackLimitCallback);
11749 Local<Function> fun = fun_templ->GetFunction();
11750 env->Global()->Set(v8_str("get_stack_limit"), fun);
11751 CompileRun("get_stack_limit();");
11752
11753 CHECK(stack_limit == set_limit);
11754}
11755
11756
11757TEST(SetResourceConstraintsInThread) {
11758 uint32_t* set_limit;
11759 {
11760 v8::Locker locker;
11761 static const int K = 1024;
11762 set_limit = ComputeStackLimit(128 * K);
11763
11764 // Set stack limit.
11765 v8::ResourceConstraints constraints;
11766 constraints.set_stack_limit(set_limit);
11767 CHECK(v8::SetResourceConstraints(&constraints));
11768
11769 // Execute a script.
11770 v8::HandleScope scope;
11771 LocalContext env;
11772 Local<v8::FunctionTemplate> fun_templ =
11773 v8::FunctionTemplate::New(GetStackLimitCallback);
11774 Local<Function> fun = fun_templ->GetFunction();
11775 env->Global()->Set(v8_str("get_stack_limit"), fun);
11776 CompileRun("get_stack_limit();");
11777
11778 CHECK(stack_limit == set_limit);
11779 }
11780 {
11781 v8::Locker locker;
11782 CHECK(stack_limit == set_limit);
11783 }
ager@chromium.org96c75b52009-08-26 09:13:16 +000011784}
ager@chromium.org3811b432009-10-28 14:53:37 +000011785
11786
11787THREADED_TEST(GetHeapStatistics) {
11788 v8::HandleScope scope;
11789 LocalContext c1;
11790 v8::HeapStatistics heap_statistics;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011791 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
11792 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
ager@chromium.org3811b432009-10-28 14:53:37 +000011793 v8::V8::GetHeapStatistics(&heap_statistics);
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011794 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
11795 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
ager@chromium.org3811b432009-10-28 14:53:37 +000011796}
11797
11798
11799static double DoubleFromBits(uint64_t value) {
11800 double target;
11801#ifdef BIG_ENDIAN_FLOATING_POINT
11802 const int kIntSize = 4;
11803 // Somebody swapped the lower and higher half of doubles.
11804 memcpy(&target, reinterpret_cast<char*>(&value) + kIntSize, kIntSize);
11805 memcpy(reinterpret_cast<char*>(&target) + kIntSize, &value, kIntSize);
11806#else
11807 memcpy(&target, &value, sizeof(target));
11808#endif
11809 return target;
11810}
11811
11812
11813static uint64_t DoubleToBits(double value) {
11814 uint64_t target;
11815#ifdef BIG_ENDIAN_FLOATING_POINT
11816 const int kIntSize = 4;
11817 // Somebody swapped the lower and higher half of doubles.
11818 memcpy(&target, reinterpret_cast<char*>(&value) + kIntSize, kIntSize);
11819 memcpy(reinterpret_cast<char*>(&target) + kIntSize, &value, kIntSize);
11820#else
11821 memcpy(&target, &value, sizeof(target));
11822#endif
11823 return target;
11824}
11825
11826
11827static double DoubleToDateTime(double input) {
11828 double date_limit = 864e13;
11829 if (IsNaN(input) || input < -date_limit || input > date_limit) {
11830 return i::OS::nan_value();
11831 }
11832 return (input < 0) ? -(floor(-input)) : floor(input);
11833}
11834
11835// We don't have a consistent way to write 64-bit constants syntactically, so we
11836// split them into two 32-bit constants and combine them programmatically.
11837static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
11838 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
11839}
11840
11841
11842THREADED_TEST(QuietSignalingNaNs) {
11843 v8::HandleScope scope;
11844 LocalContext context;
11845 v8::TryCatch try_catch;
11846
11847 // Special double values.
11848 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
11849 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
11850 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
11851 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
11852 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
11853 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
11854 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
11855
11856 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
11857 // on either side of the epoch.
11858 double date_limit = 864e13;
11859
11860 double test_values[] = {
11861 snan,
11862 qnan,
11863 infinity,
11864 max_normal,
11865 date_limit + 1,
11866 date_limit,
11867 min_normal,
11868 max_denormal,
11869 min_denormal,
11870 0,
11871 -0,
11872 -min_denormal,
11873 -max_denormal,
11874 -min_normal,
11875 -date_limit,
11876 -date_limit - 1,
11877 -max_normal,
11878 -infinity,
11879 -qnan,
11880 -snan
11881 };
11882 int num_test_values = 20;
11883
11884 for (int i = 0; i < num_test_values; i++) {
11885 double test_value = test_values[i];
11886
11887 // Check that Number::New preserves non-NaNs and quiets SNaNs.
11888 v8::Handle<v8::Value> number = v8::Number::New(test_value);
11889 double stored_number = number->NumberValue();
11890 if (!IsNaN(test_value)) {
11891 CHECK_EQ(test_value, stored_number);
11892 } else {
11893 uint64_t stored_bits = DoubleToBits(stored_number);
11894 // Check if quiet nan (bits 51..62 all set).
11895 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
11896 }
11897
11898 // Check that Date::New preserves non-NaNs in the date range and
11899 // quiets SNaNs.
11900 v8::Handle<v8::Value> date = v8::Date::New(test_value);
11901 double expected_stored_date = DoubleToDateTime(test_value);
11902 double stored_date = date->NumberValue();
11903 if (!IsNaN(expected_stored_date)) {
11904 CHECK_EQ(expected_stored_date, stored_date);
11905 } else {
11906 uint64_t stored_bits = DoubleToBits(stored_date);
11907 // Check if quiet nan (bits 51..62 all set).
11908 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
11909 }
11910 }
11911}
christian.plesner.hansen@gmail.comb9ce6372009-11-03 11:38:18 +000011912
11913
11914static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
11915 v8::HandleScope scope;
11916 v8::TryCatch tc;
11917 v8::Handle<v8::String> str = args[0]->ToString();
11918 if (tc.HasCaught())
11919 return tc.ReThrow();
11920 return v8::Undefined();
11921}
11922
11923
11924// Test that an exception can be propagated down through a spaghetti
11925// stack using ReThrow.
11926THREADED_TEST(SpaghettiStackReThrow) {
11927 v8::HandleScope scope;
11928 LocalContext context;
11929 context->Global()->Set(
11930 v8::String::New("s"),
11931 v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
11932 v8::TryCatch try_catch;
11933 CompileRun(
11934 "var i = 0;"
11935 "var o = {"
11936 " toString: function () {"
11937 " if (i == 10) {"
11938 " throw 'Hey!';"
11939 " } else {"
11940 " i++;"
11941 " return s(o);"
11942 " }"
11943 " }"
11944 "};"
11945 "s(o);");
11946 CHECK(try_catch.HasCaught());
11947 v8::String::Utf8Value value(try_catch.Exception());
11948 CHECK_EQ(0, strcmp(*value, "Hey!"));
11949}
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011950
11951
sgjesse@chromium.org98180592009-12-02 08:17:28 +000011952TEST(Regress528) {
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011953 v8::V8::Initialize();
11954
11955 v8::HandleScope scope;
11956 v8::Persistent<Context> context;
ager@chromium.org60121232009-12-03 11:25:37 +000011957 v8::Persistent<Context> other_context;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011958 int gc_count;
11959
ager@chromium.org60121232009-12-03 11:25:37 +000011960 // Create a context used to keep the code from aging in the compilation
11961 // cache.
11962 other_context = Context::New();
11963
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011964 // Context-dependent context data creates reference from the compilation
11965 // cache to the global object.
ager@chromium.org60121232009-12-03 11:25:37 +000011966 const char* source_simple = "1";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011967 context = Context::New();
11968 {
11969 v8::HandleScope scope;
11970
11971 context->Enter();
11972 Local<v8::String> obj = v8::String::New("");
11973 context->SetData(obj);
ager@chromium.org60121232009-12-03 11:25:37 +000011974 CompileRun(source_simple);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011975 context->Exit();
11976 }
11977 context.Dispose();
11978 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000011979 other_context->Enter();
11980 CompileRun(source_simple);
11981 other_context->Exit();
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011982 i::Heap::CollectAllGarbage(false);
ager@chromium.org60121232009-12-03 11:25:37 +000011983 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011984 }
ager@chromium.org60121232009-12-03 11:25:37 +000011985 CHECK_GE(2, gc_count);
11986 CHECK_EQ(1, GetGlobalObjectsCount());
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011987
11988 // Eval in a function creates reference from the compilation cache to the
11989 // global object.
ager@chromium.org60121232009-12-03 11:25:37 +000011990 const char* source_eval = "function f(){eval('1')}; f()";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011991 context = Context::New();
11992 {
11993 v8::HandleScope scope;
11994
11995 context->Enter();
ager@chromium.org60121232009-12-03 11:25:37 +000011996 CompileRun(source_eval);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011997 context->Exit();
11998 }
11999 context.Dispose();
12000 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000012001 other_context->Enter();
12002 CompileRun(source_eval);
12003 other_context->Exit();
lrn@chromium.org32d961d2010-06-30 09:09:34 +000012004 i::Heap::CollectAllGarbage(false);
ager@chromium.org60121232009-12-03 11:25:37 +000012005 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000012006 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012007 CHECK_GE(2, gc_count);
sgjesse@chromium.org98180592009-12-02 08:17:28 +000012008 CHECK_EQ(1, GetGlobalObjectsCount());
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000012009
12010 // Looking up the line number for an exception creates reference from the
12011 // compilation cache to the global object.
ager@chromium.org60121232009-12-03 11:25:37 +000012012 const char* source_exception = "function f(){throw 1;} f()";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000012013 context = Context::New();
12014 {
12015 v8::HandleScope scope;
12016
12017 context->Enter();
12018 v8::TryCatch try_catch;
ager@chromium.org60121232009-12-03 11:25:37 +000012019 CompileRun(source_exception);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000012020 CHECK(try_catch.HasCaught());
12021 v8::Handle<v8::Message> message = try_catch.Message();
12022 CHECK(!message.IsEmpty());
12023 CHECK_EQ(1, message->GetLineNumber());
12024 context->Exit();
12025 }
12026 context.Dispose();
12027 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000012028 other_context->Enter();
12029 CompileRun(source_exception);
12030 other_context->Exit();
lrn@chromium.org32d961d2010-06-30 09:09:34 +000012031 i::Heap::CollectAllGarbage(false);
ager@chromium.org60121232009-12-03 11:25:37 +000012032 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000012033 }
ager@chromium.org60121232009-12-03 11:25:37 +000012034 CHECK_GE(2, gc_count);
12035 CHECK_EQ(1, GetGlobalObjectsCount());
12036
12037 other_context.Dispose();
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000012038}
ager@chromium.org5c838252010-02-19 08:53:10 +000012039
12040
12041THREADED_TEST(ScriptOrigin) {
12042 v8::HandleScope scope;
12043 LocalContext env;
12044 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
12045 v8::Handle<v8::String> script = v8::String::New(
12046 "function f() {}\n\nfunction g() {}");
12047 v8::Script::Compile(script, &origin)->Run();
12048 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
12049 env->Global()->Get(v8::String::New("f")));
12050 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
12051 env->Global()->Get(v8::String::New("g")));
12052
12053 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
12054 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
12055 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
12056
12057 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
12058 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
12059 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
12060}
12061
12062
12063THREADED_TEST(ScriptLineNumber) {
12064 v8::HandleScope scope;
12065 LocalContext env;
12066 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
12067 v8::Handle<v8::String> script = v8::String::New(
12068 "function f() {}\n\nfunction g() {}");
12069 v8::Script::Compile(script, &origin)->Run();
12070 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
12071 env->Global()->Get(v8::String::New("f")));
12072 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
12073 env->Global()->Get(v8::String::New("g")));
12074 CHECK_EQ(0, f->GetScriptLineNumber());
12075 CHECK_EQ(2, g->GetScriptLineNumber());
12076}
12077
12078
12079static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
12080 const AccessorInfo& info) {
12081 return v8_num(42);
12082}
12083
12084
12085static void SetterWhichSetsYOnThisTo23(Local<String> name,
12086 Local<Value> value,
12087 const AccessorInfo& info) {
12088 info.This()->Set(v8_str("y"), v8_num(23));
12089}
12090
12091
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012092TEST(SetterOnConstructorPrototype) {
ager@chromium.org5c838252010-02-19 08:53:10 +000012093 v8::HandleScope scope;
12094 Local<ObjectTemplate> templ = ObjectTemplate::New();
12095 templ->SetAccessor(v8_str("x"),
12096 GetterWhichReturns42,
12097 SetterWhichSetsYOnThisTo23);
12098 LocalContext context;
12099 context->Global()->Set(v8_str("P"), templ->NewInstance());
12100 CompileRun("function C1() {"
12101 " this.x = 23;"
12102 "};"
12103 "C1.prototype = P;"
12104 "function C2() {"
12105 " this.x = 23"
12106 "};"
12107 "C2.prototype = { };"
12108 "C2.prototype.__proto__ = P;");
12109
12110 v8::Local<v8::Script> script;
12111 script = v8::Script::Compile(v8_str("new C1();"));
12112 for (int i = 0; i < 10; i++) {
12113 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
12114 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
12115 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
12116 }
12117
12118 script = v8::Script::Compile(v8_str("new C2();"));
12119 for (int i = 0; i < 10; i++) {
12120 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
12121 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
12122 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
12123 }
12124}
12125
12126
12127static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
12128 Local<String> name, const AccessorInfo& info) {
12129 return v8_num(42);
12130}
12131
12132
12133static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
12134 Local<String> name, Local<Value> value, const AccessorInfo& info) {
12135 if (name->Equals(v8_str("x"))) {
12136 info.This()->Set(v8_str("y"), v8_num(23));
12137 }
12138 return v8::Handle<Value>();
12139}
12140
12141
12142THREADED_TEST(InterceptorOnConstructorPrototype) {
12143 v8::HandleScope scope;
12144 Local<ObjectTemplate> templ = ObjectTemplate::New();
12145 templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
12146 NamedPropertySetterWhichSetsYOnThisTo23);
12147 LocalContext context;
12148 context->Global()->Set(v8_str("P"), templ->NewInstance());
12149 CompileRun("function C1() {"
12150 " this.x = 23;"
12151 "};"
12152 "C1.prototype = P;"
12153 "function C2() {"
12154 " this.x = 23"
12155 "};"
12156 "C2.prototype = { };"
12157 "C2.prototype.__proto__ = P;");
12158
12159 v8::Local<v8::Script> script;
12160 script = v8::Script::Compile(v8_str("new C1();"));
12161 for (int i = 0; i < 10; i++) {
12162 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
12163 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
12164 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
12165 }
12166
12167 script = v8::Script::Compile(v8_str("new C2();"));
12168 for (int i = 0; i < 10; i++) {
12169 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
12170 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
12171 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
12172 }
12173}
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012174
12175
12176TEST(Bug618) {
12177 const char* source = "function C1() {"
12178 " this.x = 23;"
12179 "};"
12180 "C1.prototype = P;";
12181
12182 v8::HandleScope scope;
12183 LocalContext context;
12184 v8::Local<v8::Script> script;
12185
12186 // Use a simple object as prototype.
12187 v8::Local<v8::Object> prototype = v8::Object::New();
12188 prototype->Set(v8_str("y"), v8_num(42));
12189 context->Global()->Set(v8_str("P"), prototype);
12190
12191 // This compile will add the code to the compilation cache.
12192 CompileRun(source);
12193
12194 script = v8::Script::Compile(v8_str("new C1();"));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000012195 // Allow enough iterations for the inobject slack tracking logic
12196 // to finalize instance size and install the fast construct stub.
12197 for (int i = 0; i < 256; i++) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012198 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
12199 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
12200 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
12201 }
12202
12203 // Use an API object with accessors as prototype.
12204 Local<ObjectTemplate> templ = ObjectTemplate::New();
12205 templ->SetAccessor(v8_str("x"),
12206 GetterWhichReturns42,
12207 SetterWhichSetsYOnThisTo23);
12208 context->Global()->Set(v8_str("P"), templ->NewInstance());
12209
12210 // This compile will get the code from the compilation cache.
12211 CompileRun(source);
12212
12213 script = v8::Script::Compile(v8_str("new C1();"));
12214 for (int i = 0; i < 10; i++) {
12215 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
12216 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
12217 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
12218 }
12219}
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012220
12221int prologue_call_count = 0;
12222int epilogue_call_count = 0;
12223int prologue_call_count_second = 0;
12224int epilogue_call_count_second = 0;
12225
12226void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
12227 ++prologue_call_count;
12228}
12229
12230void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
12231 ++epilogue_call_count;
12232}
12233
12234void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
12235 ++prologue_call_count_second;
12236}
12237
12238void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
12239 ++epilogue_call_count_second;
12240}
12241
12242TEST(GCCallbacks) {
12243 LocalContext context;
12244
12245 v8::V8::AddGCPrologueCallback(PrologueCallback);
12246 v8::V8::AddGCEpilogueCallback(EpilogueCallback);
12247 CHECK_EQ(0, prologue_call_count);
12248 CHECK_EQ(0, epilogue_call_count);
12249 i::Heap::CollectAllGarbage(false);
12250 CHECK_EQ(1, prologue_call_count);
12251 CHECK_EQ(1, epilogue_call_count);
12252 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
12253 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
12254 i::Heap::CollectAllGarbage(false);
12255 CHECK_EQ(2, prologue_call_count);
12256 CHECK_EQ(2, epilogue_call_count);
12257 CHECK_EQ(1, prologue_call_count_second);
12258 CHECK_EQ(1, epilogue_call_count_second);
12259 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
12260 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
12261 i::Heap::CollectAllGarbage(false);
12262 CHECK_EQ(2, prologue_call_count);
12263 CHECK_EQ(2, epilogue_call_count);
12264 CHECK_EQ(2, prologue_call_count_second);
12265 CHECK_EQ(2, epilogue_call_count_second);
12266 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
12267 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
12268 i::Heap::CollectAllGarbage(false);
12269 CHECK_EQ(2, prologue_call_count);
12270 CHECK_EQ(2, epilogue_call_count);
12271 CHECK_EQ(2, prologue_call_count_second);
12272 CHECK_EQ(2, epilogue_call_count_second);
12273}
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000012274
12275
12276THREADED_TEST(AddToJSFunctionResultCache) {
12277 i::FLAG_allow_natives_syntax = true;
12278 v8::HandleScope scope;
12279
12280 LocalContext context;
12281
12282 const char* code =
12283 "(function() {"
12284 " var key0 = 'a';"
12285 " var key1 = 'b';"
12286 " var r0 = %_GetFromCache(0, key0);"
12287 " var r1 = %_GetFromCache(0, key1);"
12288 " var r0_ = %_GetFromCache(0, key0);"
12289 " if (r0 !== r0_)"
12290 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
12291 " var r1_ = %_GetFromCache(0, key1);"
12292 " if (r1 !== r1_)"
12293 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
12294 " return 'PASSED';"
12295 "})()";
lrn@chromium.org32d961d2010-06-30 09:09:34 +000012296 i::Heap::ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000012297 ExpectString(code, "PASSED");
12298}
12299
12300
12301static const int k0CacheSize = 16;
12302
12303THREADED_TEST(FillJSFunctionResultCache) {
12304 i::FLAG_allow_natives_syntax = true;
12305 v8::HandleScope scope;
12306
12307 LocalContext context;
12308
12309 const char* code =
12310 "(function() {"
12311 " var k = 'a';"
12312 " var r = %_GetFromCache(0, k);"
12313 " for (var i = 0; i < 16; i++) {"
12314 " %_GetFromCache(0, 'a' + i);"
12315 " };"
12316 " if (r === %_GetFromCache(0, k))"
12317 " return 'FAILED: k0CacheSize is too small';"
12318 " return 'PASSED';"
12319 "})()";
lrn@chromium.org32d961d2010-06-30 09:09:34 +000012320 i::Heap::ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000012321 ExpectString(code, "PASSED");
12322}
12323
12324
12325THREADED_TEST(RoundRobinGetFromCache) {
12326 i::FLAG_allow_natives_syntax = true;
12327 v8::HandleScope scope;
12328
12329 LocalContext context;
12330
12331 const char* code =
12332 "(function() {"
12333 " var keys = [];"
12334 " for (var i = 0; i < 16; i++) keys.push(i);"
12335 " var values = [];"
12336 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
12337 " for (var i = 0; i < 16; i++) {"
12338 " var v = %_GetFromCache(0, keys[i]);"
12339 " if (v !== values[i])"
12340 " return 'Wrong value for ' + "
12341 " keys[i] + ': ' + v + ' vs. ' + values[i];"
12342 " };"
12343 " return 'PASSED';"
12344 "})()";
lrn@chromium.org32d961d2010-06-30 09:09:34 +000012345 i::Heap::ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000012346 ExpectString(code, "PASSED");
12347}
12348
12349
12350THREADED_TEST(ReverseGetFromCache) {
12351 i::FLAG_allow_natives_syntax = true;
12352 v8::HandleScope scope;
12353
12354 LocalContext context;
12355
12356 const char* code =
12357 "(function() {"
12358 " var keys = [];"
12359 " for (var i = 0; i < 16; i++) keys.push(i);"
12360 " var values = [];"
12361 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
12362 " for (var i = 15; i >= 16; i--) {"
12363 " var v = %_GetFromCache(0, keys[i]);"
12364 " if (v !== values[i])"
12365 " return 'Wrong value for ' + "
12366 " keys[i] + ': ' + v + ' vs. ' + values[i];"
12367 " };"
12368 " return 'PASSED';"
12369 "})()";
lrn@chromium.org32d961d2010-06-30 09:09:34 +000012370 i::Heap::ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000012371 ExpectString(code, "PASSED");
12372}
12373
12374
12375THREADED_TEST(TestEviction) {
12376 i::FLAG_allow_natives_syntax = true;
12377 v8::HandleScope scope;
12378
12379 LocalContext context;
12380
12381 const char* code =
12382 "(function() {"
12383 " for (var i = 0; i < 2*16; i++) {"
12384 " %_GetFromCache(0, 'a' + i);"
12385 " };"
12386 " return 'PASSED';"
12387 "})()";
lrn@chromium.org32d961d2010-06-30 09:09:34 +000012388 i::Heap::ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000012389 ExpectString(code, "PASSED");
12390}
lrn@chromium.org32d961d2010-06-30 09:09:34 +000012391
12392
12393THREADED_TEST(TwoByteStringInAsciiCons) {
12394 // See Chromium issue 47824.
12395 v8::HandleScope scope;
12396
12397 LocalContext context;
12398 const char* init_code =
12399 "var str1 = 'abelspendabel';"
12400 "var str2 = str1 + str1 + str1;"
12401 "str2;";
12402 Local<Value> result = CompileRun(init_code);
12403
12404 CHECK(result->IsString());
12405 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
12406 int length = string->length();
12407 CHECK(string->IsAsciiRepresentation());
12408
12409 FlattenString(string);
12410 i::Handle<i::String> flat_string = FlattenGetString(string);
12411
12412 CHECK(string->IsAsciiRepresentation());
12413 CHECK(flat_string->IsAsciiRepresentation());
12414
12415 // Create external resource.
12416 uint16_t* uc16_buffer = new uint16_t[length + 1];
12417
12418 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
12419 uc16_buffer[length] = 0;
12420
12421 TestResource resource(uc16_buffer);
12422
12423 flat_string->MakeExternal(&resource);
12424
12425 CHECK(flat_string->IsTwoByteRepresentation());
12426
12427 // At this point, we should have a Cons string which is flat and ASCII,
12428 // with a first half that is a two-byte string (although it only contains
12429 // ASCII characters). This is a valid sequence of steps, and it can happen
12430 // in real pages.
12431
12432 CHECK(string->IsAsciiRepresentation());
12433 i::ConsString* cons = i::ConsString::cast(*string);
12434 CHECK_EQ(0, cons->second()->length());
12435 CHECK(cons->first()->IsTwoByteRepresentation());
12436
12437 // Check that some string operations work.
12438
12439 // Atom RegExp.
12440 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
12441 CHECK_EQ(6, reresult->Int32Value());
12442
12443 // Nonatom RegExp.
12444 reresult = CompileRun("str2.match(/abe./g).length;");
12445 CHECK_EQ(6, reresult->Int32Value());
12446
12447 reresult = CompileRun("str2.search(/bel/g);");
12448 CHECK_EQ(1, reresult->Int32Value());
12449
12450 reresult = CompileRun("str2.search(/be./g);");
12451 CHECK_EQ(1, reresult->Int32Value());
12452
12453 ExpectTrue("/bel/g.test(str2);");
12454
12455 ExpectTrue("/be./g.test(str2);");
12456
12457 reresult = CompileRun("/bel/g.exec(str2);");
12458 CHECK(!reresult->IsNull());
12459
12460 reresult = CompileRun("/be./g.exec(str2);");
12461 CHECK(!reresult->IsNull());
12462
12463 ExpectString("str2.substring(2, 10);", "elspenda");
12464
12465 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
12466
12467 ExpectString("str2.charAt(2);", "e");
12468
12469 reresult = CompileRun("str2.charCodeAt(2);");
12470 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
12471}
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000012472
12473
12474// Failed access check callback that performs a GC on each invocation.
12475void FailedAccessCheckCallbackGC(Local<v8::Object> target,
12476 v8::AccessType type,
12477 Local<v8::Value> data) {
12478 i::Heap::CollectAllGarbage(true);
12479}
12480
12481
12482TEST(GCInFailedAccessCheckCallback) {
12483 // Install a failed access check callback that performs a GC on each
12484 // invocation. Then force the callback to be called from va
12485
12486 v8::V8::Initialize();
12487 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
12488
12489 v8::HandleScope scope;
12490
12491 // Create an ObjectTemplate for global objects and install access
12492 // check callbacks that will block access.
12493 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
12494 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
12495 IndexedGetAccessBlocker,
12496 v8::Handle<v8::Value>(),
12497 false);
12498
12499 // Create a context and set an x property on it's global object.
12500 LocalContext context0(NULL, global_template);
12501 context0->Global()->Set(v8_str("x"), v8_num(42));
12502 v8::Handle<v8::Object> global0 = context0->Global();
12503
12504 // Create a context with a different security token so that the
12505 // failed access check callback will be called on each access.
12506 LocalContext context1(NULL, global_template);
12507 context1->Global()->Set(v8_str("other"), global0);
12508
12509 // Get property with failed access check.
12510 ExpectUndefined("other.x");
12511
12512 // Get element with failed access check.
12513 ExpectUndefined("other[0]");
12514
12515 // Set property with failed access check.
12516 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
12517 CHECK(result->IsObject());
12518
12519 // Set element with failed access check.
12520 result = CompileRun("other[0] = new Object()");
12521 CHECK(result->IsObject());
12522
12523 // Get property attribute with failed access check.
12524 ExpectFalse("\'x\' in other");
12525
12526 // Get property attribute for element with failed access check.
12527 ExpectFalse("0 in other");
12528
12529 // Delete property.
12530 ExpectFalse("delete other.x");
12531
12532 // Delete element.
12533 CHECK_EQ(false, global0->Delete(0));
12534
12535 // DefineAccessor.
12536 CHECK_EQ(false,
12537 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
12538
12539 // Define JavaScript accessor.
12540 ExpectUndefined("Object.prototype.__defineGetter__.call("
12541 " other, \'x\', function() { return 42; })");
12542
12543 // LookupAccessor.
12544 ExpectUndefined("Object.prototype.__lookupGetter__.call("
12545 " other, \'x\')");
12546
12547 // HasLocalElement.
12548 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
12549
12550 CHECK_EQ(false, global0->HasRealIndexedProperty(0));
12551 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
12552 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
12553
12554 // Reset the failed access check callback so it does not influence
12555 // the other tests.
12556 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
12557}
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000012558
12559
12560TEST(StringCheckMultipleContexts) {
12561 const char* code =
12562 "(function() { return \"a\".charAt(0); })()";
12563
12564 {
12565 // Run the code twice in the first context to initialize the call IC.
12566 v8::HandleScope scope;
12567 LocalContext context1;
12568 ExpectString(code, "a");
12569 ExpectString(code, "a");
12570 }
12571
12572 {
12573 // Change the String.prototype in the second context and check
12574 // that the right function gets called.
12575 v8::HandleScope scope;
12576 LocalContext context2;
12577 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
12578 ExpectString(code, "not a");
12579 }
12580}
12581
12582
12583TEST(NumberCheckMultipleContexts) {
12584 const char* code =
12585 "(function() { return (42).toString(); })()";
12586
12587 {
12588 // Run the code twice in the first context to initialize the call IC.
12589 v8::HandleScope scope;
12590 LocalContext context1;
12591 ExpectString(code, "42");
12592 ExpectString(code, "42");
12593 }
12594
12595 {
12596 // Change the Number.prototype in the second context and check
12597 // that the right function gets called.
12598 v8::HandleScope scope;
12599 LocalContext context2;
12600 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
12601 ExpectString(code, "not 42");
12602 }
12603}
12604
12605
12606TEST(BooleanCheckMultipleContexts) {
12607 const char* code =
12608 "(function() { return true.toString(); })()";
12609
12610 {
12611 // Run the code twice in the first context to initialize the call IC.
12612 v8::HandleScope scope;
12613 LocalContext context1;
12614 ExpectString(code, "true");
12615 ExpectString(code, "true");
12616 }
12617
12618 {
12619 // Change the Boolean.prototype in the second context and check
12620 // that the right function gets called.
12621 v8::HandleScope scope;
12622 LocalContext context2;
12623 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
12624 ExpectString(code, "");
12625 }
12626}
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000012627
12628
12629TEST(DontDeleteCellLoadIC) {
12630 const char* function_code =
12631 "function readCell() { while (true) { return cell; } }";
12632
12633 {
12634 // Run the code twice in the first context to initialize the load
12635 // IC for a don't delete cell.
12636 v8::HandleScope scope;
12637 LocalContext context1;
12638 CompileRun("var cell = \"first\";");
12639 ExpectBoolean("delete cell", false);
12640 CompileRun(function_code);
12641 ExpectString("readCell()", "first");
12642 ExpectString("readCell()", "first");
12643 }
12644
12645 {
12646 // Use a deletable cell in the second context.
12647 v8::HandleScope scope;
12648 LocalContext context2;
12649 CompileRun("cell = \"second\";");
12650 CompileRun(function_code);
12651 ExpectString("readCell()", "second");
12652 ExpectBoolean("delete cell", true);
12653 ExpectString("(function() {"
12654 " try {"
12655 " return readCell();"
12656 " } catch(e) {"
12657 " return e.toString();"
12658 " }"
12659 "})()",
12660 "ReferenceError: cell is not defined");
12661 CompileRun("cell = \"new_second\";");
12662 i::Heap::CollectAllGarbage(true);
12663 ExpectString("readCell()", "new_second");
12664 ExpectString("readCell()", "new_second");
12665 }
12666}
12667
12668
12669TEST(DontDeleteCellLoadICForceDelete) {
12670 const char* function_code =
12671 "function readCell() { while (true) { return cell; } }";
12672
12673 // Run the code twice to initialize the load IC for a don't delete
12674 // cell.
12675 v8::HandleScope scope;
12676 LocalContext context;
12677 CompileRun("var cell = \"value\";");
12678 ExpectBoolean("delete cell", false);
12679 CompileRun(function_code);
12680 ExpectString("readCell()", "value");
12681 ExpectString("readCell()", "value");
12682
12683 // Delete the cell using the API and check the inlined code works
12684 // correctly.
12685 CHECK(context->Global()->ForceDelete(v8_str("cell")));
12686 ExpectString("(function() {"
12687 " try {"
12688 " return readCell();"
12689 " } catch(e) {"
12690 " return e.toString();"
12691 " }"
12692 "})()",
12693 "ReferenceError: cell is not defined");
12694}
12695
12696
12697TEST(DontDeleteCellLoadICAPI) {
12698 const char* function_code =
12699 "function readCell() { while (true) { return cell; } }";
12700
12701 // Run the code twice to initialize the load IC for a don't delete
12702 // cell created using the API.
12703 v8::HandleScope scope;
12704 LocalContext context;
12705 context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
12706 ExpectBoolean("delete cell", false);
12707 CompileRun(function_code);
12708 ExpectString("readCell()", "value");
12709 ExpectString("readCell()", "value");
12710
12711 // Delete the cell using the API and check the inlined code works
12712 // correctly.
12713 CHECK(context->Global()->ForceDelete(v8_str("cell")));
12714 ExpectString("(function() {"
12715 " try {"
12716 " return readCell();"
12717 " } catch(e) {"
12718 " return e.toString();"
12719 " }"
12720 "})()",
12721 "ReferenceError: cell is not defined");
12722}
12723
12724
12725TEST(GlobalLoadICGC) {
12726 const char* function_code =
12727 "function readCell() { while (true) { return cell; } }";
12728
12729 // Check inline load code for a don't delete cell is cleared during
12730 // GC.
12731 {
12732 v8::HandleScope scope;
12733 LocalContext context;
12734 CompileRun("var cell = \"value\";");
12735 ExpectBoolean("delete cell", false);
12736 CompileRun(function_code);
12737 ExpectString("readCell()", "value");
12738 ExpectString("readCell()", "value");
12739 }
12740 {
12741 v8::HandleScope scope;
12742 LocalContext context2;
12743 // Hold the code object in the second context.
12744 CompileRun(function_code);
12745 CheckSurvivingGlobalObjectsCount(1);
12746 }
12747
12748 // Check inline load code for a deletable cell is cleared during GC.
12749 {
12750 v8::HandleScope scope;
12751 LocalContext context;
12752 CompileRun("cell = \"value\";");
12753 CompileRun(function_code);
12754 ExpectString("readCell()", "value");
12755 ExpectString("readCell()", "value");
12756 }
12757 {
12758 v8::HandleScope scope;
12759 LocalContext context2;
12760 // Hold the code object in the second context.
12761 CompileRun(function_code);
12762 CheckSurvivingGlobalObjectsCount(1);
12763 }
12764}
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000012765
12766
12767TEST(RegExp) {
12768 v8::HandleScope scope;
12769 LocalContext context;
12770
12771 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
12772 CHECK(re->IsRegExp());
12773 CHECK(re->GetSource()->Equals(v8_str("foo")));
12774 CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
12775
12776 re = v8::RegExp::New(v8_str("bar"),
12777 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
12778 v8::RegExp::kGlobal));
12779 CHECK(re->IsRegExp());
12780 CHECK(re->GetSource()->Equals(v8_str("bar")));
12781 CHECK_EQ(static_cast<int>(re->GetFlags()),
12782 v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal);
12783
12784 re = v8::RegExp::New(v8_str("baz"),
12785 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
12786 v8::RegExp::kMultiline));
12787 CHECK(re->IsRegExp());
12788 CHECK(re->GetSource()->Equals(v8_str("baz")));
12789 CHECK_EQ(static_cast<int>(re->GetFlags()),
12790 v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline);
12791
12792 re = CompileRun("/quux/").As<v8::RegExp>();
12793 CHECK(re->IsRegExp());
12794 CHECK(re->GetSource()->Equals(v8_str("quux")));
12795 CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
12796
12797 re = CompileRun("/quux/gm").As<v8::RegExp>();
12798 CHECK(re->IsRegExp());
12799 CHECK(re->GetSource()->Equals(v8_str("quux")));
12800 CHECK_EQ(static_cast<int>(re->GetFlags()),
12801 v8::RegExp::kGlobal | v8::RegExp::kMultiline);
12802
12803 // Override the RegExp constructor and check the API constructor
12804 // still works.
12805 CompileRun("RegExp = function() {}");
12806
12807 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
12808 CHECK(re->IsRegExp());
12809 CHECK(re->GetSource()->Equals(v8_str("foobar")));
12810 CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
12811
12812 re = v8::RegExp::New(v8_str("foobarbaz"),
12813 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
12814 v8::RegExp::kMultiline));
12815 CHECK(re->IsRegExp());
12816 CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
12817 CHECK_EQ(static_cast<int>(re->GetFlags()),
12818 v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline);
12819
12820 context->Global()->Set(v8_str("re"), re);
12821 ExpectTrue("re.test('FoobarbaZ')");
12822
12823 v8::TryCatch try_catch;
12824 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
12825 CHECK(re.IsEmpty());
12826 CHECK(try_catch.HasCaught());
12827 context->Global()->Set(v8_str("ex"), try_catch.Exception());
12828 ExpectTrue("ex instanceof SyntaxError");
12829}
12830
12831
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000012832THREADED_TEST(Equals) {
12833 v8::HandleScope handleScope;
12834 LocalContext localContext;
12835
12836 v8::Handle<v8::Object> globalProxy = localContext->Global();
12837 v8::Handle<Value> global = globalProxy->GetPrototype();
12838
12839 CHECK(global->StrictEquals(global));
12840 CHECK(!global->StrictEquals(globalProxy));
12841 CHECK(!globalProxy->StrictEquals(global));
12842 CHECK(globalProxy->StrictEquals(globalProxy));
12843
12844 CHECK(global->Equals(global));
12845 CHECK(!global->Equals(globalProxy));
12846 CHECK(!globalProxy->Equals(global));
12847 CHECK(globalProxy->Equals(globalProxy));
12848}
12849
12850
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000012851static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
12852 const v8::AccessorInfo& info ) {
12853 return v8_str("42!");
12854}
12855
12856
12857static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo& info) {
12858 v8::Handle<v8::Array> result = v8::Array::New();
12859 result->Set(0, v8_str("universalAnswer"));
12860 return result;
12861}
12862
12863
12864TEST(NamedEnumeratorAndForIn) {
12865 v8::HandleScope handle_scope;
12866 LocalContext context;
12867 v8::Context::Scope context_scope(context.local());
12868
12869 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New();
12870 tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
12871 context->Global()->Set(v8_str("o"), tmpl->NewInstance());
12872 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
12873 "var result = []; for (var k in o) result.push(k); result"));
12874 CHECK_EQ(1, result->Length());
12875 CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
12876}
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000012877
12878
12879TEST(DefinePropertyPostDetach) {
12880 v8::HandleScope scope;
12881 LocalContext context;
12882 v8::Handle<v8::Object> proxy = context->Global();
12883 v8::Handle<v8::Function> define_property =
12884 CompileRun("(function() {"
12885 " Object.defineProperty("
12886 " this,"
12887 " 1,"
12888 " { configurable: true, enumerable: true, value: 3 });"
12889 "})").As<Function>();
12890 context->DetachGlobal();
12891 define_property->Call(proxy, 0, NULL);
12892}