blob: 90f499674299768599b7986e8674a487fe54c10f [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);
1652}
1653
1654
1655THREADED_TEST(HiddenProperties) {
1656 v8::HandleScope scope;
1657 LocalContext env;
1658
1659 v8::Local<v8::Object> obj = v8::Object::New();
1660 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1661 v8::Local<v8::String> empty = v8_str("");
1662 v8::Local<v8::String> prop_name = v8_str("prop_name");
1663
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001664 i::Heap::CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001665
kasperl@chromium.orgacae3782009-04-11 09:17:08 +00001666 // Make sure delete of a non-existent hidden value works
1667 CHECK(obj->DeleteHiddenValue(key));
1668
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001669 CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
1670 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
1671 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
1672 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1673
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001674 i::Heap::CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001675
1676 // Make sure we do not find the hidden property.
1677 CHECK(!obj->Has(empty));
1678 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1679 CHECK(obj->Get(empty)->IsUndefined());
1680 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1681 CHECK(obj->Set(empty, v8::Integer::New(2003)));
1682 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1683 CHECK_EQ(2003, obj->Get(empty)->Int32Value());
1684
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001685 i::Heap::CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001686
1687 // Add another property and delete it afterwards to force the object in
1688 // slow case.
1689 CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
1690 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1691 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
1692 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1693 CHECK(obj->Delete(prop_name));
1694 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1695
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001696 i::Heap::CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001697
1698 CHECK(obj->DeleteHiddenValue(key));
1699 CHECK(obj->GetHiddenValue(key).IsEmpty());
1700}
1701
1702
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001703static bool interceptor_for_hidden_properties_called;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001704static v8::Handle<Value> InterceptorForHiddenProperties(
1705 Local<String> name, const AccessorInfo& info) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001706 interceptor_for_hidden_properties_called = true;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001707 return v8::Handle<Value>();
1708}
1709
1710
1711THREADED_TEST(HiddenPropertiesWithInterceptors) {
1712 v8::HandleScope scope;
1713 LocalContext context;
1714
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001715 interceptor_for_hidden_properties_called = false;
1716
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001717 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1718
1719 // Associate an interceptor with an object and start setting hidden values.
1720 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
1721 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
1722 instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
1723 Local<v8::Function> function = fun_templ->GetFunction();
1724 Local<v8::Object> obj = function->NewInstance();
1725 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
1726 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001727 CHECK(!interceptor_for_hidden_properties_called);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001728}
1729
1730
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001731THREADED_TEST(External) {
1732 v8::HandleScope scope;
1733 int x = 3;
1734 Local<v8::External> ext = v8::External::New(&x);
1735 LocalContext env;
1736 env->Global()->Set(v8_str("ext"), ext);
1737 Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001738 v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001739 int* ptr = static_cast<int*>(reext->Value());
1740 CHECK_EQ(x, 3);
1741 *ptr = 10;
1742 CHECK_EQ(x, 10);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001743
1744 // Make sure unaligned pointers are wrapped properly.
1745 char* data = i::StrDup("0123456789");
1746 Local<v8::Value> zero = v8::External::Wrap(&data[0]);
1747 Local<v8::Value> one = v8::External::Wrap(&data[1]);
1748 Local<v8::Value> two = v8::External::Wrap(&data[2]);
1749 Local<v8::Value> three = v8::External::Wrap(&data[3]);
1750
1751 char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero));
1752 CHECK_EQ('0', *char_ptr);
1753 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one));
1754 CHECK_EQ('1', *char_ptr);
1755 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two));
1756 CHECK_EQ('2', *char_ptr);
1757 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three));
1758 CHECK_EQ('3', *char_ptr);
1759 i::DeleteArray(data);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001760}
1761
1762
1763THREADED_TEST(GlobalHandle) {
1764 v8::Persistent<String> global;
1765 {
1766 v8::HandleScope scope;
1767 Local<String> str = v8_str("str");
1768 global = v8::Persistent<String>::New(str);
1769 }
1770 CHECK_EQ(global->Length(), 3);
1771 global.Dispose();
1772}
1773
1774
1775THREADED_TEST(ScriptException) {
1776 v8::HandleScope scope;
1777 LocalContext env;
1778 Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
1779 v8::TryCatch try_catch;
1780 Local<Value> result = script->Run();
1781 CHECK(result.IsEmpty());
1782 CHECK(try_catch.HasCaught());
1783 String::AsciiValue exception_value(try_catch.Exception());
1784 CHECK_EQ(*exception_value, "panama!");
1785}
1786
1787
1788bool message_received;
1789
1790
1791static void check_message(v8::Handle<v8::Message> message,
1792 v8::Handle<Value> data) {
1793 CHECK_EQ(5.76, data->NumberValue());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001794 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001795 CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001796 message_received = true;
1797}
1798
1799
1800THREADED_TEST(MessageHandlerData) {
1801 message_received = false;
1802 v8::HandleScope scope;
1803 CHECK(!message_received);
1804 v8::V8::AddMessageListener(check_message, v8_num(5.76));
1805 LocalContext context;
1806 v8::ScriptOrigin origin =
1807 v8::ScriptOrigin(v8_str("6.75"));
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001808 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
1809 &origin);
1810 script->SetData(v8_str("7.56"));
1811 script->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001812 CHECK(message_received);
1813 // clear out the message listener
1814 v8::V8::RemoveMessageListeners(check_message);
1815}
1816
1817
1818THREADED_TEST(GetSetProperty) {
1819 v8::HandleScope scope;
1820 LocalContext context;
1821 context->Global()->Set(v8_str("foo"), v8_num(14));
1822 context->Global()->Set(v8_str("12"), v8_num(92));
1823 context->Global()->Set(v8::Integer::New(16), v8_num(32));
1824 context->Global()->Set(v8_num(13), v8_num(56));
1825 Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
1826 CHECK_EQ(14, foo->Int32Value());
1827 Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
1828 CHECK_EQ(92, twelve->Int32Value());
1829 Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
1830 CHECK_EQ(32, sixteen->Int32Value());
1831 Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
1832 CHECK_EQ(56, thirteen->Int32Value());
1833 CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
1834 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
1835 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
1836 CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
1837 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
1838 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
1839 CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
1840 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
1841 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
1842}
1843
1844
1845THREADED_TEST(PropertyAttributes) {
1846 v8::HandleScope scope;
1847 LocalContext context;
1848 // read-only
1849 Local<String> prop = v8_str("read_only");
1850 context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
1851 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1852 Script::Compile(v8_str("read_only = 9"))->Run();
1853 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1854 context->Global()->Set(prop, v8_num(10));
1855 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1856 // dont-delete
1857 prop = v8_str("dont_delete");
1858 context->Global()->Set(prop, v8_num(13), v8::DontDelete);
1859 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
1860 Script::Compile(v8_str("delete dont_delete"))->Run();
1861 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
1862}
1863
1864
1865THREADED_TEST(Array) {
1866 v8::HandleScope scope;
1867 LocalContext context;
1868 Local<v8::Array> array = v8::Array::New();
1869 CHECK_EQ(0, array->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001870 CHECK(array->Get(0)->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001871 CHECK(!array->Has(0));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001872 CHECK(array->Get(100)->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001873 CHECK(!array->Has(100));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001874 array->Set(2, v8_num(7));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001875 CHECK_EQ(3, array->Length());
1876 CHECK(!array->Has(0));
1877 CHECK(!array->Has(1));
1878 CHECK(array->Has(2));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001879 CHECK_EQ(7, array->Get(2)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001880 Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001881 Local<v8::Array> arr = obj.As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001882 CHECK_EQ(3, arr->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001883 CHECK_EQ(1, arr->Get(0)->Int32Value());
1884 CHECK_EQ(2, arr->Get(1)->Int32Value());
1885 CHECK_EQ(3, arr->Get(2)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001886}
1887
1888
1889v8::Handle<Value> HandleF(const v8::Arguments& args) {
1890 v8::HandleScope scope;
1891 ApiTestFuzzer::Fuzz();
1892 Local<v8::Array> result = v8::Array::New(args.Length());
1893 for (int i = 0; i < args.Length(); i++)
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001894 result->Set(i, args[i]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001895 return scope.Close(result);
1896}
1897
1898
1899THREADED_TEST(Vector) {
1900 v8::HandleScope scope;
1901 Local<ObjectTemplate> global = ObjectTemplate::New();
1902 global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
1903 LocalContext context(0, global);
1904
1905 const char* fun = "f()";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001906 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001907 CHECK_EQ(0, a0->Length());
1908
1909 const char* fun2 = "f(11)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001910 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001911 CHECK_EQ(1, a1->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001912 CHECK_EQ(11, a1->Get(0)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001913
1914 const char* fun3 = "f(12, 13)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001915 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001916 CHECK_EQ(2, a2->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001917 CHECK_EQ(12, a2->Get(0)->Int32Value());
1918 CHECK_EQ(13, a2->Get(1)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001919
1920 const char* fun4 = "f(14, 15, 16)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001921 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001922 CHECK_EQ(3, a3->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001923 CHECK_EQ(14, a3->Get(0)->Int32Value());
1924 CHECK_EQ(15, a3->Get(1)->Int32Value());
1925 CHECK_EQ(16, a3->Get(2)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001926
1927 const char* fun5 = "f(17, 18, 19, 20)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001928 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001929 CHECK_EQ(4, a4->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001930 CHECK_EQ(17, a4->Get(0)->Int32Value());
1931 CHECK_EQ(18, a4->Get(1)->Int32Value());
1932 CHECK_EQ(19, a4->Get(2)->Int32Value());
1933 CHECK_EQ(20, a4->Get(3)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001934}
1935
1936
1937THREADED_TEST(FunctionCall) {
1938 v8::HandleScope scope;
1939 LocalContext context;
1940 CompileRun(
1941 "function Foo() {"
1942 " var result = [];"
1943 " for (var i = 0; i < arguments.length; i++) {"
1944 " result.push(arguments[i]);"
1945 " }"
1946 " return result;"
1947 "}");
1948 Local<Function> Foo =
1949 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
1950
1951 v8::Handle<Value>* args0 = NULL;
1952 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
1953 CHECK_EQ(0, a0->Length());
1954
1955 v8::Handle<Value> args1[] = { v8_num(1.1) };
1956 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
1957 CHECK_EQ(1, a1->Length());
1958 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
1959
1960 v8::Handle<Value> args2[] = { v8_num(2.2),
1961 v8_num(3.3) };
1962 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
1963 CHECK_EQ(2, a2->Length());
1964 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
1965 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
1966
1967 v8::Handle<Value> args3[] = { v8_num(4.4),
1968 v8_num(5.5),
1969 v8_num(6.6) };
1970 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
1971 CHECK_EQ(3, a3->Length());
1972 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
1973 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
1974 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
1975
1976 v8::Handle<Value> args4[] = { v8_num(7.7),
1977 v8_num(8.8),
1978 v8_num(9.9),
1979 v8_num(10.11) };
1980 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
1981 CHECK_EQ(4, a4->Length());
1982 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
1983 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
1984 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
1985 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
1986}
1987
1988
1989static const char* js_code_causing_out_of_memory =
1990 "var a = new Array(); while(true) a.push(a);";
1991
1992
1993// These tests run for a long time and prevent us from running tests
1994// that come after them so they cannot run in parallel.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001995TEST(OutOfMemory) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001996 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00001997 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001998 // Set heap limits.
1999 static const int K = 1024;
2000 v8::ResourceConstraints constraints;
2001 constraints.set_max_young_space_size(256 * K);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002002 constraints.set_max_old_space_size(4 * K * K);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002003 v8::SetResourceConstraints(&constraints);
2004
2005 // Execute a script that causes out of memory.
2006 v8::HandleScope scope;
2007 LocalContext context;
2008 v8::V8::IgnoreOutOfMemoryException();
2009 Local<Script> script =
2010 Script::Compile(String::New(js_code_causing_out_of_memory));
2011 Local<Value> result = script->Run();
2012
2013 // Check for out of memory state.
2014 CHECK(result.IsEmpty());
2015 CHECK(context->HasOutOfMemoryException());
2016}
2017
2018
2019v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
2020 ApiTestFuzzer::Fuzz();
2021
2022 v8::HandleScope scope;
2023 LocalContext context;
2024 Local<Script> script =
2025 Script::Compile(String::New(js_code_causing_out_of_memory));
2026 Local<Value> result = script->Run();
2027
2028 // Check for out of memory state.
2029 CHECK(result.IsEmpty());
2030 CHECK(context->HasOutOfMemoryException());
2031
2032 return result;
2033}
2034
2035
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002036TEST(OutOfMemoryNested) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002037 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002038 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002039 // Set heap limits.
2040 static const int K = 1024;
2041 v8::ResourceConstraints constraints;
2042 constraints.set_max_young_space_size(256 * K);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002043 constraints.set_max_old_space_size(4 * K * K);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002044 v8::SetResourceConstraints(&constraints);
2045
2046 v8::HandleScope scope;
2047 Local<ObjectTemplate> templ = ObjectTemplate::New();
2048 templ->Set(v8_str("ProvokeOutOfMemory"),
2049 v8::FunctionTemplate::New(ProvokeOutOfMemory));
2050 LocalContext context(0, templ);
2051 v8::V8::IgnoreOutOfMemoryException();
2052 Local<Value> result = CompileRun(
2053 "var thrown = false;"
2054 "try {"
2055 " ProvokeOutOfMemory();"
2056 "} catch (e) {"
2057 " thrown = true;"
2058 "}");
2059 // Check for out of memory state.
2060 CHECK(result.IsEmpty());
2061 CHECK(context->HasOutOfMemoryException());
2062}
2063
2064
2065TEST(HugeConsStringOutOfMemory) {
2066 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002067 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002068 v8::HandleScope scope;
2069 LocalContext context;
2070 // Set heap limits.
2071 static const int K = 1024;
2072 v8::ResourceConstraints constraints;
2073 constraints.set_max_young_space_size(256 * K);
2074 constraints.set_max_old_space_size(2 * K * K);
2075 v8::SetResourceConstraints(&constraints);
2076
2077 // Execute a script that causes out of memory.
2078 v8::V8::IgnoreOutOfMemoryException();
2079
2080 // Build huge string. This should fail with out of memory exception.
2081 Local<Value> result = CompileRun(
2082 "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002083 "for (var i = 0; i < 22; i++) { str = str + str; }");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002084
2085 // Check for out of memory state.
2086 CHECK(result.IsEmpty());
2087 CHECK(context->HasOutOfMemoryException());
2088}
2089
2090
2091THREADED_TEST(ConstructCall) {
2092 v8::HandleScope scope;
2093 LocalContext context;
2094 CompileRun(
2095 "function Foo() {"
2096 " var result = [];"
2097 " for (var i = 0; i < arguments.length; i++) {"
2098 " result.push(arguments[i]);"
2099 " }"
2100 " return result;"
2101 "}");
2102 Local<Function> Foo =
2103 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2104
2105 v8::Handle<Value>* args0 = NULL;
2106 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
2107 CHECK_EQ(0, a0->Length());
2108
2109 v8::Handle<Value> args1[] = { v8_num(1.1) };
2110 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
2111 CHECK_EQ(1, a1->Length());
2112 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2113
2114 v8::Handle<Value> args2[] = { v8_num(2.2),
2115 v8_num(3.3) };
2116 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
2117 CHECK_EQ(2, a2->Length());
2118 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2119 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2120
2121 v8::Handle<Value> args3[] = { v8_num(4.4),
2122 v8_num(5.5),
2123 v8_num(6.6) };
2124 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
2125 CHECK_EQ(3, a3->Length());
2126 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2127 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2128 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2129
2130 v8::Handle<Value> args4[] = { v8_num(7.7),
2131 v8_num(8.8),
2132 v8_num(9.9),
2133 v8_num(10.11) };
2134 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
2135 CHECK_EQ(4, a4->Length());
2136 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2137 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2138 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2139 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2140}
2141
2142
2143static void CheckUncle(v8::TryCatch* try_catch) {
2144 CHECK(try_catch->HasCaught());
2145 String::AsciiValue str_value(try_catch->Exception());
2146 CHECK_EQ(*str_value, "uncle?");
2147 try_catch->Reset();
2148}
2149
2150
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002151THREADED_TEST(ConversionNumber) {
2152 v8::HandleScope scope;
2153 LocalContext env;
2154 // Very large number.
2155 CompileRun("var obj = Math.pow(2,32) * 1237;");
2156 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2157 CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
2158 CHECK_EQ(0, obj->ToInt32()->Value());
2159 CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned.
2160 // Large number.
2161 CompileRun("var obj = -1234567890123;");
2162 obj = env->Global()->Get(v8_str("obj"));
2163 CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
2164 CHECK_EQ(-1912276171, obj->ToInt32()->Value());
2165 CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT
2166 // Small positive integer.
2167 CompileRun("var obj = 42;");
2168 obj = env->Global()->Get(v8_str("obj"));
2169 CHECK_EQ(42.0, obj->ToNumber()->Value());
2170 CHECK_EQ(42, obj->ToInt32()->Value());
2171 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
2172 // Negative integer.
2173 CompileRun("var obj = -37;");
2174 obj = env->Global()->Get(v8_str("obj"));
2175 CHECK_EQ(-37.0, obj->ToNumber()->Value());
2176 CHECK_EQ(-37, obj->ToInt32()->Value());
2177 CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT
2178 // Positive non-int32 integer.
2179 CompileRun("var obj = 0x81234567;");
2180 obj = env->Global()->Get(v8_str("obj"));
2181 CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
2182 CHECK_EQ(-2128394905, obj->ToInt32()->Value());
2183 CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT
2184 // Fraction.
2185 CompileRun("var obj = 42.3;");
2186 obj = env->Global()->Get(v8_str("obj"));
2187 CHECK_EQ(42.3, obj->ToNumber()->Value());
2188 CHECK_EQ(42, obj->ToInt32()->Value());
2189 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
2190 // Large negative fraction.
2191 CompileRun("var obj = -5726623061.75;");
2192 obj = env->Global()->Get(v8_str("obj"));
2193 CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
2194 CHECK_EQ(-1431655765, obj->ToInt32()->Value());
2195 CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT
2196}
2197
2198
2199THREADED_TEST(isNumberType) {
2200 v8::HandleScope scope;
2201 LocalContext env;
2202 // Very large number.
2203 CompileRun("var obj = Math.pow(2,32) * 1237;");
2204 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2205 CHECK(!obj->IsInt32());
2206 CHECK(!obj->IsUint32());
2207 // Large negative number.
2208 CompileRun("var obj = -1234567890123;");
2209 obj = env->Global()->Get(v8_str("obj"));
2210 CHECK(!obj->IsInt32());
2211 CHECK(!obj->IsUint32());
2212 // Small positive integer.
2213 CompileRun("var obj = 42;");
2214 obj = env->Global()->Get(v8_str("obj"));
2215 CHECK(obj->IsInt32());
2216 CHECK(obj->IsUint32());
2217 // Negative integer.
2218 CompileRun("var obj = -37;");
2219 obj = env->Global()->Get(v8_str("obj"));
2220 CHECK(obj->IsInt32());
2221 CHECK(!obj->IsUint32());
2222 // Positive non-int32 integer.
2223 CompileRun("var obj = 0x81234567;");
2224 obj = env->Global()->Get(v8_str("obj"));
2225 CHECK(!obj->IsInt32());
2226 CHECK(obj->IsUint32());
2227 // Fraction.
2228 CompileRun("var obj = 42.3;");
2229 obj = env->Global()->Get(v8_str("obj"));
2230 CHECK(!obj->IsInt32());
2231 CHECK(!obj->IsUint32());
2232 // Large negative fraction.
2233 CompileRun("var obj = -5726623061.75;");
2234 obj = env->Global()->Get(v8_str("obj"));
2235 CHECK(!obj->IsInt32());
2236 CHECK(!obj->IsUint32());
2237}
2238
2239
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002240THREADED_TEST(ConversionException) {
2241 v8::HandleScope scope;
2242 LocalContext env;
2243 CompileRun(
2244 "function TestClass() { };"
2245 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
2246 "var obj = new TestClass();");
2247 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2248
2249 v8::TryCatch try_catch;
2250
2251 Local<Value> to_string_result = obj->ToString();
2252 CHECK(to_string_result.IsEmpty());
2253 CheckUncle(&try_catch);
2254
2255 Local<Value> to_number_result = obj->ToNumber();
2256 CHECK(to_number_result.IsEmpty());
2257 CheckUncle(&try_catch);
2258
2259 Local<Value> to_integer_result = obj->ToInteger();
2260 CHECK(to_integer_result.IsEmpty());
2261 CheckUncle(&try_catch);
2262
2263 Local<Value> to_uint32_result = obj->ToUint32();
2264 CHECK(to_uint32_result.IsEmpty());
2265 CheckUncle(&try_catch);
2266
2267 Local<Value> to_int32_result = obj->ToInt32();
2268 CHECK(to_int32_result.IsEmpty());
2269 CheckUncle(&try_catch);
2270
2271 Local<Value> to_object_result = v8::Undefined()->ToObject();
2272 CHECK(to_object_result.IsEmpty());
2273 CHECK(try_catch.HasCaught());
2274 try_catch.Reset();
2275
2276 int32_t int32_value = obj->Int32Value();
2277 CHECK_EQ(0, int32_value);
2278 CheckUncle(&try_catch);
2279
2280 uint32_t uint32_value = obj->Uint32Value();
2281 CHECK_EQ(0, uint32_value);
2282 CheckUncle(&try_catch);
2283
2284 double number_value = obj->NumberValue();
2285 CHECK_NE(0, IsNaN(number_value));
2286 CheckUncle(&try_catch);
2287
2288 int64_t integer_value = obj->IntegerValue();
2289 CHECK_EQ(0.0, static_cast<double>(integer_value));
2290 CheckUncle(&try_catch);
2291}
2292
2293
2294v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
2295 ApiTestFuzzer::Fuzz();
2296 return v8::ThrowException(v8_str("konto"));
2297}
2298
2299
ager@chromium.org8bb60582008-12-11 12:02:20 +00002300v8::Handle<Value> CCatcher(const v8::Arguments& args) {
2301 if (args.Length() < 1) return v8::Boolean::New(false);
2302 v8::HandleScope scope;
2303 v8::TryCatch try_catch;
ager@chromium.org71daaf62009-04-01 07:22:49 +00002304 Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
2305 CHECK(!try_catch.HasCaught() || result.IsEmpty());
ager@chromium.org8bb60582008-12-11 12:02:20 +00002306 return v8::Boolean::New(try_catch.HasCaught());
2307}
2308
2309
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002310THREADED_TEST(APICatch) {
2311 v8::HandleScope scope;
2312 Local<ObjectTemplate> templ = ObjectTemplate::New();
2313 templ->Set(v8_str("ThrowFromC"),
2314 v8::FunctionTemplate::New(ThrowFromC));
2315 LocalContext context(0, templ);
2316 CompileRun(
2317 "var thrown = false;"
2318 "try {"
2319 " ThrowFromC();"
2320 "} catch (e) {"
2321 " thrown = true;"
2322 "}");
2323 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
2324 CHECK(thrown->BooleanValue());
2325}
2326
2327
ager@chromium.org8bb60582008-12-11 12:02:20 +00002328THREADED_TEST(APIThrowTryCatch) {
2329 v8::HandleScope scope;
2330 Local<ObjectTemplate> templ = ObjectTemplate::New();
2331 templ->Set(v8_str("ThrowFromC"),
2332 v8::FunctionTemplate::New(ThrowFromC));
2333 LocalContext context(0, templ);
2334 v8::TryCatch try_catch;
2335 CompileRun("ThrowFromC();");
2336 CHECK(try_catch.HasCaught());
2337}
2338
2339
2340// Test that a try-finally block doesn't shadow a try-catch block
2341// when setting up an external handler.
ager@chromium.org71daaf62009-04-01 07:22:49 +00002342//
2343// BUG(271): Some of the exception propagation does not work on the
2344// ARM simulator because the simulator separates the C++ stack and the
2345// JS stack. This test therefore fails on the simulator. The test is
2346// not threaded to allow the threading tests to run on the simulator.
2347TEST(TryCatchInTryFinally) {
ager@chromium.org8bb60582008-12-11 12:02:20 +00002348 v8::HandleScope scope;
2349 Local<ObjectTemplate> templ = ObjectTemplate::New();
2350 templ->Set(v8_str("CCatcher"),
2351 v8::FunctionTemplate::New(CCatcher));
2352 LocalContext context(0, templ);
2353 Local<Value> result = CompileRun("try {"
2354 " try {"
2355 " CCatcher('throw 7;');"
2356 " } finally {"
2357 " }"
2358 "} catch (e) {"
2359 "}");
2360 CHECK(result->IsTrue());
2361}
2362
2363
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002364static void check_reference_error_message(
2365 v8::Handle<v8::Message> message,
2366 v8::Handle<v8::Value> data) {
2367 const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
2368 CHECK(message->Get()->Equals(v8_str(reference_error)));
2369}
2370
2371
2372// Test that overwritten toString methods are not invoked on uncaught
2373// exception formatting. However, they are invoked when performing
2374// normal error string conversions.
2375TEST(APIThrowMessageOverwrittenToString) {
2376 v8::HandleScope scope;
2377 v8::V8::AddMessageListener(check_reference_error_message);
2378 LocalContext context;
2379 CompileRun("ReferenceError.prototype.toString ="
2380 " function() { return 'Whoops' }");
2381 CompileRun("asdf;");
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002382 CompileRun("ReferenceError.prototype.constructor.name = void 0;");
2383 CompileRun("asdf;");
2384 CompileRun("ReferenceError.prototype.constructor = void 0;");
2385 CompileRun("asdf;");
ager@chromium.org0ee099b2011-01-25 14:06:47 +00002386 CompileRun("ReferenceError.prototype.__proto__ = new Object();");
2387 CompileRun("asdf;");
2388 CompileRun("ReferenceError.prototype = new Object();");
2389 CompileRun("asdf;");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002390 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
2391 CHECK(string->Equals(v8_str("Whoops")));
2392 v8::V8::RemoveMessageListeners(check_message);
2393}
2394
2395
ager@chromium.org8bb60582008-12-11 12:02:20 +00002396static void receive_message(v8::Handle<v8::Message> message,
2397 v8::Handle<v8::Value> data) {
ager@chromium.org71daaf62009-04-01 07:22:49 +00002398 message->Get();
ager@chromium.org8bb60582008-12-11 12:02:20 +00002399 message_received = true;
2400}
2401
2402
2403TEST(APIThrowMessage) {
2404 message_received = false;
2405 v8::HandleScope scope;
2406 v8::V8::AddMessageListener(receive_message);
2407 Local<ObjectTemplate> templ = ObjectTemplate::New();
2408 templ->Set(v8_str("ThrowFromC"),
2409 v8::FunctionTemplate::New(ThrowFromC));
2410 LocalContext context(0, templ);
2411 CompileRun("ThrowFromC();");
2412 CHECK(message_received);
2413 v8::V8::RemoveMessageListeners(check_message);
2414}
2415
2416
2417TEST(APIThrowMessageAndVerboseTryCatch) {
2418 message_received = false;
2419 v8::HandleScope scope;
2420 v8::V8::AddMessageListener(receive_message);
2421 Local<ObjectTemplate> templ = ObjectTemplate::New();
2422 templ->Set(v8_str("ThrowFromC"),
2423 v8::FunctionTemplate::New(ThrowFromC));
2424 LocalContext context(0, templ);
2425 v8::TryCatch try_catch;
2426 try_catch.SetVerbose(true);
ager@chromium.org71daaf62009-04-01 07:22:49 +00002427 Local<Value> result = CompileRun("ThrowFromC();");
ager@chromium.org8bb60582008-12-11 12:02:20 +00002428 CHECK(try_catch.HasCaught());
ager@chromium.org71daaf62009-04-01 07:22:49 +00002429 CHECK(result.IsEmpty());
ager@chromium.org8bb60582008-12-11 12:02:20 +00002430 CHECK(message_received);
2431 v8::V8::RemoveMessageListeners(check_message);
2432}
2433
2434
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002435THREADED_TEST(ExternalScriptException) {
2436 v8::HandleScope scope;
2437 Local<ObjectTemplate> templ = ObjectTemplate::New();
2438 templ->Set(v8_str("ThrowFromC"),
2439 v8::FunctionTemplate::New(ThrowFromC));
2440 LocalContext context(0, templ);
2441
2442 v8::TryCatch try_catch;
2443 Local<Script> script
2444 = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
2445 Local<Value> result = script->Run();
2446 CHECK(result.IsEmpty());
2447 CHECK(try_catch.HasCaught());
2448 String::AsciiValue exception_value(try_catch.Exception());
2449 CHECK_EQ("konto", *exception_value);
2450}
2451
2452
2453
2454v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
2455 ApiTestFuzzer::Fuzz();
2456 CHECK_EQ(4, args.Length());
2457 int count = args[0]->Int32Value();
2458 int cInterval = args[2]->Int32Value();
2459 if (count == 0) {
2460 return v8::ThrowException(v8_str("FromC"));
2461 } else {
2462 Local<v8::Object> global = Context::GetCurrent()->Global();
2463 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
2464 v8::Handle<Value> argv[] = { v8_num(count - 1),
2465 args[1],
2466 args[2],
2467 args[3] };
2468 if (count % cInterval == 0) {
2469 v8::TryCatch try_catch;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002470 Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002471 int expected = args[3]->Int32Value();
2472 if (try_catch.HasCaught()) {
2473 CHECK_EQ(expected, count);
ager@chromium.org71daaf62009-04-01 07:22:49 +00002474 CHECK(result.IsEmpty());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002475 CHECK(!i::Top::has_scheduled_exception());
2476 } else {
2477 CHECK_NE(expected, count);
2478 }
2479 return result;
2480 } else {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002481 return fun.As<Function>()->Call(global, 4, argv);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002482 }
2483 }
2484}
2485
2486
2487v8::Handle<Value> JSCheck(const v8::Arguments& args) {
2488 ApiTestFuzzer::Fuzz();
2489 CHECK_EQ(3, args.Length());
2490 bool equality = args[0]->BooleanValue();
2491 int count = args[1]->Int32Value();
2492 int expected = args[2]->Int32Value();
2493 if (equality) {
2494 CHECK_EQ(count, expected);
2495 } else {
2496 CHECK_NE(count, expected);
2497 }
2498 return v8::Undefined();
2499}
2500
2501
ager@chromium.org8bb60582008-12-11 12:02:20 +00002502THREADED_TEST(EvalInTryFinally) {
2503 v8::HandleScope scope;
2504 LocalContext context;
2505 v8::TryCatch try_catch;
2506 CompileRun("(function() {"
2507 " try {"
2508 " eval('asldkf (*&^&*^');"
2509 " } finally {"
2510 " return;"
2511 " }"
2512 "})()");
2513 CHECK(!try_catch.HasCaught());
2514}
2515
2516
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002517// This test works by making a stack of alternating JavaScript and C
2518// activations. These activations set up exception handlers with regular
2519// intervals, one interval for C activations and another for JavaScript
2520// activations. When enough activations have been created an exception is
2521// thrown and we check that the right activation catches the exception and that
2522// no other activations do. The right activation is always the topmost one with
2523// a handler, regardless of whether it is in JavaScript or C.
2524//
2525// The notation used to describe a test case looks like this:
2526//
2527// *JS[4] *C[3] @JS[2] C[1] JS[0]
2528//
2529// Each entry is an activation, either JS or C. The index is the count at that
2530// level. Stars identify activations with exception handlers, the @ identifies
2531// the exception handler that should catch the exception.
ager@chromium.org71daaf62009-04-01 07:22:49 +00002532//
2533// BUG(271): Some of the exception propagation does not work on the
2534// ARM simulator because the simulator separates the C++ stack and the
2535// JS stack. This test therefore fails on the simulator. The test is
2536// not threaded to allow the threading tests to run on the simulator.
2537TEST(ExceptionOrder) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002538 v8::HandleScope scope;
2539 Local<ObjectTemplate> templ = ObjectTemplate::New();
2540 templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
2541 templ->Set(v8_str("CThrowCountDown"),
2542 v8::FunctionTemplate::New(CThrowCountDown));
2543 LocalContext context(0, templ);
2544 CompileRun(
2545 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
2546 " if (count == 0) throw 'FromJS';"
2547 " if (count % jsInterval == 0) {"
2548 " try {"
2549 " var value = CThrowCountDown(count - 1,"
2550 " jsInterval,"
2551 " cInterval,"
2552 " expected);"
2553 " check(false, count, expected);"
2554 " return value;"
2555 " } catch (e) {"
2556 " check(true, count, expected);"
2557 " }"
2558 " } else {"
2559 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
2560 " }"
2561 "}");
2562 Local<Function> fun =
2563 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
2564
2565 const int argc = 4;
2566 // count jsInterval cInterval expected
2567
2568 // *JS[4] *C[3] @JS[2] C[1] JS[0]
2569 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
2570 fun->Call(fun, argc, a0);
2571
2572 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
2573 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
2574 fun->Call(fun, argc, a1);
2575
2576 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
2577 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
2578 fun->Call(fun, argc, a2);
2579
2580 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
2581 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
2582 fun->Call(fun, argc, a3);
2583
2584 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
2585 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
2586 fun->Call(fun, argc, a4);
2587
2588 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
2589 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
2590 fun->Call(fun, argc, a5);
2591}
2592
2593
2594v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
2595 ApiTestFuzzer::Fuzz();
2596 CHECK_EQ(1, args.Length());
2597 return v8::ThrowException(args[0]);
2598}
2599
2600
2601THREADED_TEST(ThrowValues) {
2602 v8::HandleScope scope;
2603 Local<ObjectTemplate> templ = ObjectTemplate::New();
2604 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
2605 LocalContext context(0, templ);
2606 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
2607 "function Run(obj) {"
2608 " try {"
2609 " Throw(obj);"
2610 " } catch (e) {"
2611 " return e;"
2612 " }"
2613 " return 'no exception';"
2614 "}"
2615 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
2616 CHECK_EQ(5, result->Length());
2617 CHECK(result->Get(v8::Integer::New(0))->IsString());
2618 CHECK(result->Get(v8::Integer::New(1))->IsNumber());
2619 CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
2620 CHECK(result->Get(v8::Integer::New(2))->IsNumber());
2621 CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
2622 CHECK(result->Get(v8::Integer::New(3))->IsNull());
2623 CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
2624}
2625
2626
2627THREADED_TEST(CatchZero) {
2628 v8::HandleScope scope;
2629 LocalContext context;
2630 v8::TryCatch try_catch;
2631 CHECK(!try_catch.HasCaught());
2632 Script::Compile(v8_str("throw 10"))->Run();
2633 CHECK(try_catch.HasCaught());
2634 CHECK_EQ(10, try_catch.Exception()->Int32Value());
2635 try_catch.Reset();
2636 CHECK(!try_catch.HasCaught());
2637 Script::Compile(v8_str("throw 0"))->Run();
2638 CHECK(try_catch.HasCaught());
2639 CHECK_EQ(0, try_catch.Exception()->Int32Value());
2640}
2641
2642
2643THREADED_TEST(CatchExceptionFromWith) {
2644 v8::HandleScope scope;
2645 LocalContext context;
2646 v8::TryCatch try_catch;
2647 CHECK(!try_catch.HasCaught());
2648 Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
2649 CHECK(try_catch.HasCaught());
2650}
2651
2652
2653THREADED_TEST(Equality) {
2654 v8::HandleScope scope;
2655 LocalContext context;
2656 // Check that equality works at all before relying on CHECK_EQ
2657 CHECK(v8_str("a")->Equals(v8_str("a")));
2658 CHECK(!v8_str("a")->Equals(v8_str("b")));
2659
2660 CHECK_EQ(v8_str("a"), v8_str("a"));
2661 CHECK_NE(v8_str("a"), v8_str("b"));
2662 CHECK_EQ(v8_num(1), v8_num(1));
2663 CHECK_EQ(v8_num(1.00), v8_num(1));
2664 CHECK_NE(v8_num(1), v8_num(2));
2665
2666 // Assume String is not symbol.
2667 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
2668 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
2669 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
2670 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
2671 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
2672 CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
2673 Local<Value> not_a_number = v8_num(i::OS::nan_value());
2674 CHECK(!not_a_number->StrictEquals(not_a_number));
2675 CHECK(v8::False()->StrictEquals(v8::False()));
2676 CHECK(!v8::False()->StrictEquals(v8::Undefined()));
2677
2678 v8::Handle<v8::Object> obj = v8::Object::New();
2679 v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
2680 CHECK(alias->StrictEquals(obj));
2681 alias.Dispose();
2682}
2683
2684
2685THREADED_TEST(MultiRun) {
2686 v8::HandleScope scope;
2687 LocalContext context;
2688 Local<Script> script = Script::Compile(v8_str("x"));
2689 for (int i = 0; i < 10; i++)
2690 script->Run();
2691}
2692
2693
2694static v8::Handle<Value> GetXValue(Local<String> name,
2695 const AccessorInfo& info) {
2696 ApiTestFuzzer::Fuzz();
2697 CHECK_EQ(info.Data(), v8_str("donut"));
2698 CHECK_EQ(name, v8_str("x"));
2699 return name;
2700}
2701
2702
2703THREADED_TEST(SimplePropertyRead) {
2704 v8::HandleScope scope;
2705 Local<ObjectTemplate> templ = ObjectTemplate::New();
2706 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2707 LocalContext context;
2708 context->Global()->Set(v8_str("obj"), templ->NewInstance());
2709 Local<Script> script = Script::Compile(v8_str("obj.x"));
2710 for (int i = 0; i < 10; i++) {
2711 Local<Value> result = script->Run();
2712 CHECK_EQ(result, v8_str("x"));
2713 }
2714}
2715
ager@chromium.org5c838252010-02-19 08:53:10 +00002716THREADED_TEST(DefinePropertyOnAPIAccessor) {
2717 v8::HandleScope scope;
2718 Local<ObjectTemplate> templ = ObjectTemplate::New();
2719 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2720 LocalContext context;
2721 context->Global()->Set(v8_str("obj"), templ->NewInstance());
2722
2723 // Uses getOwnPropertyDescriptor to check the configurable status
2724 Local<Script> script_desc
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002725 = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
ager@chromium.org5c838252010-02-19 08:53:10 +00002726 "obj, 'x');"
2727 "prop.configurable;"));
2728 Local<Value> result = script_desc->Run();
2729 CHECK_EQ(result->BooleanValue(), true);
2730
2731 // Redefine get - but still configurable
2732 Local<Script> script_define
2733 = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
2734 " configurable: true };"
2735 "Object.defineProperty(obj, 'x', desc);"
2736 "obj.x"));
2737 result = script_define->Run();
2738 CHECK_EQ(result, v8_num(42));
2739
2740 // Check that the accessor is still configurable
2741 result = script_desc->Run();
2742 CHECK_EQ(result->BooleanValue(), true);
2743
2744 // Redefine to a non-configurable
2745 script_define
2746 = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
2747 " configurable: false };"
2748 "Object.defineProperty(obj, 'x', desc);"
2749 "obj.x"));
2750 result = script_define->Run();
2751 CHECK_EQ(result, v8_num(43));
2752 result = script_desc->Run();
2753 CHECK_EQ(result->BooleanValue(), false);
2754
2755 // Make sure that it is not possible to redefine again
2756 v8::TryCatch try_catch;
2757 result = script_define->Run();
2758 CHECK(try_catch.HasCaught());
2759 String::AsciiValue exception_value(try_catch.Exception());
2760 CHECK_EQ(*exception_value,
2761 "TypeError: Cannot redefine property: defineProperty");
2762}
2763
2764THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
2765 v8::HandleScope scope;
2766 Local<ObjectTemplate> templ = ObjectTemplate::New();
2767 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2768 LocalContext context;
2769 context->Global()->Set(v8_str("obj"), templ->NewInstance());
2770
2771 Local<Script> script_desc = Script::Compile(v8_str("var prop ="
2772 "Object.getOwnPropertyDescriptor( "
2773 "obj, 'x');"
2774 "prop.configurable;"));
2775 Local<Value> result = script_desc->Run();
2776 CHECK_EQ(result->BooleanValue(), true);
2777
2778 Local<Script> script_define =
2779 Script::Compile(v8_str("var desc = {get: function(){return 42; },"
2780 " configurable: true };"
2781 "Object.defineProperty(obj, 'x', desc);"
2782 "obj.x"));
2783 result = script_define->Run();
2784 CHECK_EQ(result, v8_num(42));
2785
2786
2787 result = script_desc->Run();
2788 CHECK_EQ(result->BooleanValue(), true);
2789
2790
2791 script_define =
2792 Script::Compile(v8_str("var desc = {get: function(){return 43; },"
2793 " configurable: false };"
2794 "Object.defineProperty(obj, 'x', desc);"
2795 "obj.x"));
2796 result = script_define->Run();
2797 CHECK_EQ(result, v8_num(43));
2798 result = script_desc->Run();
2799
2800 CHECK_EQ(result->BooleanValue(), false);
2801
2802 v8::TryCatch try_catch;
2803 result = script_define->Run();
2804 CHECK(try_catch.HasCaught());
2805 String::AsciiValue exception_value(try_catch.Exception());
2806 CHECK_EQ(*exception_value,
2807 "TypeError: Cannot redefine property: defineProperty");
2808}
2809
2810
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002811static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
2812 char const* name) {
2813 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
2814}
ager@chromium.org5c838252010-02-19 08:53:10 +00002815
2816
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002817THREADED_TEST(DefineAPIAccessorOnObject) {
2818 v8::HandleScope scope;
2819 Local<ObjectTemplate> templ = ObjectTemplate::New();
2820 LocalContext context;
2821
2822 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
2823 CompileRun("var obj2 = {};");
2824
2825 CHECK(CompileRun("obj1.x")->IsUndefined());
2826 CHECK(CompileRun("obj2.x")->IsUndefined());
2827
2828 CHECK(GetGlobalProperty(&context, "obj1")->
2829 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2830
2831 ExpectString("obj1.x", "x");
2832 CHECK(CompileRun("obj2.x")->IsUndefined());
2833
2834 CHECK(GetGlobalProperty(&context, "obj2")->
2835 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2836
2837 ExpectString("obj1.x", "x");
2838 ExpectString("obj2.x", "x");
2839
2840 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2841 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2842
2843 CompileRun("Object.defineProperty(obj1, 'x',"
2844 "{ get: function() { return 'y'; }, configurable: true })");
2845
2846 ExpectString("obj1.x", "y");
2847 ExpectString("obj2.x", "x");
2848
2849 CompileRun("Object.defineProperty(obj2, 'x',"
2850 "{ get: function() { return 'y'; }, configurable: true })");
2851
2852 ExpectString("obj1.x", "y");
2853 ExpectString("obj2.x", "y");
2854
2855 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2856 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2857
2858 CHECK(GetGlobalProperty(&context, "obj1")->
2859 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2860 CHECK(GetGlobalProperty(&context, "obj2")->
2861 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2862
2863 ExpectString("obj1.x", "x");
2864 ExpectString("obj2.x", "x");
2865
2866 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2867 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2868
2869 // Define getters/setters, but now make them not configurable.
2870 CompileRun("Object.defineProperty(obj1, 'x',"
2871 "{ get: function() { return 'z'; }, configurable: false })");
2872 CompileRun("Object.defineProperty(obj2, 'x',"
2873 "{ get: function() { return 'z'; }, configurable: false })");
2874
2875 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2876 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2877
2878 ExpectString("obj1.x", "z");
2879 ExpectString("obj2.x", "z");
2880
2881 CHECK(!GetGlobalProperty(&context, "obj1")->
2882 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2883 CHECK(!GetGlobalProperty(&context, "obj2")->
2884 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2885
2886 ExpectString("obj1.x", "z");
2887 ExpectString("obj2.x", "z");
2888}
2889
2890
2891THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
2892 v8::HandleScope scope;
2893 Local<ObjectTemplate> templ = ObjectTemplate::New();
2894 LocalContext context;
2895
2896 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
2897 CompileRun("var obj2 = {};");
2898
2899 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
2900 v8_str("x"),
2901 GetXValue, NULL,
2902 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
2903 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
2904 v8_str("x"),
2905 GetXValue, NULL,
2906 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
2907
2908 ExpectString("obj1.x", "x");
2909 ExpectString("obj2.x", "x");
2910
2911 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2912 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2913
2914 CHECK(!GetGlobalProperty(&context, "obj1")->
2915 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2916 CHECK(!GetGlobalProperty(&context, "obj2")->
2917 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2918
2919 {
2920 v8::TryCatch try_catch;
2921 CompileRun("Object.defineProperty(obj1, 'x',"
2922 "{get: function() { return 'func'; }})");
2923 CHECK(try_catch.HasCaught());
2924 String::AsciiValue exception_value(try_catch.Exception());
2925 CHECK_EQ(*exception_value,
2926 "TypeError: Cannot redefine property: defineProperty");
2927 }
2928 {
2929 v8::TryCatch try_catch;
2930 CompileRun("Object.defineProperty(obj2, 'x',"
2931 "{get: function() { return 'func'; }})");
2932 CHECK(try_catch.HasCaught());
2933 String::AsciiValue exception_value(try_catch.Exception());
2934 CHECK_EQ(*exception_value,
2935 "TypeError: Cannot redefine property: defineProperty");
2936 }
2937}
2938
2939
2940static v8::Handle<Value> Get239Value(Local<String> name,
2941 const AccessorInfo& info) {
2942 ApiTestFuzzer::Fuzz();
2943 CHECK_EQ(info.Data(), v8_str("donut"));
2944 CHECK_EQ(name, v8_str("239"));
2945 return name;
2946}
2947
2948
2949THREADED_TEST(ElementAPIAccessor) {
2950 v8::HandleScope scope;
2951 Local<ObjectTemplate> templ = ObjectTemplate::New();
2952 LocalContext context;
2953
2954 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
2955 CompileRun("var obj2 = {};");
2956
2957 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
2958 v8_str("239"),
2959 Get239Value, NULL,
2960 v8_str("donut")));
2961 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
2962 v8_str("239"),
2963 Get239Value, NULL,
2964 v8_str("donut")));
2965
2966 ExpectString("obj1[239]", "239");
2967 ExpectString("obj2[239]", "239");
2968 ExpectString("obj1['239']", "239");
2969 ExpectString("obj2['239']", "239");
2970}
2971
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002972
2973v8::Persistent<Value> xValue;
2974
2975
2976static void SetXValue(Local<String> name,
2977 Local<Value> value,
2978 const AccessorInfo& info) {
2979 CHECK_EQ(value, v8_num(4));
2980 CHECK_EQ(info.Data(), v8_str("donut"));
2981 CHECK_EQ(name, v8_str("x"));
2982 CHECK(xValue.IsEmpty());
2983 xValue = v8::Persistent<Value>::New(value);
2984}
2985
2986
2987THREADED_TEST(SimplePropertyWrite) {
2988 v8::HandleScope scope;
2989 Local<ObjectTemplate> templ = ObjectTemplate::New();
2990 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
2991 LocalContext context;
2992 context->Global()->Set(v8_str("obj"), templ->NewInstance());
2993 Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
2994 for (int i = 0; i < 10; i++) {
2995 CHECK(xValue.IsEmpty());
2996 script->Run();
2997 CHECK_EQ(v8_num(4), xValue);
2998 xValue.Dispose();
2999 xValue = v8::Persistent<Value>();
3000 }
3001}
3002
3003
3004static v8::Handle<Value> XPropertyGetter(Local<String> property,
3005 const AccessorInfo& info) {
3006 ApiTestFuzzer::Fuzz();
3007 CHECK(info.Data()->IsUndefined());
3008 return property;
3009}
3010
3011
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003012THREADED_TEST(NamedInterceptorPropertyRead) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003013 v8::HandleScope scope;
3014 Local<ObjectTemplate> templ = ObjectTemplate::New();
3015 templ->SetNamedPropertyHandler(XPropertyGetter);
3016 LocalContext context;
3017 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3018 Local<Script> script = Script::Compile(v8_str("obj.x"));
3019 for (int i = 0; i < 10; i++) {
3020 Local<Value> result = script->Run();
3021 CHECK_EQ(result, v8_str("x"));
3022 }
3023}
3024
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003025
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00003026THREADED_TEST(NamedInterceptorDictionaryIC) {
3027 v8::HandleScope scope;
3028 Local<ObjectTemplate> templ = ObjectTemplate::New();
3029 templ->SetNamedPropertyHandler(XPropertyGetter);
3030 LocalContext context;
3031 // Create an object with a named interceptor.
3032 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
3033 Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
3034 for (int i = 0; i < 10; i++) {
3035 Local<Value> result = script->Run();
3036 CHECK_EQ(result, v8_str("x"));
3037 }
3038 // Create a slow case object and a function accessing a property in
3039 // that slow case object (with dictionary probing in generated
3040 // code). Then force object with a named interceptor into slow-case,
3041 // pass it to the function, and check that the interceptor is called
3042 // instead of accessing the local property.
3043 Local<Value> result =
3044 CompileRun("function get_x(o) { return o.x; };"
3045 "var obj = { x : 42, y : 0 };"
3046 "delete obj.y;"
3047 "for (var i = 0; i < 10; i++) get_x(obj);"
3048 "interceptor_obj.x = 42;"
3049 "interceptor_obj.y = 10;"
3050 "delete interceptor_obj.y;"
3051 "get_x(interceptor_obj)");
3052 CHECK_EQ(result, v8_str("x"));
3053}
3054
3055
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003056THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
3057 v8::HandleScope scope;
3058
3059 v8::Persistent<Context> context1 = Context::New();
3060
3061 context1->Enter();
3062 Local<ObjectTemplate> templ = ObjectTemplate::New();
3063 templ->SetNamedPropertyHandler(XPropertyGetter);
3064 // Create an object with a named interceptor.
3065 v8::Local<v8::Object> object = templ->NewInstance();
3066 context1->Global()->Set(v8_str("interceptor_obj"), object);
3067
3068 // Force the object into the slow case.
3069 CompileRun("interceptor_obj.y = 0;"
3070 "delete interceptor_obj.y;");
3071 context1->Exit();
3072
3073 {
3074 // Introduce the object into a different context.
3075 // Repeat named loads to exercise ICs.
3076 LocalContext context2;
3077 context2->Global()->Set(v8_str("interceptor_obj"), object);
3078 Local<Value> result =
3079 CompileRun("function get_x(o) { return o.x; }"
3080 "interceptor_obj.x = 42;"
3081 "for (var i=0; i != 10; i++) {"
3082 " get_x(interceptor_obj);"
3083 "}"
3084 "get_x(interceptor_obj)");
3085 // Check that the interceptor was actually invoked.
3086 CHECK_EQ(result, v8_str("x"));
3087 }
3088
3089 // Return to the original context and force some object to the slow case
3090 // to cause the NormalizedMapCache to verify.
3091 context1->Enter();
3092 CompileRun("var obj = { x : 0 }; delete obj.x;");
3093 context1->Exit();
3094
3095 context1.Dispose();
3096}
3097
3098
ager@chromium.org5c838252010-02-19 08:53:10 +00003099static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
3100 const AccessorInfo& info) {
3101 // Set x on the prototype object and do not handle the get request.
3102 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003103 proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
ager@chromium.org5c838252010-02-19 08:53:10 +00003104 return v8::Handle<Value>();
3105}
3106
3107
3108// This is a regression test for http://crbug.com/20104. Map
3109// transitions should not interfere with post interceptor lookup.
3110THREADED_TEST(NamedInterceptorMapTransitionRead) {
3111 v8::HandleScope scope;
3112 Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
3113 Local<v8::ObjectTemplate> instance_template
3114 = function_template->InstanceTemplate();
3115 instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
3116 LocalContext context;
3117 context->Global()->Set(v8_str("F"), function_template->GetFunction());
3118 // Create an instance of F and introduce a map transition for x.
3119 CompileRun("var o = new F(); o.x = 23;");
3120 // Create an instance of F and invoke the getter. The result should be 23.
3121 Local<Value> result = CompileRun("o = new F(); o.x");
3122 CHECK_EQ(result->Int32Value(), 23);
3123}
3124
3125
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003126static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
3127 const AccessorInfo& info) {
3128 ApiTestFuzzer::Fuzz();
3129 if (index == 37) {
3130 return v8::Handle<Value>(v8_num(625));
3131 }
3132 return v8::Handle<Value>();
3133}
3134
3135
3136static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
3137 Local<Value> value,
3138 const AccessorInfo& info) {
3139 ApiTestFuzzer::Fuzz();
3140 if (index == 39) {
3141 return value;
3142 }
3143 return v8::Handle<Value>();
3144}
3145
3146
3147THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
3148 v8::HandleScope scope;
3149 Local<ObjectTemplate> templ = ObjectTemplate::New();
3150 templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
3151 IndexedPropertySetter);
3152 LocalContext context;
3153 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3154 Local<Script> getter_script = Script::Compile(v8_str(
3155 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
3156 Local<Script> setter_script = Script::Compile(v8_str(
3157 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
3158 "obj[17] = 23;"
3159 "obj.foo;"));
3160 Local<Script> interceptor_setter_script = Script::Compile(v8_str(
3161 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
3162 "obj[39] = 47;"
3163 "obj.foo;")); // This setter should not run, due to the interceptor.
3164 Local<Script> interceptor_getter_script = Script::Compile(v8_str(
3165 "obj[37];"));
3166 Local<Value> result = getter_script->Run();
3167 CHECK_EQ(v8_num(5), result);
3168 result = setter_script->Run();
3169 CHECK_EQ(v8_num(23), result);
3170 result = interceptor_setter_script->Run();
3171 CHECK_EQ(v8_num(23), result);
3172 result = interceptor_getter_script->Run();
3173 CHECK_EQ(v8_num(625), result);
3174}
3175
3176
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00003177static v8::Handle<Value> IdentityIndexedPropertyGetter(
3178 uint32_t index,
3179 const AccessorInfo& info) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003180 return v8::Integer::NewFromUnsigned(index);
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00003181}
3182
3183
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003184THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
3185 v8::HandleScope scope;
3186 Local<ObjectTemplate> templ = ObjectTemplate::New();
3187 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3188
3189 LocalContext context;
3190 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3191
3192 // Check fast object case.
3193 const char* fast_case_code =
3194 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
3195 ExpectString(fast_case_code, "0");
3196
3197 // Check slow case.
3198 const char* slow_case_code =
3199 "obj.x = 1; delete obj.x;"
3200 "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
3201 ExpectString(slow_case_code, "1");
3202}
3203
3204
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00003205THREADED_TEST(IndexedInterceptorWithNoSetter) {
3206 v8::HandleScope scope;
3207 Local<ObjectTemplate> templ = ObjectTemplate::New();
3208 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3209
3210 LocalContext context;
3211 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3212
3213 const char* code =
3214 "try {"
3215 " obj[0] = 239;"
3216 " for (var i = 0; i < 100; i++) {"
3217 " var v = obj[0];"
3218 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
3219 " }"
3220 " 'PASSED'"
3221 "} catch(e) {"
3222 " e"
3223 "}";
3224 ExpectString(code, "PASSED");
3225}
3226
3227
ager@chromium.org5c838252010-02-19 08:53:10 +00003228THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
3229 v8::HandleScope scope;
3230 Local<ObjectTemplate> templ = ObjectTemplate::New();
3231 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3232
3233 LocalContext context;
3234 Local<v8::Object> obj = templ->NewInstance();
3235 obj->TurnOnAccessCheck();
3236 context->Global()->Set(v8_str("obj"), obj);
3237
3238 const char* code =
3239 "try {"
3240 " for (var i = 0; i < 100; i++) {"
3241 " var v = obj[0];"
3242 " if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
3243 " }"
3244 " 'PASSED'"
3245 "} catch(e) {"
3246 " e"
3247 "}";
3248 ExpectString(code, "PASSED");
3249}
3250
3251
3252THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
3253 i::FLAG_allow_natives_syntax = true;
3254 v8::HandleScope scope;
3255 Local<ObjectTemplate> templ = ObjectTemplate::New();
3256 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3257
3258 LocalContext context;
3259 Local<v8::Object> obj = templ->NewInstance();
3260 context->Global()->Set(v8_str("obj"), obj);
3261
3262 const char* code =
3263 "try {"
3264 " for (var i = 0; i < 100; i++) {"
3265 " var expected = i;"
3266 " if (i == 5) {"
3267 " %EnableAccessChecks(obj);"
3268 " expected = undefined;"
3269 " }"
3270 " var v = obj[i];"
3271 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3272 " if (i == 5) %DisableAccessChecks(obj);"
3273 " }"
3274 " 'PASSED'"
3275 "} catch(e) {"
3276 " e"
3277 "}";
3278 ExpectString(code, "PASSED");
3279}
3280
3281
3282THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
3283 v8::HandleScope scope;
3284 Local<ObjectTemplate> templ = ObjectTemplate::New();
3285 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3286
3287 LocalContext context;
3288 Local<v8::Object> obj = templ->NewInstance();
3289 context->Global()->Set(v8_str("obj"), obj);
3290
3291 const char* code =
3292 "try {"
3293 " for (var i = 0; i < 100; i++) {"
3294 " var v = obj[i];"
3295 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
3296 " }"
3297 " 'PASSED'"
3298 "} catch(e) {"
3299 " e"
3300 "}";
3301 ExpectString(code, "PASSED");
3302}
3303
3304
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003305THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
3306 v8::HandleScope scope;
3307 Local<ObjectTemplate> templ = ObjectTemplate::New();
3308 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3309
3310 LocalContext context;
3311 Local<v8::Object> obj = templ->NewInstance();
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 expected = i;"
3318 " var key = i;"
3319 " if (i == 25) {"
3320 " key = -1;"
3321 " expected = undefined;"
3322 " }"
3323 " if (i == 50) {"
3324 " /* probe minimal Smi number on 32-bit platforms */"
3325 " key = -(1 << 30);"
3326 " expected = undefined;"
3327 " }"
3328 " if (i == 75) {"
3329 " /* probe minimal Smi number on 64-bit platforms */"
3330 " key = 1 << 31;"
3331 " expected = undefined;"
3332 " }"
3333 " var v = obj[key];"
3334 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3335 " }"
3336 " 'PASSED'"
3337 "} catch(e) {"
3338 " e"
3339 "}";
3340 ExpectString(code, "PASSED");
3341}
3342
3343
ager@chromium.org5c838252010-02-19 08:53:10 +00003344THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
3345 v8::HandleScope scope;
3346 Local<ObjectTemplate> templ = ObjectTemplate::New();
3347 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3348
3349 LocalContext context;
3350 Local<v8::Object> obj = templ->NewInstance();
3351 context->Global()->Set(v8_str("obj"), obj);
3352
3353 const char* code =
3354 "try {"
3355 " for (var i = 0; i < 100; i++) {"
3356 " var expected = i;"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003357 " var key = i;"
ager@chromium.org5c838252010-02-19 08:53:10 +00003358 " if (i == 50) {"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003359 " key = 'foobar';"
ager@chromium.org5c838252010-02-19 08:53:10 +00003360 " expected = undefined;"
3361 " }"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003362 " var v = obj[key];"
ager@chromium.org5c838252010-02-19 08:53:10 +00003363 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3364 " }"
3365 " 'PASSED'"
3366 "} catch(e) {"
3367 " e"
3368 "}";
3369 ExpectString(code, "PASSED");
3370}
3371
3372
3373THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
3374 v8::HandleScope scope;
3375 Local<ObjectTemplate> templ = ObjectTemplate::New();
3376 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3377
3378 LocalContext context;
3379 Local<v8::Object> obj = templ->NewInstance();
3380 context->Global()->Set(v8_str("obj"), obj);
3381
3382 const char* code =
3383 "var original = obj;"
3384 "try {"
3385 " for (var i = 0; i < 100; i++) {"
3386 " var expected = i;"
3387 " if (i == 50) {"
3388 " obj = {50: 'foobar'};"
3389 " expected = 'foobar';"
3390 " }"
3391 " var v = obj[i];"
3392 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3393 " if (i == 50) obj = original;"
3394 " }"
3395 " 'PASSED'"
3396 "} catch(e) {"
3397 " e"
3398 "}";
3399 ExpectString(code, "PASSED");
3400}
3401
3402
3403THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
3404 v8::HandleScope scope;
3405 Local<ObjectTemplate> templ = ObjectTemplate::New();
3406 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3407
3408 LocalContext context;
3409 Local<v8::Object> obj = templ->NewInstance();
3410 context->Global()->Set(v8_str("obj"), obj);
3411
3412 const char* code =
3413 "var original = obj;"
3414 "try {"
3415 " for (var i = 0; i < 100; i++) {"
3416 " var expected = i;"
3417 " if (i == 5) {"
3418 " obj = 239;"
3419 " expected = undefined;"
3420 " }"
3421 " var v = obj[i];"
3422 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3423 " if (i == 5) obj = original;"
3424 " }"
3425 " 'PASSED'"
3426 "} catch(e) {"
3427 " e"
3428 "}";
3429 ExpectString(code, "PASSED");
3430}
3431
3432
3433THREADED_TEST(IndexedInterceptorOnProto) {
3434 v8::HandleScope scope;
3435 Local<ObjectTemplate> templ = ObjectTemplate::New();
3436 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3437
3438 LocalContext context;
3439 Local<v8::Object> obj = templ->NewInstance();
3440 context->Global()->Set(v8_str("obj"), obj);
3441
3442 const char* code =
3443 "var o = {__proto__: obj};"
3444 "try {"
3445 " for (var i = 0; i < 100; i++) {"
3446 " var v = o[i];"
3447 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
3448 " }"
3449 " 'PASSED'"
3450 "} catch(e) {"
3451 " e"
3452 "}";
3453 ExpectString(code, "PASSED");
3454}
3455
3456
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003457THREADED_TEST(MultiContexts) {
3458 v8::HandleScope scope;
3459 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
3460 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
3461
3462 Local<String> password = v8_str("Password");
3463
3464 // Create an environment
3465 LocalContext context0(0, templ);
3466 context0->SetSecurityToken(password);
3467 v8::Handle<v8::Object> global0 = context0->Global();
3468 global0->Set(v8_str("custom"), v8_num(1234));
3469 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
3470
3471 // Create an independent environment
3472 LocalContext context1(0, templ);
3473 context1->SetSecurityToken(password);
3474 v8::Handle<v8::Object> global1 = context1->Global();
3475 global1->Set(v8_str("custom"), v8_num(1234));
3476 CHECK_NE(global0, global1);
3477 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
3478 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
3479
3480 // Now create a new context with the old global
3481 LocalContext context2(0, templ, global1);
3482 context2->SetSecurityToken(password);
3483 v8::Handle<v8::Object> global2 = context2->Global();
3484 CHECK_EQ(global1, global2);
3485 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
3486 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
3487}
3488
3489
3490THREADED_TEST(FunctionPrototypeAcrossContexts) {
3491 // Make sure that functions created by cloning boilerplates cannot
3492 // communicate through their __proto__ field.
3493
3494 v8::HandleScope scope;
3495
3496 LocalContext env0;
3497 v8::Handle<v8::Object> global0 =
3498 env0->Global();
3499 v8::Handle<v8::Object> object0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003500 global0->Get(v8_str("Object")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003501 v8::Handle<v8::Object> tostring0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003502 object0->Get(v8_str("toString")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003503 v8::Handle<v8::Object> proto0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003504 tostring0->Get(v8_str("__proto__")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003505 proto0->Set(v8_str("custom"), v8_num(1234));
3506
3507 LocalContext env1;
3508 v8::Handle<v8::Object> global1 =
3509 env1->Global();
3510 v8::Handle<v8::Object> object1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003511 global1->Get(v8_str("Object")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003512 v8::Handle<v8::Object> tostring1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003513 object1->Get(v8_str("toString")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003514 v8::Handle<v8::Object> proto1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003515 tostring1->Get(v8_str("__proto__")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003516 CHECK(!proto1->Has(v8_str("custom")));
3517}
3518
3519
3520THREADED_TEST(Regress892105) {
3521 // Make sure that object and array literals created by cloning
3522 // boilerplates cannot communicate through their __proto__
3523 // field. This is rather difficult to check, but we try to add stuff
3524 // to Object.prototype and Array.prototype and create a new
3525 // environment. This should succeed.
3526
3527 v8::HandleScope scope;
3528
3529 Local<String> source = v8_str("Object.prototype.obj = 1234;"
3530 "Array.prototype.arr = 4567;"
3531 "8901");
3532
3533 LocalContext env0;
3534 Local<Script> script0 = Script::Compile(source);
3535 CHECK_EQ(8901.0, script0->Run()->NumberValue());
3536
3537 LocalContext env1;
3538 Local<Script> script1 = Script::Compile(source);
3539 CHECK_EQ(8901.0, script1->Run()->NumberValue());
3540}
3541
3542
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003543THREADED_TEST(UndetectableObject) {
3544 v8::HandleScope scope;
3545 LocalContext env;
3546
3547 Local<v8::FunctionTemplate> desc =
3548 v8::FunctionTemplate::New(0, v8::Handle<Value>());
3549 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
3550
3551 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
3552 env->Global()->Set(v8_str("undetectable"), obj);
3553
3554 ExpectString("undetectable.toString()", "[object Object]");
3555 ExpectString("typeof undetectable", "undefined");
3556 ExpectString("typeof(undetectable)", "undefined");
3557 ExpectBoolean("typeof undetectable == 'undefined'", true);
3558 ExpectBoolean("typeof undetectable == 'object'", false);
3559 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
3560 ExpectBoolean("!undetectable", true);
3561
3562 ExpectObject("true&&undetectable", obj);
3563 ExpectBoolean("false&&undetectable", false);
3564 ExpectBoolean("true||undetectable", true);
3565 ExpectObject("false||undetectable", obj);
3566
3567 ExpectObject("undetectable&&true", obj);
3568 ExpectObject("undetectable&&false", obj);
3569 ExpectBoolean("undetectable||true", true);
3570 ExpectBoolean("undetectable||false", false);
3571
3572 ExpectBoolean("undetectable==null", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00003573 ExpectBoolean("null==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003574 ExpectBoolean("undetectable==undefined", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00003575 ExpectBoolean("undefined==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003576 ExpectBoolean("undetectable==undetectable", true);
3577
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00003578
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003579 ExpectBoolean("undetectable===null", false);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00003580 ExpectBoolean("null===undetectable", false);
3581 ExpectBoolean("undetectable===undefined", false);
3582 ExpectBoolean("undefined===undetectable", false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003583 ExpectBoolean("undetectable===undetectable", true);
3584}
3585
3586
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00003587
3588THREADED_TEST(ExtensibleOnUndetectable) {
3589 v8::HandleScope scope;
3590 LocalContext env;
3591
3592 Local<v8::FunctionTemplate> desc =
3593 v8::FunctionTemplate::New(0, v8::Handle<Value>());
3594 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
3595
3596 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
3597 env->Global()->Set(v8_str("undetectable"), obj);
3598
3599 Local<String> source = v8_str("undetectable.x = 42;"
3600 "undetectable.x");
3601
3602 Local<Script> script = Script::Compile(source);
3603
3604 CHECK_EQ(v8::Integer::New(42), script->Run());
3605
3606 ExpectBoolean("Object.isExtensible(undetectable)", true);
3607
3608 source = v8_str("Object.preventExtensions(undetectable);");
3609 script = Script::Compile(source);
3610 script->Run();
3611 ExpectBoolean("Object.isExtensible(undetectable)", false);
3612
3613 source = v8_str("undetectable.y = 2000;");
3614 script = Script::Compile(source);
3615 v8::TryCatch try_catch;
3616 Local<Value> result = script->Run();
3617 CHECK(result.IsEmpty());
3618 CHECK(try_catch.HasCaught());
3619}
3620
3621
3622
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003623THREADED_TEST(UndetectableString) {
3624 v8::HandleScope scope;
3625 LocalContext env;
3626
3627 Local<String> obj = String::NewUndetectable("foo");
3628 env->Global()->Set(v8_str("undetectable"), obj);
3629
3630 ExpectString("undetectable", "foo");
3631 ExpectString("typeof undetectable", "undefined");
3632 ExpectString("typeof(undetectable)", "undefined");
3633 ExpectBoolean("typeof undetectable == 'undefined'", true);
3634 ExpectBoolean("typeof undetectable == 'string'", 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
3663template <typename T> static void USE(T) { }
3664
3665
3666// This test is not intended to be run, just type checked.
3667static void PersistentHandles() {
3668 USE(PersistentHandles);
3669 Local<String> str = v8_str("foo");
3670 v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
3671 USE(p_str);
3672 Local<Script> scr = Script::Compile(v8_str(""));
3673 v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
3674 USE(p_scr);
3675 Local<ObjectTemplate> templ = ObjectTemplate::New();
3676 v8::Persistent<ObjectTemplate> p_templ =
3677 v8::Persistent<ObjectTemplate>::New(templ);
3678 USE(p_templ);
3679}
3680
3681
3682static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
3683 ApiTestFuzzer::Fuzz();
3684 return v8::Undefined();
3685}
3686
3687
3688THREADED_TEST(GlobalObjectTemplate) {
3689 v8::HandleScope handle_scope;
3690 Local<ObjectTemplate> global_template = ObjectTemplate::New();
3691 global_template->Set(v8_str("JSNI_Log"),
3692 v8::FunctionTemplate::New(HandleLogDelegator));
3693 v8::Persistent<Context> context = Context::New(0, global_template);
3694 Context::Scope context_scope(context);
3695 Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
3696 context.Dispose();
3697}
3698
3699
3700static const char* kSimpleExtensionSource =
3701 "function Foo() {"
3702 " return 4;"
3703 "}";
3704
3705
3706THREADED_TEST(SimpleExtensions) {
3707 v8::HandleScope handle_scope;
3708 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
3709 const char* extension_names[] = { "simpletest" };
3710 v8::ExtensionConfiguration extensions(1, extension_names);
3711 v8::Handle<Context> context = Context::New(&extensions);
3712 Context::Scope lock(context);
3713 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
3714 CHECK_EQ(result, v8::Integer::New(4));
3715}
3716
3717
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003718static const char* kEvalExtensionSource1 =
3719 "function UseEval1() {"
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00003720 " var x = 42;"
3721 " return eval('x');"
3722 "}";
3723
3724
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003725static const char* kEvalExtensionSource2 =
3726 "(function() {"
3727 " var x = 42;"
3728 " function e() {"
3729 " return eval('x');"
3730 " }"
3731 " this.UseEval2 = e;"
3732 "})()";
3733
3734
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00003735THREADED_TEST(UseEvalFromExtension) {
3736 v8::HandleScope handle_scope;
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003737 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
3738 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
3739 const char* extension_names[] = { "evaltest1", "evaltest2" };
3740 v8::ExtensionConfiguration extensions(2, extension_names);
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00003741 v8::Handle<Context> context = Context::New(&extensions);
3742 Context::Scope lock(context);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003743 v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
3744 CHECK_EQ(result, v8::Integer::New(42));
3745 result = Script::Compile(v8_str("UseEval2()"))->Run();
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00003746 CHECK_EQ(result, v8::Integer::New(42));
3747}
3748
3749
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003750static const char* kWithExtensionSource1 =
3751 "function UseWith1() {"
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00003752 " var x = 42;"
3753 " with({x:87}) { return x; }"
3754 "}";
3755
3756
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003757
3758static const char* kWithExtensionSource2 =
3759 "(function() {"
3760 " var x = 42;"
3761 " function e() {"
3762 " with ({x:87}) { return x; }"
3763 " }"
3764 " this.UseWith2 = e;"
3765 "})()";
3766
3767
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00003768THREADED_TEST(UseWithFromExtension) {
3769 v8::HandleScope handle_scope;
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003770 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
3771 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
3772 const char* extension_names[] = { "withtest1", "withtest2" };
3773 v8::ExtensionConfiguration extensions(2, extension_names);
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00003774 v8::Handle<Context> context = Context::New(&extensions);
3775 Context::Scope lock(context);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003776 v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
3777 CHECK_EQ(result, v8::Integer::New(87));
3778 result = Script::Compile(v8_str("UseWith2()"))->Run();
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00003779 CHECK_EQ(result, v8::Integer::New(87));
3780}
3781
3782
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003783THREADED_TEST(AutoExtensions) {
3784 v8::HandleScope handle_scope;
3785 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
3786 extension->set_auto_enable(true);
3787 v8::RegisterExtension(extension);
3788 v8::Handle<Context> context = Context::New();
3789 Context::Scope lock(context);
3790 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
3791 CHECK_EQ(result, v8::Integer::New(4));
3792}
3793
3794
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003795static const char* kSyntaxErrorInExtensionSource =
3796 "[";
3797
3798
3799// Test that a syntax error in an extension does not cause a fatal
3800// error but results in an empty context.
3801THREADED_TEST(SyntaxErrorExtensions) {
3802 v8::HandleScope handle_scope;
3803 v8::RegisterExtension(new Extension("syntaxerror",
3804 kSyntaxErrorInExtensionSource));
3805 const char* extension_names[] = { "syntaxerror" };
3806 v8::ExtensionConfiguration extensions(1, extension_names);
3807 v8::Handle<Context> context = Context::New(&extensions);
3808 CHECK(context.IsEmpty());
3809}
3810
3811
3812static const char* kExceptionInExtensionSource =
3813 "throw 42";
3814
3815
3816// Test that an exception when installing an extension does not cause
3817// a fatal error but results in an empty context.
3818THREADED_TEST(ExceptionExtensions) {
3819 v8::HandleScope handle_scope;
3820 v8::RegisterExtension(new Extension("exception",
3821 kExceptionInExtensionSource));
3822 const char* extension_names[] = { "exception" };
3823 v8::ExtensionConfiguration extensions(1, extension_names);
3824 v8::Handle<Context> context = Context::New(&extensions);
3825 CHECK(context.IsEmpty());
3826}
3827
3828
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00003829static const char* kNativeCallInExtensionSource =
3830 "function call_runtime_last_index_of(x) {"
3831 " return %StringLastIndexOf(x, 'bob', 10);"
3832 "}";
3833
3834
3835static const char* kNativeCallTest =
3836 "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
3837
3838// Test that a native runtime calls are supported in extensions.
3839THREADED_TEST(NativeCallInExtensions) {
3840 v8::HandleScope handle_scope;
3841 v8::RegisterExtension(new Extension("nativecall",
3842 kNativeCallInExtensionSource));
3843 const char* extension_names[] = { "nativecall" };
3844 v8::ExtensionConfiguration extensions(1, extension_names);
3845 v8::Handle<Context> context = Context::New(&extensions);
3846 Context::Scope lock(context);
3847 v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run();
3848 CHECK_EQ(result, v8::Integer::New(3));
3849}
3850
3851
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003852static void CheckDependencies(const char* name, const char* expected) {
3853 v8::HandleScope handle_scope;
3854 v8::ExtensionConfiguration config(1, &name);
3855 LocalContext context(&config);
3856 CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
3857}
3858
3859
3860/*
3861 * Configuration:
3862 *
3863 * /-- B <--\
3864 * A <- -- D <-- E
3865 * \-- C <--/
3866 */
3867THREADED_TEST(ExtensionDependency) {
3868 static const char* kEDeps[] = { "D" };
3869 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
3870 static const char* kDDeps[] = { "B", "C" };
3871 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
3872 static const char* kBCDeps[] = { "A" };
3873 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
3874 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
3875 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
3876 CheckDependencies("A", "undefinedA");
3877 CheckDependencies("B", "undefinedAB");
3878 CheckDependencies("C", "undefinedAC");
3879 CheckDependencies("D", "undefinedABCD");
3880 CheckDependencies("E", "undefinedABCDE");
3881 v8::HandleScope handle_scope;
3882 static const char* exts[2] = { "C", "E" };
3883 v8::ExtensionConfiguration config(2, exts);
3884 LocalContext context(&config);
3885 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
3886}
3887
3888
3889static const char* kExtensionTestScript =
3890 "native function A();"
3891 "native function B();"
3892 "native function C();"
3893 "function Foo(i) {"
3894 " if (i == 0) return A();"
3895 " if (i == 1) return B();"
3896 " if (i == 2) return C();"
3897 "}";
3898
3899
3900static v8::Handle<Value> CallFun(const v8::Arguments& args) {
3901 ApiTestFuzzer::Fuzz();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003902 if (args.IsConstructCall()) {
3903 args.This()->Set(v8_str("data"), args.Data());
3904 return v8::Null();
3905 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003906 return args.Data();
3907}
3908
3909
3910class FunctionExtension : public Extension {
3911 public:
3912 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
3913 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
3914 v8::Handle<String> name);
3915};
3916
3917
3918static int lookup_count = 0;
3919v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
3920 v8::Handle<String> name) {
3921 lookup_count++;
3922 if (name->Equals(v8_str("A"))) {
3923 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
3924 } else if (name->Equals(v8_str("B"))) {
3925 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
3926 } else if (name->Equals(v8_str("C"))) {
3927 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
3928 } else {
3929 return v8::Handle<v8::FunctionTemplate>();
3930 }
3931}
3932
3933
3934THREADED_TEST(FunctionLookup) {
3935 v8::RegisterExtension(new FunctionExtension());
3936 v8::HandleScope handle_scope;
3937 static const char* exts[1] = { "functiontest" };
3938 v8::ExtensionConfiguration config(1, exts);
3939 LocalContext context(&config);
3940 CHECK_EQ(3, lookup_count);
3941 CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
3942 CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
3943 CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
3944}
3945
3946
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003947THREADED_TEST(NativeFunctionConstructCall) {
3948 v8::RegisterExtension(new FunctionExtension());
3949 v8::HandleScope handle_scope;
3950 static const char* exts[1] = { "functiontest" };
3951 v8::ExtensionConfiguration config(1, exts);
3952 LocalContext context(&config);
3953 for (int i = 0; i < 10; i++) {
3954 // Run a few times to ensure that allocation of objects doesn't
3955 // change behavior of a constructor function.
3956 CHECK_EQ(v8::Integer::New(8),
3957 Script::Compile(v8_str("(new A()).data"))->Run());
3958 CHECK_EQ(v8::Integer::New(7),
3959 Script::Compile(v8_str("(new B()).data"))->Run());
3960 CHECK_EQ(v8::Integer::New(6),
3961 Script::Compile(v8_str("(new C()).data"))->Run());
3962 }
3963}
3964
3965
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003966static const char* last_location;
3967static const char* last_message;
3968void StoringErrorCallback(const char* location, const char* message) {
3969 if (last_location == NULL) {
3970 last_location = location;
3971 last_message = message;
3972 }
3973}
3974
3975
3976// ErrorReporting creates a circular extensions configuration and
3977// tests that the fatal error handler gets called. This renders V8
3978// unusable and therefore this test cannot be run in parallel.
3979TEST(ErrorReporting) {
3980 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
3981 static const char* aDeps[] = { "B" };
3982 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
3983 static const char* bDeps[] = { "A" };
3984 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
3985 last_location = NULL;
3986 v8::ExtensionConfiguration config(1, bDeps);
3987 v8::Handle<Context> context = Context::New(&config);
3988 CHECK(context.IsEmpty());
3989 CHECK_NE(last_location, NULL);
3990}
3991
3992
ager@chromium.org7c537e22008-10-16 08:43:32 +00003993static const char* js_code_causing_huge_string_flattening =
3994 "var str = 'X';"
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00003995 "for (var i = 0; i < 30; i++) {"
ager@chromium.org7c537e22008-10-16 08:43:32 +00003996 " str = str + str;"
3997 "}"
3998 "str.match(/X/);";
3999
4000
4001void OOMCallback(const char* location, const char* message) {
4002 exit(0);
4003}
4004
4005
4006TEST(RegexpOutOfMemory) {
4007 // Execute a script that causes out of memory when flattening a string.
4008 v8::HandleScope scope;
4009 v8::V8::SetFatalErrorHandler(OOMCallback);
4010 LocalContext context;
4011 Local<Script> script =
4012 Script::Compile(String::New(js_code_causing_huge_string_flattening));
4013 last_location = NULL;
4014 Local<Value> result = script->Run();
4015
4016 CHECK(false); // Should not return.
4017}
4018
4019
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004020static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
4021 v8::Handle<Value> data) {
4022 CHECK_EQ(v8::Undefined(), data);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004023 CHECK(message->GetScriptResourceName()->IsUndefined());
4024 CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004025 message->GetLineNumber();
4026 message->GetSourceLine();
4027}
4028
4029
4030THREADED_TEST(ErrorWithMissingScriptInfo) {
4031 v8::HandleScope scope;
4032 LocalContext context;
4033 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
4034 Script::Compile(v8_str("throw Error()"))->Run();
4035 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
4036}
4037
4038
4039int global_index = 0;
4040
4041class Snorkel {
4042 public:
4043 Snorkel() { index_ = global_index++; }
4044 int index_;
4045};
4046
4047class Whammy {
4048 public:
4049 Whammy() {
4050 cursor_ = 0;
4051 }
4052 ~Whammy() {
4053 script_.Dispose();
4054 }
4055 v8::Handle<Script> getScript() {
4056 if (script_.IsEmpty())
4057 script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
4058 return Local<Script>(*script_);
4059 }
4060
4061 public:
4062 static const int kObjectCount = 256;
4063 int cursor_;
4064 v8::Persistent<v8::Object> objects_[kObjectCount];
4065 v8::Persistent<Script> script_;
4066};
4067
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004068static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004069 Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
4070 delete snorkel;
4071 obj.ClearWeak();
4072}
4073
4074v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
4075 const AccessorInfo& info) {
4076 Whammy* whammy =
4077 static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
4078
4079 v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
4080
4081 v8::Handle<v8::Object> obj = v8::Object::New();
4082 v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
4083 if (!prev.IsEmpty()) {
4084 prev->Set(v8_str("next"), obj);
4085 prev.MakeWeak(new Snorkel(), &HandleWeakReference);
4086 whammy->objects_[whammy->cursor_].Clear();
4087 }
4088 whammy->objects_[whammy->cursor_] = global;
4089 whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
4090 return whammy->getScript()->Run();
4091}
4092
4093THREADED_TEST(WeakReference) {
4094 v8::HandleScope handle_scope;
4095 v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00004096 Whammy* whammy = new Whammy();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004097 templ->SetNamedPropertyHandler(WhammyPropertyGetter,
4098 0, 0, 0, 0,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00004099 v8::External::New(whammy));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004100 const char* extension_list[] = { "v8/gc" };
4101 v8::ExtensionConfiguration extensions(1, extension_list);
4102 v8::Persistent<Context> context = Context::New(&extensions);
4103 Context::Scope context_scope(context);
4104
4105 v8::Handle<v8::Object> interceptor = templ->NewInstance();
4106 context->Global()->Set(v8_str("whammy"), interceptor);
4107 const char* code =
4108 "var last;"
4109 "for (var i = 0; i < 10000; i++) {"
4110 " var obj = whammy.length;"
4111 " if (last) last.next = obj;"
4112 " last = obj;"
4113 "}"
4114 "gc();"
4115 "4";
4116 v8::Handle<Value> result = CompileRun(code);
4117 CHECK_EQ(4.0, result->NumberValue());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00004118 delete whammy;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004119 context.Dispose();
4120}
4121
4122
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004123static bool in_scavenge = false;
4124static int last = -1;
4125
4126static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
4127 CHECK_EQ(-1, last);
4128 last = 0;
4129 obj.Dispose();
4130 obj.Clear();
4131 in_scavenge = true;
4132 i::Heap::PerformScavenge();
4133 in_scavenge = false;
4134 *(reinterpret_cast<bool*>(data)) = true;
4135}
4136
4137static void CheckIsNotInvokedInScavenge(v8::Persistent<v8::Value> obj,
4138 void* data) {
4139 CHECK_EQ(0, last);
4140 last = 1;
4141 *(reinterpret_cast<bool*>(data)) = in_scavenge;
4142 obj.Dispose();
4143 obj.Clear();
4144}
4145
4146THREADED_TEST(NoWeakRefCallbacksInScavenge) {
4147 // Test verifies that scavenge cannot invoke WeakReferenceCallbacks.
4148 // Calling callbacks from scavenges is unsafe as objects held by those
4149 // handlers might have become strongly reachable, but scavenge doesn't
4150 // check that.
4151 v8::Persistent<Context> context = Context::New();
4152 Context::Scope context_scope(context);
4153
4154 v8::Persistent<v8::Object> object_a;
4155 v8::Persistent<v8::Object> object_b;
4156
4157 {
4158 v8::HandleScope handle_scope;
4159 object_b = v8::Persistent<v8::Object>::New(v8::Object::New());
4160 object_a = v8::Persistent<v8::Object>::New(v8::Object::New());
4161 }
4162
4163 bool object_a_disposed = false;
4164 object_a.MakeWeak(&object_a_disposed, &ForceScavenge);
4165 bool released_in_scavenge = false;
4166 object_b.MakeWeak(&released_in_scavenge, &CheckIsNotInvokedInScavenge);
4167
4168 while (!object_a_disposed) {
4169 i::Heap::CollectAllGarbage(false);
4170 }
4171 CHECK(!released_in_scavenge);
4172}
4173
4174
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004175v8::Handle<Function> args_fun;
4176
4177
4178static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
4179 ApiTestFuzzer::Fuzz();
4180 CHECK_EQ(args_fun, args.Callee());
4181 CHECK_EQ(3, args.Length());
4182 CHECK_EQ(v8::Integer::New(1), args[0]);
4183 CHECK_EQ(v8::Integer::New(2), args[1]);
4184 CHECK_EQ(v8::Integer::New(3), args[2]);
4185 CHECK_EQ(v8::Undefined(), args[3]);
4186 v8::HandleScope scope;
ager@chromium.orgab99eea2009-08-25 07:05:41 +00004187 i::Heap::CollectAllGarbage(false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004188 return v8::Undefined();
4189}
4190
4191
4192THREADED_TEST(Arguments) {
4193 v8::HandleScope scope;
4194 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
4195 global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
4196 LocalContext context(NULL, global);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004197 args_fun = context->Global()->Get(v8_str("f")).As<Function>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004198 v8_compile("f(1, 2, 3)")->Run();
4199}
4200
4201
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004202static v8::Handle<Value> NoBlockGetterX(Local<String> name,
4203 const AccessorInfo&) {
4204 return v8::Handle<Value>();
4205}
4206
4207
4208static v8::Handle<Value> NoBlockGetterI(uint32_t index,
4209 const AccessorInfo&) {
4210 return v8::Handle<Value>();
4211}
4212
4213
4214static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
4215 const AccessorInfo&) {
4216 if (!name->Equals(v8_str("foo"))) {
4217 return v8::Handle<v8::Boolean>(); // not intercepted
4218 }
4219
4220 return v8::False(); // intercepted, and don't delete the property
4221}
4222
4223
4224static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
4225 if (index != 2) {
4226 return v8::Handle<v8::Boolean>(); // not intercepted
4227 }
4228
4229 return v8::False(); // intercepted, and don't delete the property
4230}
4231
4232
4233THREADED_TEST(Deleter) {
4234 v8::HandleScope scope;
4235 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4236 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
4237 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
4238 LocalContext context;
4239 context->Global()->Set(v8_str("k"), obj->NewInstance());
4240 CompileRun(
4241 "k.foo = 'foo';"
4242 "k.bar = 'bar';"
4243 "k[2] = 2;"
4244 "k[4] = 4;");
4245 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
4246 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
4247
4248 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
4249 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
4250
4251 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
4252 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
4253
4254 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
4255 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
4256}
4257
4258
4259static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
4260 ApiTestFuzzer::Fuzz();
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004261 if (name->Equals(v8_str("foo")) ||
4262 name->Equals(v8_str("bar")) ||
4263 name->Equals(v8_str("baz"))) {
4264 return v8::Undefined();
4265 }
4266 return v8::Handle<Value>();
4267}
4268
4269
4270static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
4271 ApiTestFuzzer::Fuzz();
4272 if (index == 0 || index == 1) return v8::Undefined();
4273 return v8::Handle<Value>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004274}
4275
4276
4277static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
4278 ApiTestFuzzer::Fuzz();
4279 v8::Handle<v8::Array> result = v8::Array::New(3);
4280 result->Set(v8::Integer::New(0), v8_str("foo"));
4281 result->Set(v8::Integer::New(1), v8_str("bar"));
4282 result->Set(v8::Integer::New(2), v8_str("baz"));
4283 return result;
4284}
4285
4286
4287static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
4288 ApiTestFuzzer::Fuzz();
4289 v8::Handle<v8::Array> result = v8::Array::New(2);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004290 result->Set(v8::Integer::New(0), v8_str("0"));
4291 result->Set(v8::Integer::New(1), v8_str("1"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004292 return result;
4293}
4294
4295
4296THREADED_TEST(Enumerators) {
4297 v8::HandleScope scope;
4298 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4299 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004300 obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004301 LocalContext context;
4302 context->Global()->Set(v8_str("k"), obj->NewInstance());
4303 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004304 "k[10] = 0;"
4305 "k.a = 0;"
4306 "k[5] = 0;"
4307 "k.b = 0;"
4308 "k[4294967295] = 0;"
4309 "k.c = 0;"
4310 "k[4294967296] = 0;"
4311 "k.d = 0;"
4312 "k[140000] = 0;"
4313 "k.e = 0;"
4314 "k[30000000000] = 0;"
4315 "k.f = 0;"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004316 "var result = [];"
4317 "for (var prop in k) {"
4318 " result.push(prop);"
4319 "}"
4320 "result"));
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004321 // Check that we get all the property names returned including the
4322 // ones from the enumerators in the right order: indexed properties
4323 // in numerical order, indexed interceptor properties, named
4324 // properties in insertion order, named interceptor properties.
4325 // This order is not mandated by the spec, so this test is just
4326 // documenting our behavior.
4327 CHECK_EQ(17, result->Length());
4328 // Indexed properties in numerical order.
4329 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
4330 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
4331 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
4332 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
4333 // Indexed interceptor properties in the order they are returned
4334 // from the enumerator interceptor.
4335 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
4336 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
4337 // Named properties in insertion order.
4338 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
4339 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
4340 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
4341 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
4342 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
4343 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
4344 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
4345 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
4346 // Named interceptor properties.
4347 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
4348 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
4349 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004350}
4351
4352
4353int p_getter_count;
4354int p_getter_count2;
4355
4356
4357static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
4358 ApiTestFuzzer::Fuzz();
4359 p_getter_count++;
4360 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
4361 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
4362 if (name->Equals(v8_str("p1"))) {
4363 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
4364 } else if (name->Equals(v8_str("p2"))) {
4365 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
4366 } else if (name->Equals(v8_str("p3"))) {
4367 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
4368 } else if (name->Equals(v8_str("p4"))) {
4369 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
4370 }
4371 return v8::Undefined();
4372}
4373
4374
4375static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
4376 ApiTestFuzzer::Fuzz();
4377 LocalContext context;
4378 context->Global()->Set(v8_str("o1"), obj->NewInstance());
4379 CompileRun(
4380 "o1.__proto__ = { };"
4381 "var o2 = { __proto__: o1 };"
4382 "var o3 = { __proto__: o2 };"
4383 "var o4 = { __proto__: o3 };"
4384 "for (var i = 0; i < 10; i++) o4.p4;"
4385 "for (var i = 0; i < 10; i++) o3.p3;"
4386 "for (var i = 0; i < 10; i++) o2.p2;"
4387 "for (var i = 0; i < 10; i++) o1.p1;");
4388}
4389
4390
4391static v8::Handle<Value> PGetter2(Local<String> name,
4392 const AccessorInfo& info) {
4393 ApiTestFuzzer::Fuzz();
4394 p_getter_count2++;
4395 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
4396 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
4397 if (name->Equals(v8_str("p1"))) {
4398 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
4399 } else if (name->Equals(v8_str("p2"))) {
4400 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
4401 } else if (name->Equals(v8_str("p3"))) {
4402 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
4403 } else if (name->Equals(v8_str("p4"))) {
4404 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
4405 }
4406 return v8::Undefined();
4407}
4408
4409
4410THREADED_TEST(GetterHolders) {
4411 v8::HandleScope scope;
4412 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4413 obj->SetAccessor(v8_str("p1"), PGetter);
4414 obj->SetAccessor(v8_str("p2"), PGetter);
4415 obj->SetAccessor(v8_str("p3"), PGetter);
4416 obj->SetAccessor(v8_str("p4"), PGetter);
4417 p_getter_count = 0;
4418 RunHolderTest(obj);
4419 CHECK_EQ(40, p_getter_count);
4420}
4421
4422
4423THREADED_TEST(PreInterceptorHolders) {
4424 v8::HandleScope scope;
4425 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4426 obj->SetNamedPropertyHandler(PGetter2);
4427 p_getter_count2 = 0;
4428 RunHolderTest(obj);
4429 CHECK_EQ(40, p_getter_count2);
4430}
4431
4432
4433THREADED_TEST(ObjectInstantiation) {
4434 v8::HandleScope scope;
4435 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
4436 templ->SetAccessor(v8_str("t"), PGetter2);
4437 LocalContext context;
4438 context->Global()->Set(v8_str("o"), templ->NewInstance());
4439 for (int i = 0; i < 100; i++) {
4440 v8::HandleScope inner_scope;
4441 v8::Handle<v8::Object> obj = templ->NewInstance();
4442 CHECK_NE(obj, context->Global()->Get(v8_str("o")));
4443 context->Global()->Set(v8_str("o2"), obj);
4444 v8::Handle<Value> value =
4445 Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
4446 CHECK_EQ(v8::True(), value);
4447 context->Global()->Set(v8_str("o"), obj);
4448 }
4449}
4450
4451
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004452static int StrCmp16(uint16_t* a, uint16_t* b) {
4453 while (true) {
4454 if (*a == 0 && *b == 0) return 0;
4455 if (*a != *b) return 0 + *a - *b;
4456 a++;
4457 b++;
4458 }
4459}
4460
4461
4462static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
4463 while (true) {
4464 if (n-- == 0) return 0;
4465 if (*a == 0 && *b == 0) return 0;
4466 if (*a != *b) return 0 + *a - *b;
4467 a++;
4468 b++;
4469 }
4470}
4471
4472
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004473THREADED_TEST(StringWrite) {
4474 v8::HandleScope scope;
4475 v8::Handle<String> str = v8_str("abcde");
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004476 // abc<Icelandic eth><Unicode snowman>.
4477 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
4478
4479 CHECK_EQ(5, str2->Length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004480
4481 char buf[100];
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004482 char utf8buf[100];
4483 uint16_t wbuf[100];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004484 int len;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004485 int charlen;
4486
4487 memset(utf8buf, 0x1, sizeof(utf8buf));
4488 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
4489 CHECK_EQ(len, 9);
4490 CHECK_EQ(charlen, 5);
4491 CHECK_EQ(strcmp(utf8buf, "abc\303\260\342\230\203"), 0);
4492
4493 memset(utf8buf, 0x1, sizeof(utf8buf));
4494 len = str2->WriteUtf8(utf8buf, 8, &charlen);
4495 CHECK_EQ(len, 8);
4496 CHECK_EQ(charlen, 5);
4497 CHECK_EQ(strncmp(utf8buf, "abc\303\260\342\230\203\1", 9), 0);
4498
4499 memset(utf8buf, 0x1, sizeof(utf8buf));
4500 len = str2->WriteUtf8(utf8buf, 7, &charlen);
4501 CHECK_EQ(len, 5);
4502 CHECK_EQ(charlen, 4);
4503 CHECK_EQ(strncmp(utf8buf, "abc\303\260\1", 5), 0);
4504
4505 memset(utf8buf, 0x1, sizeof(utf8buf));
4506 len = str2->WriteUtf8(utf8buf, 6, &charlen);
4507 CHECK_EQ(len, 5);
4508 CHECK_EQ(charlen, 4);
4509 CHECK_EQ(strncmp(utf8buf, "abc\303\260\1", 5), 0);
4510
4511 memset(utf8buf, 0x1, sizeof(utf8buf));
4512 len = str2->WriteUtf8(utf8buf, 5, &charlen);
4513 CHECK_EQ(len, 5);
4514 CHECK_EQ(charlen, 4);
4515 CHECK_EQ(strncmp(utf8buf, "abc\303\260\1", 5), 0);
4516
4517 memset(utf8buf, 0x1, sizeof(utf8buf));
4518 len = str2->WriteUtf8(utf8buf, 4, &charlen);
4519 CHECK_EQ(len, 3);
4520 CHECK_EQ(charlen, 3);
4521 CHECK_EQ(strncmp(utf8buf, "abc\1", 4), 0);
4522
4523 memset(utf8buf, 0x1, sizeof(utf8buf));
4524 len = str2->WriteUtf8(utf8buf, 3, &charlen);
4525 CHECK_EQ(len, 3);
4526 CHECK_EQ(charlen, 3);
4527 CHECK_EQ(strncmp(utf8buf, "abc\1", 4), 0);
4528
4529 memset(utf8buf, 0x1, sizeof(utf8buf));
4530 len = str2->WriteUtf8(utf8buf, 2, &charlen);
4531 CHECK_EQ(len, 2);
4532 CHECK_EQ(charlen, 2);
4533 CHECK_EQ(strncmp(utf8buf, "ab\1", 3), 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004534
4535 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004536 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004537 len = str->WriteAscii(buf);
4538 CHECK_EQ(len, 5);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004539 len = str->Write(wbuf);
4540 CHECK_EQ(len, 5);
4541 CHECK_EQ(strcmp("abcde", buf), 0);
4542 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
4543 CHECK_EQ(StrCmp16(answer1, wbuf), 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004544
4545 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004546 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004547 len = str->WriteAscii(buf, 0, 4);
4548 CHECK_EQ(len, 4);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004549 len = str->Write(wbuf, 0, 4);
4550 CHECK_EQ(len, 4);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004551 CHECK_EQ(strncmp("abcd\1", buf, 5), 0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004552 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
4553 CHECK_EQ(StrNCmp16(answer2, wbuf, 5), 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004554
4555 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004556 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004557 len = str->WriteAscii(buf, 0, 5);
4558 CHECK_EQ(len, 5);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004559 len = str->Write(wbuf, 0, 5);
4560 CHECK_EQ(len, 5);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004561 CHECK_EQ(strncmp("abcde\1", buf, 6), 0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004562 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
4563 CHECK_EQ(StrNCmp16(answer3, wbuf, 6), 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004564
4565 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004566 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004567 len = str->WriteAscii(buf, 0, 6);
4568 CHECK_EQ(len, 5);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004569 len = str->Write(wbuf, 0, 6);
4570 CHECK_EQ(len, 5);
4571 CHECK_EQ(strcmp("abcde", buf), 0);
4572 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
4573 CHECK_EQ(StrCmp16(answer4, wbuf), 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004574
4575 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004576 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004577 len = str->WriteAscii(buf, 4, -1);
4578 CHECK_EQ(len, 1);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004579 len = str->Write(wbuf, 4, -1);
4580 CHECK_EQ(len, 1);
4581 CHECK_EQ(strcmp("e", buf), 0);
4582 uint16_t answer5[] = {'e', '\0'};
4583 CHECK_EQ(StrCmp16(answer5, wbuf), 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004584
4585 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004586 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004587 len = str->WriteAscii(buf, 4, 6);
4588 CHECK_EQ(len, 1);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004589 len = str->Write(wbuf, 4, 6);
4590 CHECK_EQ(len, 1);
4591 CHECK_EQ(strcmp("e", buf), 0);
4592 CHECK_EQ(StrCmp16(answer5, wbuf), 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004593
4594 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004595 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004596 len = str->WriteAscii(buf, 4, 1);
4597 CHECK_EQ(len, 1);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004598 len = str->Write(wbuf, 4, 1);
4599 CHECK_EQ(len, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004600 CHECK_EQ(strncmp("e\1", buf, 2), 0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004601 uint16_t answer6[] = {'e', 0x101};
4602 CHECK_EQ(StrNCmp16(answer6, wbuf, 2), 0);
4603
4604 memset(buf, 0x1, sizeof(buf));
4605 memset(wbuf, 0x1, sizeof(wbuf));
4606 len = str->WriteAscii(buf, 3, 1);
4607 CHECK_EQ(len, 1);
4608 len = str->Write(wbuf, 3, 1);
4609 CHECK_EQ(len, 1);
4610 CHECK_EQ(strncmp("d\1", buf, 2), 0);
4611 uint16_t answer7[] = {'d', 0x101};
4612 CHECK_EQ(StrNCmp16(answer7, wbuf, 2), 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004613}
4614
4615
4616THREADED_TEST(ToArrayIndex) {
4617 v8::HandleScope scope;
4618 LocalContext context;
4619
4620 v8::Handle<String> str = v8_str("42");
4621 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
4622 CHECK(!index.IsEmpty());
4623 CHECK_EQ(42.0, index->Uint32Value());
4624 str = v8_str("42asdf");
4625 index = str->ToArrayIndex();
4626 CHECK(index.IsEmpty());
4627 str = v8_str("-42");
4628 index = str->ToArrayIndex();
4629 CHECK(index.IsEmpty());
4630 str = v8_str("4294967295");
4631 index = str->ToArrayIndex();
4632 CHECK(!index.IsEmpty());
4633 CHECK_EQ(4294967295.0, index->Uint32Value());
4634 v8::Handle<v8::Number> num = v8::Number::New(1);
4635 index = num->ToArrayIndex();
4636 CHECK(!index.IsEmpty());
4637 CHECK_EQ(1.0, index->Uint32Value());
4638 num = v8::Number::New(-1);
4639 index = num->ToArrayIndex();
4640 CHECK(index.IsEmpty());
4641 v8::Handle<v8::Object> obj = v8::Object::New();
4642 index = obj->ToArrayIndex();
4643 CHECK(index.IsEmpty());
4644}
4645
4646
4647THREADED_TEST(ErrorConstruction) {
4648 v8::HandleScope scope;
4649 LocalContext context;
4650
4651 v8::Handle<String> foo = v8_str("foo");
4652 v8::Handle<String> message = v8_str("message");
4653 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
4654 CHECK(range_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004655 v8::Handle<v8::Object> range_obj = range_error.As<v8::Object>();
4656 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004657 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
4658 CHECK(reference_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004659 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004660 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
4661 CHECK(syntax_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004662 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004663 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
4664 CHECK(type_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004665 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004666 v8::Handle<Value> error = v8::Exception::Error(foo);
4667 CHECK(error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004668 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004669}
4670
4671
4672static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
4673 ApiTestFuzzer::Fuzz();
4674 return v8_num(10);
4675}
4676
4677
4678static void YSetter(Local<String> name,
4679 Local<Value> value,
4680 const AccessorInfo& info) {
4681 if (info.This()->Has(name)) {
4682 info.This()->Delete(name);
4683 }
4684 info.This()->Set(name, value);
4685}
4686
4687
4688THREADED_TEST(DeleteAccessor) {
4689 v8::HandleScope scope;
4690 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4691 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
4692 LocalContext context;
4693 v8::Handle<v8::Object> holder = obj->NewInstance();
4694 context->Global()->Set(v8_str("holder"), holder);
4695 v8::Handle<Value> result = CompileRun(
4696 "holder.y = 11; holder.y = 12; holder.y");
4697 CHECK_EQ(12, result->Uint32Value());
4698}
4699
4700
4701THREADED_TEST(TypeSwitch) {
4702 v8::HandleScope scope;
4703 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
4704 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
4705 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
4706 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
4707 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
4708 LocalContext context;
4709 v8::Handle<v8::Object> obj0 = v8::Object::New();
4710 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
4711 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
4712 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
4713 for (int i = 0; i < 10; i++) {
4714 CHECK_EQ(0, type_switch->match(obj0));
4715 CHECK_EQ(1, type_switch->match(obj1));
4716 CHECK_EQ(2, type_switch->match(obj2));
4717 CHECK_EQ(3, type_switch->match(obj3));
4718 CHECK_EQ(3, type_switch->match(obj3));
4719 CHECK_EQ(2, type_switch->match(obj2));
4720 CHECK_EQ(1, type_switch->match(obj1));
4721 CHECK_EQ(0, type_switch->match(obj0));
4722 }
4723}
4724
4725
4726// For use within the TestSecurityHandler() test.
4727static bool g_security_callback_result = false;
4728static bool NamedSecurityTestCallback(Local<v8::Object> global,
4729 Local<Value> name,
4730 v8::AccessType type,
4731 Local<Value> data) {
4732 // Always allow read access.
4733 if (type == v8::ACCESS_GET)
4734 return true;
4735
4736 // Sometimes allow other access.
4737 return g_security_callback_result;
4738}
4739
4740
4741static bool IndexedSecurityTestCallback(Local<v8::Object> global,
4742 uint32_t key,
4743 v8::AccessType type,
4744 Local<Value> data) {
4745 // Always allow read access.
4746 if (type == v8::ACCESS_GET)
4747 return true;
4748
4749 // Sometimes allow other access.
4750 return g_security_callback_result;
4751}
4752
4753
4754static int trouble_nesting = 0;
4755static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
4756 ApiTestFuzzer::Fuzz();
4757 trouble_nesting++;
4758
4759 // Call a JS function that throws an uncaught exception.
4760 Local<v8::Object> arg_this = Context::GetCurrent()->Global();
4761 Local<Value> trouble_callee = (trouble_nesting == 3) ?
4762 arg_this->Get(v8_str("trouble_callee")) :
4763 arg_this->Get(v8_str("trouble_caller"));
4764 CHECK(trouble_callee->IsFunction());
4765 return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
4766}
4767
4768
4769static int report_count = 0;
4770static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
4771 v8::Handle<Value>) {
4772 report_count++;
4773}
4774
4775
4776// Counts uncaught exceptions, but other tests running in parallel
4777// also have uncaught exceptions.
4778TEST(ApiUncaughtException) {
ager@chromium.org8bb60582008-12-11 12:02:20 +00004779 report_count = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004780 v8::HandleScope scope;
4781 LocalContext env;
4782 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
4783
4784 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
4785 v8::Local<v8::Object> global = env->Global();
4786 global->Set(v8_str("trouble"), fun->GetFunction());
4787
4788 Script::Compile(v8_str("function trouble_callee() {"
4789 " var x = null;"
4790 " return x.foo;"
4791 "};"
4792 "function trouble_caller() {"
4793 " trouble();"
4794 "};"))->Run();
4795 Local<Value> trouble = global->Get(v8_str("trouble"));
4796 CHECK(trouble->IsFunction());
4797 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
4798 CHECK(trouble_callee->IsFunction());
4799 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
4800 CHECK(trouble_caller->IsFunction());
4801 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
4802 CHECK_EQ(1, report_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00004803 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
4804}
4805
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004806static const char* script_resource_name = "ExceptionInNativeScript.js";
4807static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
4808 v8::Handle<Value>) {
4809 v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
4810 CHECK(!name_val.IsEmpty() && name_val->IsString());
4811 v8::String::AsciiValue name(message->GetScriptResourceName());
4812 CHECK_EQ(script_resource_name, *name);
4813 CHECK_EQ(3, message->GetLineNumber());
4814 v8::String::AsciiValue source_line(message->GetSourceLine());
4815 CHECK_EQ(" new o.foo();", *source_line);
4816}
4817
4818TEST(ExceptionInNativeScript) {
4819 v8::HandleScope scope;
4820 LocalContext env;
4821 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
4822
4823 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
4824 v8::Local<v8::Object> global = env->Global();
4825 global->Set(v8_str("trouble"), fun->GetFunction());
4826
4827 Script::Compile(v8_str("function trouble() {\n"
4828 " var o = {};\n"
4829 " new o.foo();\n"
4830 "};"), v8::String::New(script_resource_name))->Run();
4831 Local<Value> trouble = global->Get(v8_str("trouble"));
4832 CHECK(trouble->IsFunction());
4833 Function::Cast(*trouble)->Call(global, 0, NULL);
4834 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
4835}
4836
ager@chromium.org8bb60582008-12-11 12:02:20 +00004837
4838TEST(CompilationErrorUsingTryCatchHandler) {
4839 v8::HandleScope scope;
4840 LocalContext env;
4841 v8::TryCatch try_catch;
4842 Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
4843 CHECK_NE(NULL, *try_catch.Exception());
4844 CHECK(try_catch.HasCaught());
4845}
4846
4847
4848TEST(TryCatchFinallyUsingTryCatchHandler) {
4849 v8::HandleScope scope;
4850 LocalContext env;
4851 v8::TryCatch try_catch;
4852 Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
4853 CHECK(!try_catch.HasCaught());
4854 Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
4855 CHECK(try_catch.HasCaught());
4856 try_catch.Reset();
4857 Script::Compile(v8_str("(function() {"
4858 "try { throw ''; } finally { return; }"
4859 "})()"))->Run();
4860 CHECK(!try_catch.HasCaught());
4861 Script::Compile(v8_str("(function()"
4862 " { try { throw ''; } finally { throw 0; }"
4863 "})()"))->Run();
4864 CHECK(try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004865}
4866
4867
4868// SecurityHandler can't be run twice
4869TEST(SecurityHandler) {
4870 v8::HandleScope scope0;
4871 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
4872 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
4873 IndexedSecurityTestCallback);
4874 // Create an environment
4875 v8::Persistent<Context> context0 =
4876 Context::New(NULL, global_template);
4877 context0->Enter();
4878
4879 v8::Handle<v8::Object> global0 = context0->Global();
4880 v8::Handle<Script> script0 = v8_compile("foo = 111");
4881 script0->Run();
4882 global0->Set(v8_str("0"), v8_num(999));
4883 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
4884 CHECK_EQ(111, foo0->Int32Value());
4885 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
4886 CHECK_EQ(999, z0->Int32Value());
4887
4888 // Create another environment, should fail security checks.
4889 v8::HandleScope scope1;
4890
4891 v8::Persistent<Context> context1 =
4892 Context::New(NULL, global_template);
4893 context1->Enter();
4894
4895 v8::Handle<v8::Object> global1 = context1->Global();
4896 global1->Set(v8_str("othercontext"), global0);
4897 // This set will fail the security check.
4898 v8::Handle<Script> script1 =
4899 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
4900 script1->Run();
4901 // This read will pass the security check.
4902 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
4903 CHECK_EQ(111, foo1->Int32Value());
4904 // This read will pass the security check.
4905 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
4906 CHECK_EQ(999, z1->Int32Value());
4907
4908 // Create another environment, should pass security checks.
4909 { g_security_callback_result = true; // allow security handler to pass.
4910 v8::HandleScope scope2;
4911 LocalContext context2;
4912 v8::Handle<v8::Object> global2 = context2->Global();
4913 global2->Set(v8_str("othercontext"), global0);
4914 v8::Handle<Script> script2 =
4915 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
4916 script2->Run();
4917 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
4918 CHECK_EQ(333, foo2->Int32Value());
4919 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
4920 CHECK_EQ(888, z2->Int32Value());
4921 }
4922
4923 context1->Exit();
4924 context1.Dispose();
4925
4926 context0->Exit();
4927 context0.Dispose();
4928}
4929
4930
4931THREADED_TEST(SecurityChecks) {
4932 v8::HandleScope handle_scope;
4933 LocalContext env1;
4934 v8::Persistent<Context> env2 = Context::New();
4935
4936 Local<Value> foo = v8_str("foo");
4937 Local<Value> bar = v8_str("bar");
4938
4939 // Set to the same domain.
4940 env1->SetSecurityToken(foo);
4941
4942 // Create a function in env1.
4943 Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
4944 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
4945 CHECK(spy->IsFunction());
4946
4947 // Create another function accessing global objects.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004948 Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004949 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
4950 CHECK(spy2->IsFunction());
4951
4952 // Switch to env2 in the same domain and invoke spy on env2.
4953 {
4954 env2->SetSecurityToken(foo);
4955 // Enter env2
4956 Context::Scope scope_env2(env2);
4957 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
4958 CHECK(result->IsFunction());
4959 }
4960
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004961 {
4962 env2->SetSecurityToken(bar);
4963 Context::Scope scope_env2(env2);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004964
4965 // Call cross_domain_call, it should throw an exception
4966 v8::TryCatch try_catch;
4967 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
4968 CHECK(try_catch.HasCaught());
4969 }
4970
4971 env2.Dispose();
4972}
4973
4974
4975// Regression test case for issue 1183439.
4976THREADED_TEST(SecurityChecksForPrototypeChain) {
4977 v8::HandleScope scope;
4978 LocalContext current;
4979 v8::Persistent<Context> other = Context::New();
4980
4981 // Change context to be able to get to the Object function in the
4982 // other context without hitting the security checks.
4983 v8::Local<Value> other_object;
4984 { Context::Scope scope(other);
4985 other_object = other->Global()->Get(v8_str("Object"));
4986 other->Global()->Set(v8_num(42), v8_num(87));
4987 }
4988
4989 current->Global()->Set(v8_str("other"), other->Global());
4990 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
4991
4992 // Make sure the security check fails here and we get an undefined
4993 // result instead of getting the Object function. Repeat in a loop
4994 // to make sure to exercise the IC code.
4995 v8::Local<Script> access_other0 = v8_compile("other.Object");
4996 v8::Local<Script> access_other1 = v8_compile("other[42]");
4997 for (int i = 0; i < 5; i++) {
4998 CHECK(!access_other0->Run()->Equals(other_object));
4999 CHECK(access_other0->Run()->IsUndefined());
5000 CHECK(!access_other1->Run()->Equals(v8_num(87)));
5001 CHECK(access_other1->Run()->IsUndefined());
5002 }
5003
5004 // Create an object that has 'other' in its prototype chain and make
5005 // sure we cannot access the Object function indirectly through
5006 // that. Repeat in a loop to make sure to exercise the IC code.
5007 v8_compile("function F() { };"
5008 "F.prototype = other;"
5009 "var f = new F();")->Run();
5010 v8::Local<Script> access_f0 = v8_compile("f.Object");
5011 v8::Local<Script> access_f1 = v8_compile("f[42]");
5012 for (int j = 0; j < 5; j++) {
5013 CHECK(!access_f0->Run()->Equals(other_object));
5014 CHECK(access_f0->Run()->IsUndefined());
5015 CHECK(!access_f1->Run()->Equals(v8_num(87)));
5016 CHECK(access_f1->Run()->IsUndefined());
5017 }
5018
5019 // Now it gets hairy: Set the prototype for the other global object
5020 // to be the current global object. The prototype chain for 'f' now
5021 // goes through 'other' but ends up in the current global object.
5022 { Context::Scope scope(other);
5023 other->Global()->Set(v8_str("__proto__"), current->Global());
5024 }
5025 // Set a named and an index property on the current global
5026 // object. To force the lookup to go through the other global object,
5027 // the properties must not exist in the other global object.
5028 current->Global()->Set(v8_str("foo"), v8_num(100));
5029 current->Global()->Set(v8_num(99), v8_num(101));
5030 // Try to read the properties from f and make sure that the access
5031 // gets stopped by the security checks on the other global object.
5032 Local<Script> access_f2 = v8_compile("f.foo");
5033 Local<Script> access_f3 = v8_compile("f[99]");
5034 for (int k = 0; k < 5; k++) {
5035 CHECK(!access_f2->Run()->Equals(v8_num(100)));
5036 CHECK(access_f2->Run()->IsUndefined());
5037 CHECK(!access_f3->Run()->Equals(v8_num(101)));
5038 CHECK(access_f3->Run()->IsUndefined());
5039 }
5040 other.Dispose();
5041}
5042
5043
5044THREADED_TEST(CrossDomainDelete) {
5045 v8::HandleScope handle_scope;
5046 LocalContext env1;
5047 v8::Persistent<Context> env2 = Context::New();
5048
5049 Local<Value> foo = v8_str("foo");
5050 Local<Value> bar = v8_str("bar");
5051
5052 // Set to the same domain.
5053 env1->SetSecurityToken(foo);
5054 env2->SetSecurityToken(foo);
5055
5056 env1->Global()->Set(v8_str("prop"), v8_num(3));
5057 env2->Global()->Set(v8_str("env1"), env1->Global());
5058
5059 // Change env2 to a different domain and delete env1.prop.
5060 env2->SetSecurityToken(bar);
5061 {
5062 Context::Scope scope_env2(env2);
5063 Local<Value> result =
5064 Script::Compile(v8_str("delete env1.prop"))->Run();
5065 CHECK(result->IsFalse());
5066 }
5067
5068 // Check that env1.prop still exists.
5069 Local<Value> v = env1->Global()->Get(v8_str("prop"));
5070 CHECK(v->IsNumber());
5071 CHECK_EQ(3, v->Int32Value());
5072
5073 env2.Dispose();
5074}
5075
5076
ager@chromium.org870a0b62008-11-04 11:43:05 +00005077THREADED_TEST(CrossDomainIsPropertyEnumerable) {
5078 v8::HandleScope handle_scope;
5079 LocalContext env1;
5080 v8::Persistent<Context> env2 = Context::New();
5081
5082 Local<Value> foo = v8_str("foo");
5083 Local<Value> bar = v8_str("bar");
5084
5085 // Set to the same domain.
5086 env1->SetSecurityToken(foo);
5087 env2->SetSecurityToken(foo);
5088
5089 env1->Global()->Set(v8_str("prop"), v8_num(3));
5090 env2->Global()->Set(v8_str("env1"), env1->Global());
5091
5092 // env1.prop is enumerable in env2.
5093 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
5094 {
5095 Context::Scope scope_env2(env2);
5096 Local<Value> result = Script::Compile(test)->Run();
5097 CHECK(result->IsTrue());
5098 }
5099
5100 // Change env2 to a different domain and test again.
5101 env2->SetSecurityToken(bar);
5102 {
5103 Context::Scope scope_env2(env2);
5104 Local<Value> result = Script::Compile(test)->Run();
5105 CHECK(result->IsFalse());
5106 }
5107
5108 env2.Dispose();
5109}
5110
5111
ager@chromium.org236ad962008-09-25 09:45:57 +00005112THREADED_TEST(CrossDomainForIn) {
5113 v8::HandleScope handle_scope;
5114 LocalContext env1;
5115 v8::Persistent<Context> env2 = Context::New();
5116
5117 Local<Value> foo = v8_str("foo");
5118 Local<Value> bar = v8_str("bar");
5119
5120 // Set to the same domain.
5121 env1->SetSecurityToken(foo);
5122 env2->SetSecurityToken(foo);
5123
5124 env1->Global()->Set(v8_str("prop"), v8_num(3));
5125 env2->Global()->Set(v8_str("env1"), env1->Global());
5126
5127 // Change env2 to a different domain and set env1's global object
5128 // as the __proto__ of an object in env2 and enumerate properties
5129 // in for-in. It shouldn't enumerate properties on env1's global
5130 // object.
5131 env2->SetSecurityToken(bar);
5132 {
5133 Context::Scope scope_env2(env2);
5134 Local<Value> result =
5135 CompileRun("(function(){var obj = {'__proto__':env1};"
5136 "for (var p in obj)"
5137 " if (p == 'prop') return false;"
5138 "return true;})()");
5139 CHECK(result->IsTrue());
5140 }
5141 env2.Dispose();
5142}
5143
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005144
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005145TEST(ContextDetachGlobal) {
5146 v8::HandleScope handle_scope;
5147 LocalContext env1;
5148 v8::Persistent<Context> env2 = Context::New();
5149
5150 Local<v8::Object> global1 = env1->Global();
5151
5152 Local<Value> foo = v8_str("foo");
5153
5154 // Set to the same domain.
5155 env1->SetSecurityToken(foo);
5156 env2->SetSecurityToken(foo);
5157
5158 // Enter env2
5159 env2->Enter();
5160
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00005161 // Create a function in env2 and add a reference to it in env1.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005162 Local<v8::Object> global2 = env2->Global();
5163 global2->Set(v8_str("prop"), v8::Integer::New(1));
5164 CompileRun("function getProp() {return prop;}");
5165
5166 env1->Global()->Set(v8_str("getProp"),
5167 global2->Get(v8_str("getProp")));
5168
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00005169 // Detach env2's global, and reuse the global object of env2
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005170 env2->Exit();
5171 env2->DetachGlobal();
5172 // env2 has a new global object.
5173 CHECK(!env2->Global()->Equals(global2));
5174
5175 v8::Persistent<Context> env3 =
5176 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
5177 env3->SetSecurityToken(v8_str("bar"));
5178 env3->Enter();
5179
5180 Local<v8::Object> global3 = env3->Global();
5181 CHECK_EQ(global2, global3);
5182 CHECK(global3->Get(v8_str("prop"))->IsUndefined());
5183 CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
5184 global3->Set(v8_str("prop"), v8::Integer::New(-1));
5185 global3->Set(v8_str("prop2"), v8::Integer::New(2));
5186 env3->Exit();
5187
5188 // Call getProp in env1, and it should return the value 1
5189 {
5190 Local<Value> get_prop = global1->Get(v8_str("getProp"));
5191 CHECK(get_prop->IsFunction());
5192 v8::TryCatch try_catch;
5193 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
5194 CHECK(!try_catch.HasCaught());
5195 CHECK_EQ(1, r->Int32Value());
5196 }
5197
5198 // Check that env3 is not accessible from env1
5199 {
5200 Local<Value> r = global3->Get(v8_str("prop2"));
5201 CHECK(r->IsUndefined());
5202 }
5203
5204 env2.Dispose();
5205 env3.Dispose();
5206}
5207
5208
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00005209TEST(DetachAndReattachGlobal) {
5210 v8::HandleScope scope;
5211 LocalContext env1;
5212
5213 // Create second environment.
5214 v8::Persistent<Context> env2 = Context::New();
5215
5216 Local<Value> foo = v8_str("foo");
5217
5218 // Set same security token for env1 and env2.
5219 env1->SetSecurityToken(foo);
5220 env2->SetSecurityToken(foo);
5221
5222 // Create a property on the global object in env2.
5223 {
5224 v8::Context::Scope scope(env2);
5225 env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
5226 }
5227
5228 // Create a reference to env2 global from env1 global.
5229 env1->Global()->Set(v8_str("other"), env2->Global());
5230
5231 // Check that we have access to other.p in env2 from env1.
5232 Local<Value> result = CompileRun("other.p");
5233 CHECK(result->IsInt32());
5234 CHECK_EQ(42, result->Int32Value());
5235
5236 // Hold on to global from env2 and detach global from env2.
5237 Local<v8::Object> global2 = env2->Global();
5238 env2->DetachGlobal();
5239
5240 // Check that the global has been detached. No other.p property can
5241 // be found.
5242 result = CompileRun("other.p");
5243 CHECK(result->IsUndefined());
5244
5245 // Reuse global2 for env3.
5246 v8::Persistent<Context> env3 =
5247 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
5248 CHECK_EQ(global2, env3->Global());
5249
5250 // Start by using the same security token for env3 as for env1 and env2.
5251 env3->SetSecurityToken(foo);
5252
5253 // Create a property on the global object in env3.
5254 {
5255 v8::Context::Scope scope(env3);
5256 env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
5257 }
5258
5259 // Check that other.p is now the property in env3 and that we have access.
5260 result = CompileRun("other.p");
5261 CHECK(result->IsInt32());
5262 CHECK_EQ(24, result->Int32Value());
5263
5264 // Change security token for env3 to something different from env1 and env2.
5265 env3->SetSecurityToken(v8_str("bar"));
5266
5267 // Check that we do not have access to other.p in env1. |other| is now
5268 // the global object for env3 which has a different security token,
5269 // so access should be blocked.
5270 result = CompileRun("other.p");
5271 CHECK(result->IsUndefined());
5272
5273 // Detach the global for env3 and reattach it to env2.
5274 env3->DetachGlobal();
5275 env2->ReattachGlobal(global2);
5276
5277 // Check that we have access to other.p again in env1. |other| is now
5278 // the global object for env2 which has the same security token as env1.
5279 result = CompileRun("other.p");
5280 CHECK(result->IsInt32());
5281 CHECK_EQ(42, result->Int32Value());
5282
5283 env2.Dispose();
5284 env3.Dispose();
5285}
5286
5287
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005288static bool NamedAccessBlocker(Local<v8::Object> global,
5289 Local<Value> name,
5290 v8::AccessType type,
5291 Local<Value> data) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005292 return Context::GetCurrent()->Global()->Equals(global);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005293}
5294
5295
5296static bool IndexedAccessBlocker(Local<v8::Object> global,
5297 uint32_t key,
5298 v8::AccessType type,
5299 Local<Value> data) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005300 return Context::GetCurrent()->Global()->Equals(global);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005301}
5302
5303
5304static int g_echo_value = -1;
5305static v8::Handle<Value> EchoGetter(Local<String> name,
5306 const AccessorInfo& info) {
5307 return v8_num(g_echo_value);
5308}
5309
5310
5311static void EchoSetter(Local<String> name,
5312 Local<Value> value,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005313 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005314 if (value->IsNumber())
5315 g_echo_value = value->Int32Value();
5316}
5317
5318
5319static v8::Handle<Value> UnreachableGetter(Local<String> name,
5320 const AccessorInfo& info) {
5321 CHECK(false); // This function should not be called..
5322 return v8::Undefined();
5323}
5324
5325
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005326static void UnreachableSetter(Local<String>, Local<Value>,
5327 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005328 CHECK(false); // This function should nto be called.
5329}
5330
5331
5332THREADED_TEST(AccessControl) {
5333 v8::HandleScope handle_scope;
5334 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
5335
5336 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
5337 IndexedAccessBlocker);
5338
5339 // Add an accessor accessible by cross-domain JS code.
5340 global_template->SetAccessor(
5341 v8_str("accessible_prop"),
5342 EchoGetter, EchoSetter,
5343 v8::Handle<Value>(),
5344 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
5345
5346 // Add an accessor that is not accessible by cross-domain JS code.
ager@chromium.org870a0b62008-11-04 11:43:05 +00005347 global_template->SetAccessor(v8_str("blocked_prop"),
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005348 UnreachableGetter, UnreachableSetter,
5349 v8::Handle<Value>(),
5350 v8::DEFAULT);
5351
5352 // Create an environment
5353 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
5354 context0->Enter();
5355
5356 v8::Handle<v8::Object> global0 = context0->Global();
5357
5358 v8::HandleScope scope1;
5359
5360 v8::Persistent<Context> context1 = Context::New();
5361 context1->Enter();
5362
5363 v8::Handle<v8::Object> global1 = context1->Global();
5364 global1->Set(v8_str("other"), global0);
5365
5366 v8::Handle<Value> value;
5367
5368 // Access blocked property
5369 value = v8_compile("other.blocked_prop = 1")->Run();
5370 value = v8_compile("other.blocked_prop")->Run();
5371 CHECK(value->IsUndefined());
5372
ager@chromium.org870a0b62008-11-04 11:43:05 +00005373 value = v8_compile("propertyIsEnumerable.call(other, 'blocked_prop')")->Run();
5374 CHECK(value->IsFalse());
5375
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005376 // Access accessible property
5377 value = v8_compile("other.accessible_prop = 3")->Run();
5378 CHECK(value->IsNumber());
5379 CHECK_EQ(3, value->Int32Value());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00005380 CHECK_EQ(3, g_echo_value);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005381
5382 value = v8_compile("other.accessible_prop")->Run();
5383 CHECK(value->IsNumber());
5384 CHECK_EQ(3, value->Int32Value());
5385
ager@chromium.org870a0b62008-11-04 11:43:05 +00005386 value =
5387 v8_compile("propertyIsEnumerable.call(other, 'accessible_prop')")->Run();
5388 CHECK(value->IsTrue());
5389
5390 // Enumeration doesn't enumerate accessors from inaccessible objects in
5391 // the prototype chain even if the accessors are in themselves accessible.
5392 Local<Value> result =
5393 CompileRun("(function(){var obj = {'__proto__':other};"
5394 "for (var p in obj)"
5395 " if (p == 'accessible_prop' || p == 'blocked_prop') {"
5396 " return false;"
5397 " }"
5398 "return true;})()");
5399 CHECK(result->IsTrue());
5400
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005401 context1->Exit();
5402 context0->Exit();
5403 context1.Dispose();
5404 context0.Dispose();
5405}
5406
5407
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005408static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
5409 Local<Value> name,
5410 v8::AccessType type,
5411 Local<Value> data) {
5412 return false;
5413}
5414
5415
5416static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
5417 uint32_t key,
5418 v8::AccessType type,
5419 Local<Value> data) {
5420 return false;
5421}
5422
5423
5424THREADED_TEST(AccessControlGetOwnPropertyNames) {
5425 v8::HandleScope handle_scope;
5426 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
5427
5428 obj_template->Set(v8_str("x"), v8::Integer::New(42));
5429 obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
5430 GetOwnPropertyNamesIndexedBlocker);
5431
5432 // Create an environment
5433 v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
5434 context0->Enter();
5435
5436 v8::Handle<v8::Object> global0 = context0->Global();
5437
5438 v8::HandleScope scope1;
5439
5440 v8::Persistent<Context> context1 = Context::New();
5441 context1->Enter();
5442
5443 v8::Handle<v8::Object> global1 = context1->Global();
5444 global1->Set(v8_str("other"), global0);
5445 global1->Set(v8_str("object"), obj_template->NewInstance());
5446
5447 v8::Handle<Value> value;
5448
5449 // Attempt to get the property names of the other global object and
5450 // of an object that requires access checks. Accessing the other
5451 // global object should be blocked by access checks on the global
5452 // proxy object. Accessing the object that requires access checks
5453 // is blocked by the access checks on the object itself.
5454 value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
5455 CHECK(value->IsTrue());
5456
5457 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
5458 CHECK(value->IsTrue());
5459
5460 context1->Exit();
5461 context0->Exit();
5462 context1.Dispose();
5463 context0.Dispose();
5464}
5465
5466
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00005467static v8::Handle<v8::Array> NamedPropertyEnumerator(const AccessorInfo& info) {
5468 v8::Handle<v8::Array> result = v8::Array::New(1);
5469 result->Set(0, v8_str("x"));
5470 return result;
5471}
5472
5473
5474THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
5475 v8::HandleScope handle_scope;
5476 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
5477
5478 obj_template->Set(v8_str("x"), v8::Integer::New(42));
5479 obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
5480 NamedPropertyEnumerator);
5481
5482 LocalContext context;
5483 v8::Handle<v8::Object> global = context->Global();
5484 global->Set(v8_str("object"), obj_template->NewInstance());
5485
5486 v8::Handle<Value> value =
5487 CompileRun("Object.getOwnPropertyNames(object).join(',')");
5488 CHECK_EQ(v8_str("x"), value);
5489}
5490
5491
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005492static v8::Handle<Value> ConstTenGetter(Local<String> name,
5493 const AccessorInfo& info) {
5494 return v8_num(10);
5495}
5496
5497
5498THREADED_TEST(CrossDomainAccessors) {
5499 v8::HandleScope handle_scope;
5500
5501 v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
5502
5503 v8::Handle<v8::ObjectTemplate> global_template =
5504 func_template->InstanceTemplate();
5505
5506 v8::Handle<v8::ObjectTemplate> proto_template =
5507 func_template->PrototypeTemplate();
5508
5509 // Add an accessor to proto that's accessible by cross-domain JS code.
5510 proto_template->SetAccessor(v8_str("accessible"),
5511 ConstTenGetter, 0,
5512 v8::Handle<Value>(),
5513 v8::ALL_CAN_READ);
5514
5515 // Add an accessor that is not accessible by cross-domain JS code.
5516 global_template->SetAccessor(v8_str("unreachable"),
5517 UnreachableGetter, 0,
5518 v8::Handle<Value>(),
5519 v8::DEFAULT);
5520
5521 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
5522 context0->Enter();
5523
5524 Local<v8::Object> global = context0->Global();
5525 // Add a normal property that shadows 'accessible'
5526 global->Set(v8_str("accessible"), v8_num(11));
5527
5528 // Enter a new context.
5529 v8::HandleScope scope1;
5530 v8::Persistent<Context> context1 = Context::New();
5531 context1->Enter();
5532
5533 v8::Handle<v8::Object> global1 = context1->Global();
5534 global1->Set(v8_str("other"), global);
5535
5536 // Should return 10, instead of 11
5537 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
5538 CHECK(value->IsNumber());
5539 CHECK_EQ(10, value->Int32Value());
5540
5541 value = v8_compile("other.unreachable")->Run();
5542 CHECK(value->IsUndefined());
5543
5544 context1->Exit();
5545 context0->Exit();
5546 context1.Dispose();
5547 context0.Dispose();
5548}
5549
5550
5551static int named_access_count = 0;
5552static int indexed_access_count = 0;
5553
5554static bool NamedAccessCounter(Local<v8::Object> global,
5555 Local<Value> name,
5556 v8::AccessType type,
5557 Local<Value> data) {
5558 named_access_count++;
5559 return true;
5560}
5561
5562
5563static bool IndexedAccessCounter(Local<v8::Object> global,
5564 uint32_t key,
5565 v8::AccessType type,
5566 Local<Value> data) {
5567 indexed_access_count++;
5568 return true;
5569}
5570
5571
5572// This one is too easily disturbed by other tests.
5573TEST(AccessControlIC) {
5574 named_access_count = 0;
5575 indexed_access_count = 0;
5576
5577 v8::HandleScope handle_scope;
5578
5579 // Create an environment.
5580 v8::Persistent<Context> context0 = Context::New();
5581 context0->Enter();
5582
5583 // Create an object that requires access-check functions to be
5584 // called for cross-domain access.
5585 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
5586 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
5587 IndexedAccessCounter);
5588 Local<v8::Object> object = object_template->NewInstance();
5589
5590 v8::HandleScope scope1;
5591
5592 // Create another environment.
5593 v8::Persistent<Context> context1 = Context::New();
5594 context1->Enter();
5595
5596 // Make easy access to the object from the other environment.
5597 v8::Handle<v8::Object> global1 = context1->Global();
5598 global1->Set(v8_str("obj"), object);
5599
5600 v8::Handle<Value> value;
5601
5602 // Check that the named access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00005603 CompileRun("function testProp(obj) {"
5604 " for (var i = 0; i < 10; i++) obj.prop = 1;"
5605 " for (var j = 0; j < 10; j++) obj.prop;"
5606 " return obj.prop"
5607 "}");
5608 value = CompileRun("testProp(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005609 CHECK(value->IsNumber());
5610 CHECK_EQ(1, value->Int32Value());
5611 CHECK_EQ(21, named_access_count);
5612
5613 // Check that the named access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00005614 CompileRun("var p = 'prop';"
5615 "function testKeyed(obj) {"
5616 " for (var i = 0; i < 10; i++) obj[p] = 1;"
5617 " for (var j = 0; j < 10; j++) obj[p];"
5618 " return obj[p];"
5619 "}");
5620 // Use obj which requires access checks. No inline caching is used
5621 // in that case.
5622 value = CompileRun("testKeyed(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005623 CHECK(value->IsNumber());
5624 CHECK_EQ(1, value->Int32Value());
5625 CHECK_EQ(42, named_access_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00005626 // Force the inline caches into generic state and try again.
5627 CompileRun("testKeyed({ a: 0 })");
5628 CompileRun("testKeyed({ b: 0 })");
5629 value = CompileRun("testKeyed(obj)");
5630 CHECK(value->IsNumber());
5631 CHECK_EQ(1, value->Int32Value());
5632 CHECK_EQ(63, named_access_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005633
5634 // Check that the indexed access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00005635 CompileRun("function testIndexed(obj) {"
5636 " for (var i = 0; i < 10; i++) obj[0] = 1;"
5637 " for (var j = 0; j < 10; j++) obj[0];"
5638 " return obj[0]"
5639 "}");
5640 value = CompileRun("testIndexed(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005641 CHECK(value->IsNumber());
5642 CHECK_EQ(1, value->Int32Value());
5643 CHECK_EQ(21, indexed_access_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00005644 // Force the inline caches into generic state.
5645 CompileRun("testIndexed(new Array(1))");
5646 // Test that the indexed access check is called.
5647 value = CompileRun("testIndexed(obj)");
5648 CHECK(value->IsNumber());
5649 CHECK_EQ(1, value->Int32Value());
5650 CHECK_EQ(42, indexed_access_count);
5651
5652 // Check that the named access check is called when invoking
5653 // functions on an object that requires access checks.
5654 CompileRun("obj.f = function() {}");
5655 CompileRun("function testCallNormal(obj) {"
5656 " for (var i = 0; i < 10; i++) obj.f();"
5657 "}");
5658 CompileRun("testCallNormal(obj)");
5659 CHECK_EQ(74, named_access_count);
5660
5661 // Force obj into slow case.
5662 value = CompileRun("delete obj.prop");
5663 CHECK(value->BooleanValue());
5664 // Force inline caches into dictionary probing mode.
5665 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
5666 // Test that the named access check is called.
5667 value = CompileRun("testProp(obj);");
5668 CHECK(value->IsNumber());
5669 CHECK_EQ(1, value->Int32Value());
5670 CHECK_EQ(96, named_access_count);
5671
5672 // Force the call inline cache into dictionary probing mode.
5673 CompileRun("o.f = function() {}; testCallNormal(o)");
5674 // Test that the named access check is still called for each
5675 // invocation of the function.
5676 value = CompileRun("testCallNormal(obj)");
5677 CHECK_EQ(106, named_access_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005678
5679 context1->Exit();
5680 context0->Exit();
5681 context1.Dispose();
5682 context0.Dispose();
5683}
5684
5685
5686static bool NamedAccessFlatten(Local<v8::Object> global,
5687 Local<Value> name,
5688 v8::AccessType type,
5689 Local<Value> data) {
5690 char buf[100];
5691 int len;
5692
5693 CHECK(name->IsString());
5694
5695 memset(buf, 0x1, sizeof(buf));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005696 len = name.As<String>()->WriteAscii(buf);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005697 CHECK_EQ(4, len);
5698
5699 uint16_t buf2[100];
5700
5701 memset(buf, 0x1, sizeof(buf));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005702 len = name.As<String>()->Write(buf2);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005703 CHECK_EQ(4, len);
5704
5705 return true;
5706}
5707
5708
5709static bool IndexedAccessFlatten(Local<v8::Object> global,
5710 uint32_t key,
5711 v8::AccessType type,
5712 Local<Value> data) {
5713 return true;
5714}
5715
5716
5717// Regression test. In access checks, operations that may cause
5718// garbage collection are not allowed. It used to be the case that
5719// using the Write operation on a string could cause a garbage
5720// collection due to flattening of the string. This is no longer the
5721// case.
5722THREADED_TEST(AccessControlFlatten) {
5723 named_access_count = 0;
5724 indexed_access_count = 0;
5725
5726 v8::HandleScope handle_scope;
5727
5728 // Create an environment.
5729 v8::Persistent<Context> context0 = Context::New();
5730 context0->Enter();
5731
5732 // Create an object that requires access-check functions to be
5733 // called for cross-domain access.
5734 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
5735 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
5736 IndexedAccessFlatten);
5737 Local<v8::Object> object = object_template->NewInstance();
5738
5739 v8::HandleScope scope1;
5740
5741 // Create another environment.
5742 v8::Persistent<Context> context1 = Context::New();
5743 context1->Enter();
5744
5745 // Make easy access to the object from the other environment.
5746 v8::Handle<v8::Object> global1 = context1->Global();
5747 global1->Set(v8_str("obj"), object);
5748
5749 v8::Handle<Value> value;
5750
5751 value = v8_compile("var p = 'as' + 'df';")->Run();
5752 value = v8_compile("obj[p];")->Run();
5753
5754 context1->Exit();
5755 context0->Exit();
5756 context1.Dispose();
5757 context0.Dispose();
5758}
5759
5760
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005761static v8::Handle<Value> AccessControlNamedGetter(
5762 Local<String>, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005763 return v8::Integer::New(42);
5764}
5765
5766
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005767static v8::Handle<Value> AccessControlNamedSetter(
5768 Local<String>, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005769 return value;
5770}
5771
5772
5773static v8::Handle<Value> AccessControlIndexedGetter(
5774 uint32_t index,
5775 const AccessorInfo& info) {
5776 return v8_num(42);
5777}
5778
5779
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005780static v8::Handle<Value> AccessControlIndexedSetter(
5781 uint32_t, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005782 return value;
5783}
5784
5785
5786THREADED_TEST(AccessControlInterceptorIC) {
5787 named_access_count = 0;
5788 indexed_access_count = 0;
5789
5790 v8::HandleScope handle_scope;
5791
5792 // Create an environment.
5793 v8::Persistent<Context> context0 = Context::New();
5794 context0->Enter();
5795
5796 // Create an object that requires access-check functions to be
5797 // called for cross-domain access. The object also has interceptors
5798 // interceptor.
5799 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
5800 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
5801 IndexedAccessCounter);
5802 object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
5803 AccessControlNamedSetter);
5804 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
5805 AccessControlIndexedSetter);
5806 Local<v8::Object> object = object_template->NewInstance();
5807
5808 v8::HandleScope scope1;
5809
5810 // Create another environment.
5811 v8::Persistent<Context> context1 = Context::New();
5812 context1->Enter();
5813
5814 // Make easy access to the object from the other environment.
5815 v8::Handle<v8::Object> global1 = context1->Global();
5816 global1->Set(v8_str("obj"), object);
5817
5818 v8::Handle<Value> value;
5819
5820 // Check that the named access-control function is called every time
5821 // eventhough there is an interceptor on the object.
5822 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
5823 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
5824 "obj.x")->Run();
5825 CHECK(value->IsNumber());
5826 CHECK_EQ(42, value->Int32Value());
5827 CHECK_EQ(21, named_access_count);
5828
5829 value = v8_compile("var p = 'x';")->Run();
5830 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
5831 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
5832 "obj[p]")->Run();
5833 CHECK(value->IsNumber());
5834 CHECK_EQ(42, value->Int32Value());
5835 CHECK_EQ(42, named_access_count);
5836
5837 // Check that the indexed access-control function is called every
5838 // time eventhough there is an interceptor on the object.
5839 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
5840 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
5841 "obj[0]")->Run();
5842 CHECK(value->IsNumber());
5843 CHECK_EQ(42, value->Int32Value());
5844 CHECK_EQ(21, indexed_access_count);
5845
5846 context1->Exit();
5847 context0->Exit();
5848 context1.Dispose();
5849 context0.Dispose();
5850}
5851
5852
5853THREADED_TEST(Version) {
5854 v8::V8::GetVersion();
5855}
5856
5857
5858static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
5859 ApiTestFuzzer::Fuzz();
5860 return v8_num(12);
5861}
5862
5863
5864THREADED_TEST(InstanceProperties) {
5865 v8::HandleScope handle_scope;
5866 LocalContext context;
5867
5868 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5869 Local<ObjectTemplate> instance = t->InstanceTemplate();
5870
5871 instance->Set(v8_str("x"), v8_num(42));
5872 instance->Set(v8_str("f"),
5873 v8::FunctionTemplate::New(InstanceFunctionCallback));
5874
5875 Local<Value> o = t->GetFunction()->NewInstance();
5876
5877 context->Global()->Set(v8_str("i"), o);
5878 Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
5879 CHECK_EQ(42, value->Int32Value());
5880
5881 value = Script::Compile(v8_str("i.f()"))->Run();
5882 CHECK_EQ(12, value->Int32Value());
5883}
5884
5885
5886static v8::Handle<Value>
5887GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
5888 ApiTestFuzzer::Fuzz();
5889 return v8::Handle<Value>();
5890}
5891
5892
5893THREADED_TEST(GlobalObjectInstanceProperties) {
5894 v8::HandleScope handle_scope;
5895
5896 Local<Value> global_object;
5897
5898 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5899 t->InstanceTemplate()->SetNamedPropertyHandler(
5900 GlobalObjectInstancePropertiesGet);
5901 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
5902 instance_template->Set(v8_str("x"), v8_num(42));
5903 instance_template->Set(v8_str("f"),
5904 v8::FunctionTemplate::New(InstanceFunctionCallback));
5905
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005906 // The script to check how Crankshaft compiles missing global function
5907 // invocations. function g is not defined and should throw on call.
5908 const char* script =
5909 "function wrapper(call) {"
5910 " var x = 0, y = 1;"
5911 " for (var i = 0; i < 1000; i++) {"
5912 " x += i * 100;"
5913 " y += i * 100;"
5914 " }"
5915 " if (call) g();"
5916 "}"
5917 "for (var i = 0; i < 17; i++) wrapper(false);"
5918 "var thrown = 0;"
5919 "try { wrapper(true); } catch (e) { thrown = 1; };"
5920 "thrown";
5921
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005922 {
5923 LocalContext env(NULL, instance_template);
5924 // Hold on to the global object so it can be used again in another
5925 // environment initialization.
5926 global_object = env->Global();
5927
5928 Local<Value> value = Script::Compile(v8_str("x"))->Run();
5929 CHECK_EQ(42, value->Int32Value());
5930 value = Script::Compile(v8_str("f()"))->Run();
5931 CHECK_EQ(12, value->Int32Value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005932 value = Script::Compile(v8_str(script))->Run();
5933 CHECK_EQ(1, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005934 }
5935
5936 {
5937 // Create new environment reusing the global object.
5938 LocalContext env(NULL, instance_template, global_object);
5939 Local<Value> value = Script::Compile(v8_str("x"))->Run();
5940 CHECK_EQ(42, value->Int32Value());
5941 value = Script::Compile(v8_str("f()"))->Run();
5942 CHECK_EQ(12, value->Int32Value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005943 value = Script::Compile(v8_str(script))->Run();
5944 CHECK_EQ(1, value->Int32Value());
5945 }
5946}
5947
5948
5949THREADED_TEST(CallKnownGlobalReceiver) {
5950 v8::HandleScope handle_scope;
5951
5952 Local<Value> global_object;
5953
5954 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5955 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
5956
5957 // The script to check that we leave global object not
5958 // global object proxy on stack when we deoptimize from inside
5959 // arguments evaluation.
5960 // To provoke error we need to both force deoptimization
5961 // from arguments evaluation and to force CallIC to take
5962 // CallIC_Miss code path that can't cope with global proxy.
5963 const char* script =
5964 "function bar(x, y) { try { } finally { } }"
5965 "function baz(x) { try { } finally { } }"
5966 "function bom(x) { try { } finally { } }"
5967 "function foo(x) { bar([x], bom(2)); }"
5968 "for (var i = 0; i < 10000; i++) foo(1);"
5969 "foo";
5970
5971 Local<Value> foo;
5972 {
5973 LocalContext env(NULL, instance_template);
5974 // Hold on to the global object so it can be used again in another
5975 // environment initialization.
5976 global_object = env->Global();
5977 foo = Script::Compile(v8_str(script))->Run();
5978 }
5979
5980 {
5981 // Create new environment reusing the global object.
5982 LocalContext env(NULL, instance_template, global_object);
5983 env->Global()->Set(v8_str("foo"), foo);
5984 Local<Value> value = Script::Compile(v8_str("foo()"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005985 }
5986}
5987
5988
5989static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
5990 ApiTestFuzzer::Fuzz();
5991 return v8_num(42);
5992}
5993
5994
5995static int shadow_y;
5996static int shadow_y_setter_call_count;
5997static int shadow_y_getter_call_count;
5998
5999
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006000static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006001 shadow_y_setter_call_count++;
6002 shadow_y = 42;
6003}
6004
6005
6006static v8::Handle<Value> ShadowYGetter(Local<String> name,
6007 const AccessorInfo& info) {
6008 ApiTestFuzzer::Fuzz();
6009 shadow_y_getter_call_count++;
6010 return v8_num(shadow_y);
6011}
6012
6013
6014static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
6015 const AccessorInfo& info) {
6016 return v8::Handle<Value>();
6017}
6018
6019
6020static v8::Handle<Value> ShadowNamedGet(Local<String> key,
6021 const AccessorInfo&) {
6022 return v8::Handle<Value>();
6023}
6024
6025
6026THREADED_TEST(ShadowObject) {
6027 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
6028 v8::HandleScope handle_scope;
6029
6030 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
6031 LocalContext context(NULL, global_template);
6032
6033 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6034 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
6035 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
6036 Local<ObjectTemplate> proto = t->PrototypeTemplate();
6037 Local<ObjectTemplate> instance = t->InstanceTemplate();
6038
6039 // Only allow calls of f on instances of t.
6040 Local<v8::Signature> signature = v8::Signature::New(t);
6041 proto->Set(v8_str("f"),
6042 v8::FunctionTemplate::New(ShadowFunctionCallback,
6043 Local<Value>(),
6044 signature));
6045 proto->Set(v8_str("x"), v8_num(12));
6046
6047 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
6048
6049 Local<Value> o = t->GetFunction()->NewInstance();
6050 context->Global()->Set(v8_str("__proto__"), o);
6051
6052 Local<Value> value =
6053 Script::Compile(v8_str("propertyIsEnumerable(0)"))->Run();
6054 CHECK(value->IsBoolean());
6055 CHECK(!value->BooleanValue());
6056
6057 value = Script::Compile(v8_str("x"))->Run();
6058 CHECK_EQ(12, value->Int32Value());
6059
6060 value = Script::Compile(v8_str("f()"))->Run();
6061 CHECK_EQ(42, value->Int32Value());
6062
6063 Script::Compile(v8_str("y = 42"))->Run();
6064 CHECK_EQ(1, shadow_y_setter_call_count);
6065 value = Script::Compile(v8_str("y"))->Run();
6066 CHECK_EQ(1, shadow_y_getter_call_count);
6067 CHECK_EQ(42, value->Int32Value());
6068}
6069
6070
6071THREADED_TEST(HiddenPrototype) {
6072 v8::HandleScope handle_scope;
6073 LocalContext context;
6074
6075 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
6076 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
6077 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
6078 t1->SetHiddenPrototype(true);
6079 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
6080 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
6081 t2->SetHiddenPrototype(true);
6082 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
6083 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
6084 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
6085
6086 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
6087 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
6088 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
6089 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
6090
6091 // Setting the prototype on an object skips hidden prototypes.
6092 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6093 o0->Set(v8_str("__proto__"), o1);
6094 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6095 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6096 o0->Set(v8_str("__proto__"), o2);
6097 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6098 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6099 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6100 o0->Set(v8_str("__proto__"), o3);
6101 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6102 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6103 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6104 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
6105
6106 // Getting the prototype of o0 should get the first visible one
6107 // which is o3. Therefore, z should not be defined on the prototype
6108 // object.
6109 Local<Value> proto = o0->Get(v8_str("__proto__"));
6110 CHECK(proto->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006111 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006112}
6113
6114
ager@chromium.org5c838252010-02-19 08:53:10 +00006115THREADED_TEST(SetPrototype) {
6116 v8::HandleScope handle_scope;
6117 LocalContext context;
6118
6119 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
6120 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
6121 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
6122 t1->SetHiddenPrototype(true);
6123 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
6124 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
6125 t2->SetHiddenPrototype(true);
6126 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
6127 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
6128 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
6129
6130 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
6131 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
6132 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
6133 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
6134
6135 // Setting the prototype on an object does not skip hidden prototypes.
6136 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6137 CHECK(o0->SetPrototype(o1));
6138 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6139 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6140 CHECK(o1->SetPrototype(o2));
6141 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6142 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6143 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6144 CHECK(o2->SetPrototype(o3));
6145 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6146 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6147 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6148 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
6149
6150 // Getting the prototype of o0 should get the first visible one
6151 // which is o3. Therefore, z should not be defined on the prototype
6152 // object.
6153 Local<Value> proto = o0->Get(v8_str("__proto__"));
6154 CHECK(proto->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006155 CHECK_EQ(proto.As<v8::Object>(), o3);
ager@chromium.org5c838252010-02-19 08:53:10 +00006156
6157 // However, Object::GetPrototype ignores hidden prototype.
6158 Local<Value> proto0 = o0->GetPrototype();
6159 CHECK(proto0->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006160 CHECK_EQ(proto0.As<v8::Object>(), o1);
ager@chromium.org5c838252010-02-19 08:53:10 +00006161
6162 Local<Value> proto1 = o1->GetPrototype();
6163 CHECK(proto1->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006164 CHECK_EQ(proto1.As<v8::Object>(), o2);
ager@chromium.org5c838252010-02-19 08:53:10 +00006165
6166 Local<Value> proto2 = o2->GetPrototype();
6167 CHECK(proto2->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006168 CHECK_EQ(proto2.As<v8::Object>(), o3);
ager@chromium.org5c838252010-02-19 08:53:10 +00006169}
6170
6171
6172THREADED_TEST(SetPrototypeThrows) {
6173 v8::HandleScope handle_scope;
6174 LocalContext context;
6175
6176 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6177
6178 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
6179 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
6180
6181 CHECK(o0->SetPrototype(o1));
6182 // If setting the prototype leads to the cycle, SetPrototype should
6183 // return false and keep VM in sane state.
6184 v8::TryCatch try_catch;
6185 CHECK(!o1->SetPrototype(o0));
6186 CHECK(!try_catch.HasCaught());
6187 ASSERT(!i::Top::has_pending_exception());
6188
6189 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
6190}
6191
6192
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006193THREADED_TEST(GetterSetterExceptions) {
6194 v8::HandleScope handle_scope;
6195 LocalContext context;
6196 CompileRun(
6197 "function Foo() { };"
6198 "function Throw() { throw 5; };"
6199 "var x = { };"
6200 "x.__defineSetter__('set', Throw);"
6201 "x.__defineGetter__('get', Throw);");
6202 Local<v8::Object> x =
6203 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
6204 v8::TryCatch try_catch;
6205 x->Set(v8_str("set"), v8::Integer::New(8));
6206 x->Get(v8_str("get"));
6207 x->Set(v8_str("set"), v8::Integer::New(8));
6208 x->Get(v8_str("get"));
6209 x->Set(v8_str("set"), v8::Integer::New(8));
6210 x->Get(v8_str("get"));
6211 x->Set(v8_str("set"), v8::Integer::New(8));
6212 x->Get(v8_str("get"));
6213}
6214
6215
6216THREADED_TEST(Constructor) {
6217 v8::HandleScope handle_scope;
6218 LocalContext context;
6219 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
6220 templ->SetClassName(v8_str("Fun"));
6221 Local<Function> cons = templ->GetFunction();
6222 context->Global()->Set(v8_str("Fun"), cons);
6223 Local<v8::Object> inst = cons->NewInstance();
6224 i::Handle<i::JSObject> obj = v8::Utils::OpenHandle(*inst);
6225 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
6226 CHECK(value->BooleanValue());
6227}
6228
6229THREADED_TEST(FunctionDescriptorException) {
6230 v8::HandleScope handle_scope;
6231 LocalContext context;
6232 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
6233 templ->SetClassName(v8_str("Fun"));
6234 Local<Function> cons = templ->GetFunction();
6235 context->Global()->Set(v8_str("Fun"), cons);
6236 Local<Value> value = CompileRun(
6237 "function test() {"
6238 " try {"
6239 " (new Fun()).blah()"
6240 " } catch (e) {"
6241 " var str = String(e);"
6242 " if (str.indexOf('TypeError') == -1) return 1;"
6243 " if (str.indexOf('[object Fun]') != -1) return 2;"
6244 " if (str.indexOf('#<a Fun>') == -1) return 3;"
6245 " return 0;"
6246 " }"
6247 " return 4;"
6248 "}"
6249 "test();");
6250 CHECK_EQ(0, value->Int32Value());
6251}
6252
6253
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006254THREADED_TEST(EvalAliasedDynamic) {
6255 v8::HandleScope scope;
6256 LocalContext current;
6257
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006258 // Tests where aliased eval can only be resolved dynamically.
6259 Local<Script> script =
6260 Script::Compile(v8_str("function f(x) { "
6261 " var foo = 2;"
6262 " with (x) { return eval('foo'); }"
6263 "}"
6264 "foo = 0;"
6265 "result1 = f(new Object());"
ager@chromium.orge2902be2009-06-08 12:21:35 +00006266 "result2 = f(this);"
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006267 "var x = new Object();"
6268 "x.eval = function(x) { return 1; };"
6269 "result3 = f(x);"));
6270 script->Run();
6271 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
6272 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
6273 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
6274
6275 v8::TryCatch try_catch;
6276 script =
6277 Script::Compile(v8_str("function f(x) { "
6278 " var bar = 2;"
6279 " with (x) { return eval('bar'); }"
6280 "}"
ager@chromium.orge2902be2009-06-08 12:21:35 +00006281 "f(this)"));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006282 script->Run();
6283 CHECK(try_catch.HasCaught());
6284 try_catch.Reset();
6285}
6286
6287
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006288THREADED_TEST(CrossEval) {
6289 v8::HandleScope scope;
6290 LocalContext other;
6291 LocalContext current;
6292
6293 Local<String> token = v8_str("<security token>");
6294 other->SetSecurityToken(token);
6295 current->SetSecurityToken(token);
6296
6297 // Setup reference from current to other.
6298 current->Global()->Set(v8_str("other"), other->Global());
6299
6300 // Check that new variables are introduced in other context.
6301 Local<Script> script =
6302 Script::Compile(v8_str("other.eval('var foo = 1234')"));
6303 script->Run();
6304 Local<Value> foo = other->Global()->Get(v8_str("foo"));
6305 CHECK_EQ(1234, foo->Int32Value());
6306 CHECK(!current->Global()->Has(v8_str("foo")));
6307
6308 // Check that writing to non-existing properties introduces them in
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006309 // the other context.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006310 script =
6311 Script::Compile(v8_str("other.eval('na = 1234')"));
6312 script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006313 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
6314 CHECK(!current->Global()->Has(v8_str("na")));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006315
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006316 // Check that global variables in current context are not visible in other
6317 // context.
6318 v8::TryCatch try_catch;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006319 script =
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006320 Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006321 Local<Value> result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006322 CHECK(try_catch.HasCaught());
6323 try_catch.Reset();
6324
6325 // Check that local variables in current context are not visible in other
6326 // context.
6327 script =
6328 Script::Compile(v8_str("(function() { "
6329 " var baz = 87;"
6330 " return other.eval('baz');"
6331 "})();"));
6332 result = script->Run();
6333 CHECK(try_catch.HasCaught());
6334 try_catch.Reset();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006335
6336 // Check that global variables in the other environment are visible
6337 // when evaluting code.
6338 other->Global()->Set(v8_str("bis"), v8_num(1234));
6339 script = Script::Compile(v8_str("other.eval('bis')"));
6340 CHECK_EQ(1234, script->Run()->Int32Value());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006341 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006342
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006343 // Check that the 'this' pointer points to the global object evaluating
6344 // code.
6345 other->Global()->Set(v8_str("t"), other->Global());
6346 script = Script::Compile(v8_str("other.eval('this == t')"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006347 result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006348 CHECK(result->IsTrue());
6349 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006350
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006351 // Check that variables introduced in with-statement are not visible in
6352 // other context.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006353 script =
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006354 Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006355 result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006356 CHECK(try_catch.HasCaught());
6357 try_catch.Reset();
ager@chromium.org3bf7b912008-11-17 09:09:45 +00006358
6359 // Check that you cannot use 'eval.call' with another object than the
6360 // current global object.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00006361 script =
6362 Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
6363 result = script->Run();
6364 CHECK(try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006365}
6366
6367
ager@chromium.orge2902be2009-06-08 12:21:35 +00006368// Test that calling eval in a context which has been detached from
6369// its global throws an exception. This behavior is consistent with
6370// other JavaScript implementations.
6371THREADED_TEST(EvalInDetachedGlobal) {
6372 v8::HandleScope scope;
6373
6374 v8::Persistent<Context> context0 = Context::New();
6375 v8::Persistent<Context> context1 = Context::New();
6376
6377 // Setup function in context0 that uses eval from context0.
6378 context0->Enter();
6379 v8::Handle<v8::Value> fun =
6380 CompileRun("var x = 42;"
6381 "(function() {"
6382 " var e = eval;"
6383 " return function(s) { return e(s); }"
6384 "})()");
6385 context0->Exit();
6386
6387 // Put the function into context1 and call it before and after
6388 // detaching the global. Before detaching, the call succeeds and
6389 // after detaching and exception is thrown.
6390 context1->Enter();
6391 context1->Global()->Set(v8_str("fun"), fun);
6392 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
6393 CHECK_EQ(42, x_value->Int32Value());
6394 context0->DetachGlobal();
6395 v8::TryCatch catcher;
6396 x_value = CompileRun("fun('x')");
6397 CHECK(x_value.IsEmpty());
6398 CHECK(catcher.HasCaught());
6399 context1->Exit();
6400
6401 context1.Dispose();
6402 context0.Dispose();
6403}
6404
6405
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006406THREADED_TEST(CrossLazyLoad) {
6407 v8::HandleScope scope;
6408 LocalContext other;
6409 LocalContext current;
6410
6411 Local<String> token = v8_str("<security token>");
6412 other->SetSecurityToken(token);
6413 current->SetSecurityToken(token);
6414
6415 // Setup reference from current to other.
6416 current->Global()->Set(v8_str("other"), other->Global());
6417
6418 // Trigger lazy loading in other context.
6419 Local<Script> script =
6420 Script::Compile(v8_str("other.eval('new Date(42)')"));
6421 Local<Value> value = script->Run();
6422 CHECK_EQ(42.0, value->NumberValue());
6423}
6424
6425
6426static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
6427 ApiTestFuzzer::Fuzz();
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00006428 if (args.IsConstructCall()) {
6429 if (args[0]->IsInt32()) {
6430 return v8_num(-args[0]->Int32Value());
6431 }
6432 }
6433
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006434 return args[0];
6435}
6436
6437
6438// Test that a call handler can be set for objects which will allow
6439// non-function objects created through the API to be called as
6440// functions.
6441THREADED_TEST(CallAsFunction) {
6442 v8::HandleScope scope;
6443 LocalContext context;
6444
6445 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6446 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
6447 instance_template->SetCallAsFunctionHandler(call_as_function);
6448 Local<v8::Object> instance = t->GetFunction()->NewInstance();
6449 context->Global()->Set(v8_str("obj"), instance);
6450 v8::TryCatch try_catch;
6451 Local<Value> value;
6452 CHECK(!try_catch.HasCaught());
6453
ager@chromium.org9085a012009-05-11 19:22:57 +00006454 value = CompileRun("obj(42)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006455 CHECK(!try_catch.HasCaught());
6456 CHECK_EQ(42, value->Int32Value());
6457
ager@chromium.org9085a012009-05-11 19:22:57 +00006458 value = CompileRun("(function(o){return o(49)})(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006459 CHECK(!try_catch.HasCaught());
6460 CHECK_EQ(49, value->Int32Value());
6461
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006462 // test special case of call as function
ager@chromium.org9085a012009-05-11 19:22:57 +00006463 value = CompileRun("[obj]['0'](45)");
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006464 CHECK(!try_catch.HasCaught());
6465 CHECK_EQ(45, value->Int32Value());
6466
ager@chromium.org9085a012009-05-11 19:22:57 +00006467 value = CompileRun("obj.call = Function.prototype.call;"
6468 "obj.call(null, 87)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006469 CHECK(!try_catch.HasCaught());
6470 CHECK_EQ(87, value->Int32Value());
6471
6472 // Regression tests for bug #1116356: Calling call through call/apply
6473 // must work for non-function receivers.
6474 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
ager@chromium.org9085a012009-05-11 19:22:57 +00006475 value = CompileRun(apply_99);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006476 CHECK(!try_catch.HasCaught());
6477 CHECK_EQ(99, value->Int32Value());
6478
6479 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
ager@chromium.org9085a012009-05-11 19:22:57 +00006480 value = CompileRun(call_17);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006481 CHECK(!try_catch.HasCaught());
6482 CHECK_EQ(17, value->Int32Value());
ager@chromium.org9085a012009-05-11 19:22:57 +00006483
6484 // Check that the call-as-function handler can be called through
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006485 // new.
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00006486 value = CompileRun("new obj(43)");
ager@chromium.org9085a012009-05-11 19:22:57 +00006487 CHECK(!try_catch.HasCaught());
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00006488 CHECK_EQ(-43, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006489}
6490
6491
6492static int CountHandles() {
6493 return v8::HandleScope::NumberOfHandles();
6494}
6495
6496
6497static int Recurse(int depth, int iterations) {
6498 v8::HandleScope scope;
6499 if (depth == 0) return CountHandles();
6500 for (int i = 0; i < iterations; i++) {
6501 Local<v8::Number> n = v8::Integer::New(42);
6502 }
6503 return Recurse(depth - 1, iterations);
6504}
6505
6506
6507THREADED_TEST(HandleIteration) {
6508 static const int kIterations = 500;
6509 static const int kNesting = 200;
6510 CHECK_EQ(0, CountHandles());
6511 {
6512 v8::HandleScope scope1;
6513 CHECK_EQ(0, CountHandles());
6514 for (int i = 0; i < kIterations; i++) {
6515 Local<v8::Number> n = v8::Integer::New(42);
6516 CHECK_EQ(i + 1, CountHandles());
6517 }
6518
6519 CHECK_EQ(kIterations, CountHandles());
6520 {
6521 v8::HandleScope scope2;
6522 for (int j = 0; j < kIterations; j++) {
6523 Local<v8::Number> n = v8::Integer::New(42);
6524 CHECK_EQ(j + 1 + kIterations, CountHandles());
6525 }
6526 }
6527 CHECK_EQ(kIterations, CountHandles());
6528 }
6529 CHECK_EQ(0, CountHandles());
6530 CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
6531}
6532
6533
6534static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
6535 Local<String> name,
6536 const AccessorInfo& info) {
6537 ApiTestFuzzer::Fuzz();
6538 return v8::Handle<Value>();
6539}
6540
6541
6542THREADED_TEST(InterceptorHasOwnProperty) {
6543 v8::HandleScope scope;
6544 LocalContext context;
6545 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6546 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
6547 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
6548 Local<Function> function = fun_templ->GetFunction();
6549 context->Global()->Set(v8_str("constructor"), function);
6550 v8::Handle<Value> value = CompileRun(
6551 "var o = new constructor();"
6552 "o.hasOwnProperty('ostehaps');");
6553 CHECK_EQ(false, value->BooleanValue());
6554 value = CompileRun(
6555 "o.ostehaps = 42;"
6556 "o.hasOwnProperty('ostehaps');");
6557 CHECK_EQ(true, value->BooleanValue());
6558 value = CompileRun(
6559 "var p = new constructor();"
6560 "p.hasOwnProperty('ostehaps');");
6561 CHECK_EQ(false, value->BooleanValue());
6562}
6563
6564
ager@chromium.org9085a012009-05-11 19:22:57 +00006565static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
6566 Local<String> name,
6567 const AccessorInfo& info) {
6568 ApiTestFuzzer::Fuzz();
ager@chromium.orgab99eea2009-08-25 07:05:41 +00006569 i::Heap::CollectAllGarbage(false);
ager@chromium.org9085a012009-05-11 19:22:57 +00006570 return v8::Handle<Value>();
6571}
6572
6573
6574THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
6575 v8::HandleScope scope;
6576 LocalContext context;
6577 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6578 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
6579 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
6580 Local<Function> function = fun_templ->GetFunction();
6581 context->Global()->Set(v8_str("constructor"), function);
6582 // Let's first make some stuff so we can be sure to get a good GC.
6583 CompileRun(
6584 "function makestr(size) {"
6585 " switch (size) {"
6586 " case 1: return 'f';"
6587 " case 2: return 'fo';"
6588 " case 3: return 'foo';"
6589 " }"
6590 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
6591 "}"
6592 "var x = makestr(12345);"
6593 "x = makestr(31415);"
6594 "x = makestr(23456);");
6595 v8::Handle<Value> value = CompileRun(
6596 "var o = new constructor();"
6597 "o.__proto__ = new String(x);"
6598 "o.hasOwnProperty('ostehaps');");
6599 CHECK_EQ(false, value->BooleanValue());
6600}
6601
6602
ager@chromium.orge2902be2009-06-08 12:21:35 +00006603typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
6604 const AccessorInfo& info);
6605
6606
6607static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
6608 const char* source,
6609 int expected) {
6610 v8::HandleScope scope;
6611 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006612 templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
ager@chromium.orge2902be2009-06-08 12:21:35 +00006613 LocalContext context;
6614 context->Global()->Set(v8_str("o"), templ->NewInstance());
6615 v8::Handle<Value> value = CompileRun(source);
6616 CHECK_EQ(expected, value->Int32Value());
6617}
6618
6619
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006620static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
6621 const AccessorInfo& info) {
6622 ApiTestFuzzer::Fuzz();
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006623 CHECK_EQ(v8_str("data"), info.Data());
6624 CHECK_EQ(v8_str("x"), name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006625 return v8::Integer::New(42);
6626}
6627
6628
6629// This test should hit the load IC for the interceptor case.
6630THREADED_TEST(InterceptorLoadIC) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00006631 CheckInterceptorLoadIC(InterceptorLoadICGetter,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006632 "var result = 0;"
6633 "for (var i = 0; i < 1000; i++) {"
6634 " result = o.x;"
ager@chromium.orge2902be2009-06-08 12:21:35 +00006635 "}",
6636 42);
6637}
6638
6639
6640// Below go several tests which verify that JITing for various
6641// configurations of interceptor and explicit fields works fine
6642// (those cases are special cased to get better performance).
6643
6644static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
6645 const AccessorInfo& info) {
6646 ApiTestFuzzer::Fuzz();
6647 return v8_str("x")->Equals(name)
6648 ? v8::Integer::New(42) : v8::Handle<v8::Value>();
6649}
6650
6651
6652THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
6653 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6654 "var result = 0;"
6655 "o.y = 239;"
6656 "for (var i = 0; i < 1000; i++) {"
6657 " result = o.y;"
6658 "}",
6659 239);
6660}
6661
6662
6663THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
6664 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6665 "var result = 0;"
6666 "o.__proto__ = { 'y': 239 };"
6667 "for (var i = 0; i < 1000; i++) {"
6668 " result = o.y + o.x;"
6669 "}",
6670 239 + 42);
6671}
6672
6673
6674THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
6675 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6676 "var result = 0;"
6677 "o.__proto__.y = 239;"
6678 "for (var i = 0; i < 1000; i++) {"
6679 " result = o.y + o.x;"
6680 "}",
6681 239 + 42);
6682}
6683
6684
6685THREADED_TEST(InterceptorLoadICUndefined) {
6686 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6687 "var result = 0;"
6688 "for (var i = 0; i < 1000; i++) {"
6689 " result = (o.y == undefined) ? 239 : 42;"
6690 "}",
6691 239);
6692}
6693
6694
6695THREADED_TEST(InterceptorLoadICWithOverride) {
6696 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6697 "fst = new Object(); fst.__proto__ = o;"
6698 "snd = new Object(); snd.__proto__ = fst;"
6699 "var result1 = 0;"
6700 "for (var i = 0; i < 1000; i++) {"
6701 " result1 = snd.x;"
6702 "}"
6703 "fst.x = 239;"
6704 "var result = 0;"
6705 "for (var i = 0; i < 1000; i++) {"
6706 " result = snd.x;"
6707 "}"
6708 "result + result1",
6709 239 + 42);
6710}
6711
6712
kasperl@chromium.orge959c182009-07-27 08:59:04 +00006713// Test the case when we stored field into
6714// a stub, but interceptor produced value on its own.
6715THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
6716 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6717 "proto = new Object();"
6718 "o.__proto__ = proto;"
6719 "proto.x = 239;"
6720 "for (var i = 0; i < 1000; i++) {"
6721 " o.x;"
6722 // Now it should be ICed and keep a reference to x defined on proto
6723 "}"
6724 "var result = 0;"
6725 "for (var i = 0; i < 1000; i++) {"
6726 " result += o.x;"
6727 "}"
6728 "result;",
6729 42 * 1000);
6730}
6731
6732
6733// Test the case when we stored field into
6734// a stub, but it got invalidated later on.
6735THREADED_TEST(InterceptorLoadICInvalidatedField) {
6736 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6737 "proto1 = new Object();"
6738 "proto2 = new Object();"
6739 "o.__proto__ = proto1;"
6740 "proto1.__proto__ = proto2;"
6741 "proto2.y = 239;"
6742 "for (var i = 0; i < 1000; i++) {"
6743 " o.y;"
6744 // Now it should be ICed and keep a reference to y defined on proto2
6745 "}"
6746 "proto1.y = 42;"
6747 "var result = 0;"
6748 "for (var i = 0; i < 1000; i++) {"
6749 " result += o.y;"
6750 "}"
6751 "result;",
6752 42 * 1000);
6753}
6754
6755
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00006756static int interceptor_load_not_handled_calls = 0;
6757static v8::Handle<Value> InterceptorLoadNotHandled(Local<String> name,
6758 const AccessorInfo& info) {
6759 ++interceptor_load_not_handled_calls;
6760 return v8::Handle<v8::Value>();
6761}
6762
6763
6764// Test how post-interceptor lookups are done in the non-cacheable
6765// case: the interceptor should not be invoked during this lookup.
6766THREADED_TEST(InterceptorLoadICPostInterceptor) {
6767 interceptor_load_not_handled_calls = 0;
6768 CheckInterceptorLoadIC(InterceptorLoadNotHandled,
6769 "receiver = new Object();"
6770 "receiver.__proto__ = o;"
6771 "proto = new Object();"
6772 "/* Make proto a slow-case object. */"
6773 "for (var i = 0; i < 1000; i++) {"
6774 " proto[\"xxxxxxxx\" + i] = [];"
6775 "}"
6776 "proto.x = 17;"
6777 "o.__proto__ = proto;"
6778 "var result = 0;"
6779 "for (var i = 0; i < 1000; i++) {"
6780 " result += receiver.x;"
6781 "}"
6782 "result;",
6783 17 * 1000);
6784 CHECK_EQ(1000, interceptor_load_not_handled_calls);
6785}
6786
6787
kasperl@chromium.orge959c182009-07-27 08:59:04 +00006788// Test the case when we stored field into
6789// a stub, but it got invalidated later on due to override on
6790// global object which is between interceptor and fields' holders.
6791THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
6792 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6793 "o.__proto__ = this;" // set a global to be a proto of o.
6794 "this.__proto__.y = 239;"
6795 "for (var i = 0; i < 10; i++) {"
6796 " if (o.y != 239) throw 'oops: ' + o.y;"
6797 // Now it should be ICed and keep a reference to y defined on field_holder.
6798 "}"
6799 "this.y = 42;" // Assign on a global.
6800 "var result = 0;"
6801 "for (var i = 0; i < 10; i++) {"
6802 " result += o.y;"
6803 "}"
6804 "result;",
6805 42 * 10);
6806}
6807
6808
kasperl@chromium.orge959c182009-07-27 08:59:04 +00006809static void SetOnThis(Local<String> name,
6810 Local<Value> value,
6811 const AccessorInfo& info) {
6812 info.This()->ForceSet(name, value);
6813}
6814
6815
6816THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
6817 v8::HandleScope scope;
6818 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6819 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6820 templ->SetAccessor(v8_str("y"), Return239);
6821 LocalContext context;
6822 context->Global()->Set(v8_str("o"), templ->NewInstance());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006823
6824 // Check the case when receiver and interceptor's holder
6825 // are the same objects.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00006826 v8::Handle<Value> value = CompileRun(
6827 "var result = 0;"
6828 "for (var i = 0; i < 7; i++) {"
6829 " result = o.y;"
6830 "}");
6831 CHECK_EQ(239, value->Int32Value());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006832
6833 // Check the case when interceptor's holder is in proto chain
6834 // of receiver.
6835 value = CompileRun(
6836 "r = { __proto__: o };"
6837 "var result = 0;"
6838 "for (var i = 0; i < 7; i++) {"
6839 " result = r.y;"
6840 "}");
6841 CHECK_EQ(239, value->Int32Value());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00006842}
6843
6844
6845THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
6846 v8::HandleScope scope;
6847 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6848 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6849 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6850 templ_p->SetAccessor(v8_str("y"), Return239);
6851
6852 LocalContext context;
6853 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6854 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6855
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006856 // Check the case when receiver and interceptor's holder
6857 // are the same objects.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00006858 v8::Handle<Value> value = CompileRun(
6859 "o.__proto__ = p;"
6860 "var result = 0;"
6861 "for (var i = 0; i < 7; i++) {"
6862 " result = o.x + o.y;"
6863 "}");
6864 CHECK_EQ(239 + 42, value->Int32Value());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006865
6866 // Check the case when interceptor's holder is in proto chain
6867 // of receiver.
6868 value = CompileRun(
6869 "r = { __proto__: o };"
6870 "var result = 0;"
6871 "for (var i = 0; i < 7; i++) {"
6872 " result = r.x + r.y;"
6873 "}");
6874 CHECK_EQ(239 + 42, value->Int32Value());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00006875}
6876
6877
6878THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
6879 v8::HandleScope scope;
6880 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6881 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6882 templ->SetAccessor(v8_str("y"), Return239);
6883
6884 LocalContext context;
6885 context->Global()->Set(v8_str("o"), templ->NewInstance());
6886
6887 v8::Handle<Value> value = CompileRun(
6888 "fst = new Object(); fst.__proto__ = o;"
6889 "snd = new Object(); snd.__proto__ = fst;"
6890 "var result1 = 0;"
6891 "for (var i = 0; i < 7; i++) {"
6892 " result1 = snd.x;"
6893 "}"
6894 "fst.x = 239;"
6895 "var result = 0;"
6896 "for (var i = 0; i < 7; i++) {"
6897 " result = snd.x;"
6898 "}"
6899 "result + result1");
6900 CHECK_EQ(239 + 42, value->Int32Value());
6901}
6902
6903
6904// Test the case when we stored callback into
6905// a stub, but interceptor produced value on its own.
6906THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
6907 v8::HandleScope scope;
6908 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6909 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6910 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6911 templ_p->SetAccessor(v8_str("y"), Return239);
6912
6913 LocalContext context;
6914 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6915 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6916
6917 v8::Handle<Value> value = CompileRun(
6918 "o.__proto__ = p;"
6919 "for (var i = 0; i < 7; i++) {"
6920 " o.x;"
6921 // Now it should be ICed and keep a reference to x defined on p
6922 "}"
6923 "var result = 0;"
6924 "for (var i = 0; i < 7; i++) {"
6925 " result += o.x;"
6926 "}"
6927 "result");
6928 CHECK_EQ(42 * 7, value->Int32Value());
6929}
6930
6931
6932// Test the case when we stored callback into
6933// a stub, but it got invalidated later on.
6934THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
6935 v8::HandleScope scope;
6936 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6937 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6938 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6939 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
6940
6941 LocalContext context;
6942 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6943 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6944
6945 v8::Handle<Value> value = CompileRun(
6946 "inbetween = new Object();"
6947 "o.__proto__ = inbetween;"
6948 "inbetween.__proto__ = p;"
6949 "for (var i = 0; i < 10; i++) {"
6950 " o.y;"
6951 // Now it should be ICed and keep a reference to y defined on p
6952 "}"
6953 "inbetween.y = 42;"
6954 "var result = 0;"
6955 "for (var i = 0; i < 10; i++) {"
6956 " result += o.y;"
6957 "}"
6958 "result");
6959 CHECK_EQ(42 * 10, value->Int32Value());
6960}
6961
6962
6963// Test the case when we stored callback into
6964// a stub, but it got invalidated later on due to override on
6965// global object which is between interceptor and callbacks' holders.
6966THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
6967 v8::HandleScope scope;
6968 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6969 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6970 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6971 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
6972
6973 LocalContext context;
6974 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6975 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6976
6977 v8::Handle<Value> value = CompileRun(
6978 "o.__proto__ = this;"
6979 "this.__proto__ = p;"
6980 "for (var i = 0; i < 10; i++) {"
6981 " if (o.y != 239) throw 'oops: ' + o.y;"
6982 // Now it should be ICed and keep a reference to y defined on p
6983 "}"
6984 "this.y = 42;"
6985 "var result = 0;"
6986 "for (var i = 0; i < 10; i++) {"
6987 " result += o.y;"
6988 "}"
6989 "result");
6990 CHECK_EQ(42 * 10, value->Int32Value());
6991}
6992
6993
ager@chromium.orge2902be2009-06-08 12:21:35 +00006994static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
6995 const AccessorInfo& info) {
6996 ApiTestFuzzer::Fuzz();
6997 CHECK(v8_str("x")->Equals(name));
6998 return v8::Integer::New(0);
6999}
7000
7001
7002THREADED_TEST(InterceptorReturningZero) {
7003 CheckInterceptorLoadIC(InterceptorLoadICGetter0,
7004 "o.x == undefined ? 1 : 0",
7005 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007006}
7007
7008
7009static v8::Handle<Value> InterceptorStoreICSetter(
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007010 Local<String> key, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007011 CHECK(v8_str("x")->Equals(key));
7012 CHECK_EQ(42, value->Int32Value());
7013 return value;
7014}
7015
7016
7017// This test should hit the store IC for the interceptor case.
7018THREADED_TEST(InterceptorStoreIC) {
7019 v8::HandleScope scope;
7020 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7021 templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007022 InterceptorStoreICSetter,
7023 0, 0, 0, v8_str("data"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007024 LocalContext context;
7025 context->Global()->Set(v8_str("o"), templ->NewInstance());
7026 v8::Handle<Value> value = CompileRun(
7027 "for (var i = 0; i < 1000; i++) {"
7028 " o.x = 42;"
7029 "}");
7030}
7031
7032
ager@chromium.orgeadaf222009-06-16 09:43:10 +00007033THREADED_TEST(InterceptorStoreICWithNoSetter) {
7034 v8::HandleScope scope;
7035 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7036 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7037 LocalContext context;
7038 context->Global()->Set(v8_str("o"), templ->NewInstance());
7039 v8::Handle<Value> value = CompileRun(
7040 "for (var i = 0; i < 1000; i++) {"
7041 " o.y = 239;"
7042 "}"
7043 "42 + o.y");
7044 CHECK_EQ(239 + 42, value->Int32Value());
7045}
7046
7047
7048
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007049
7050v8::Handle<Value> call_ic_function;
7051v8::Handle<Value> call_ic_function2;
7052v8::Handle<Value> call_ic_function3;
7053
7054static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
7055 const AccessorInfo& info) {
7056 ApiTestFuzzer::Fuzz();
7057 CHECK(v8_str("x")->Equals(name));
7058 return call_ic_function;
7059}
7060
7061
7062// This test should hit the call IC for the interceptor case.
7063THREADED_TEST(InterceptorCallIC) {
7064 v8::HandleScope scope;
7065 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7066 templ->SetNamedPropertyHandler(InterceptorCallICGetter);
7067 LocalContext context;
7068 context->Global()->Set(v8_str("o"), templ->NewInstance());
7069 call_ic_function =
7070 v8_compile("function f(x) { return x + 1; }; f")->Run();
7071 v8::Handle<Value> value = CompileRun(
7072 "var result = 0;"
7073 "for (var i = 0; i < 1000; i++) {"
7074 " result = o.x(41);"
7075 "}");
7076 CHECK_EQ(42, value->Int32Value());
7077}
7078
kasperl@chromium.orge959c182009-07-27 08:59:04 +00007079
7080// This test checks that if interceptor doesn't provide
7081// a value, we can fetch regular value.
7082THREADED_TEST(InterceptorCallICSeesOthers) {
7083 v8::HandleScope scope;
7084 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7085 templ->SetNamedPropertyHandler(NoBlockGetterX);
7086 LocalContext context;
7087 context->Global()->Set(v8_str("o"), templ->NewInstance());
7088 v8::Handle<Value> value = CompileRun(
7089 "o.x = function f(x) { return x + 1; };"
7090 "var result = 0;"
7091 "for (var i = 0; i < 7; i++) {"
7092 " result = o.x(41);"
7093 "}");
7094 CHECK_EQ(42, value->Int32Value());
7095}
7096
7097
7098static v8::Handle<Value> call_ic_function4;
7099static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
7100 const AccessorInfo& info) {
7101 ApiTestFuzzer::Fuzz();
7102 CHECK(v8_str("x")->Equals(name));
7103 return call_ic_function4;
7104}
7105
7106
7107// This test checks that if interceptor provides a function,
7108// even if we cached shadowed variant, interceptor's function
7109// is invoked
7110THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
7111 v8::HandleScope scope;
7112 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7113 templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
7114 LocalContext context;
7115 context->Global()->Set(v8_str("o"), templ->NewInstance());
7116 call_ic_function4 =
7117 v8_compile("function f(x) { return x - 1; }; f")->Run();
7118 v8::Handle<Value> value = CompileRun(
7119 "o.__proto__.x = function(x) { return x + 1; };"
7120 "var result = 0;"
7121 "for (var i = 0; i < 1000; i++) {"
7122 " result = o.x(42);"
7123 "}");
7124 CHECK_EQ(41, value->Int32Value());
7125}
7126
7127
7128// Test the case when we stored cacheable lookup into
7129// a stub, but it got invalidated later on
7130THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
7131 v8::HandleScope scope;
7132 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7133 templ->SetNamedPropertyHandler(NoBlockGetterX);
7134 LocalContext context;
7135 context->Global()->Set(v8_str("o"), templ->NewInstance());
7136 v8::Handle<Value> value = CompileRun(
7137 "proto1 = new Object();"
7138 "proto2 = new Object();"
7139 "o.__proto__ = proto1;"
7140 "proto1.__proto__ = proto2;"
7141 "proto2.y = function(x) { return x + 1; };"
7142 // Invoke it many times to compile a stub
7143 "for (var i = 0; i < 7; i++) {"
7144 " o.y(42);"
7145 "}"
7146 "proto1.y = function(x) { return x - 1; };"
7147 "var result = 0;"
7148 "for (var i = 0; i < 7; i++) {"
7149 " result += o.y(42);"
7150 "}");
7151 CHECK_EQ(41 * 7, value->Int32Value());
7152}
7153
7154
7155static v8::Handle<Value> call_ic_function5;
7156static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
7157 const AccessorInfo& info) {
7158 ApiTestFuzzer::Fuzz();
7159 if (v8_str("x")->Equals(name))
7160 return call_ic_function5;
7161 else
7162 return Local<Value>();
7163}
7164
7165
7166// This test checks that if interceptor doesn't provide a function,
7167// cached constant function is used
7168THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
7169 v8::HandleScope scope;
7170 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7171 templ->SetNamedPropertyHandler(NoBlockGetterX);
7172 LocalContext context;
7173 context->Global()->Set(v8_str("o"), templ->NewInstance());
7174 v8::Handle<Value> value = CompileRun(
7175 "function inc(x) { return x + 1; };"
7176 "inc(1);"
7177 "o.x = inc;"
7178 "var result = 0;"
7179 "for (var i = 0; i < 1000; i++) {"
7180 " result = o.x(42);"
7181 "}");
7182 CHECK_EQ(43, value->Int32Value());
7183}
7184
7185
7186// This test checks that if interceptor provides a function,
7187// even if we cached constant function, interceptor's function
7188// is invoked
7189THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
7190 v8::HandleScope scope;
7191 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7192 templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
7193 LocalContext context;
7194 context->Global()->Set(v8_str("o"), templ->NewInstance());
7195 call_ic_function5 =
7196 v8_compile("function f(x) { return x - 1; }; f")->Run();
7197 v8::Handle<Value> value = CompileRun(
7198 "function inc(x) { return x + 1; };"
7199 "inc(1);"
7200 "o.x = inc;"
7201 "var result = 0;"
7202 "for (var i = 0; i < 1000; i++) {"
7203 " result = o.x(42);"
7204 "}");
7205 CHECK_EQ(41, value->Int32Value());
7206}
7207
7208
7209// Test the case when we stored constant function into
7210// a stub, but it got invalidated later on
7211THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
7212 v8::HandleScope scope;
7213 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7214 templ->SetNamedPropertyHandler(NoBlockGetterX);
7215 LocalContext context;
7216 context->Global()->Set(v8_str("o"), templ->NewInstance());
7217 v8::Handle<Value> value = CompileRun(
7218 "function inc(x) { return x + 1; };"
7219 "inc(1);"
7220 "proto1 = new Object();"
7221 "proto2 = new Object();"
7222 "o.__proto__ = proto1;"
7223 "proto1.__proto__ = proto2;"
7224 "proto2.y = inc;"
7225 // Invoke it many times to compile a stub
7226 "for (var i = 0; i < 7; i++) {"
7227 " o.y(42);"
7228 "}"
7229 "proto1.y = function(x) { return x - 1; };"
7230 "var result = 0;"
7231 "for (var i = 0; i < 7; i++) {"
7232 " result += o.y(42);"
7233 "}");
7234 CHECK_EQ(41 * 7, value->Int32Value());
7235}
7236
7237
7238// Test the case when we stored constant function into
7239// a stub, but it got invalidated later on due to override on
7240// global object which is between interceptor and constant function' holders.
7241THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
7242 v8::HandleScope scope;
7243 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7244 templ->SetNamedPropertyHandler(NoBlockGetterX);
7245 LocalContext context;
7246 context->Global()->Set(v8_str("o"), templ->NewInstance());
7247 v8::Handle<Value> value = CompileRun(
7248 "function inc(x) { return x + 1; };"
7249 "inc(1);"
7250 "o.__proto__ = this;"
7251 "this.__proto__.y = inc;"
7252 // Invoke it many times to compile a stub
7253 "for (var i = 0; i < 7; i++) {"
7254 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
7255 "}"
7256 "this.y = function(x) { return x - 1; };"
7257 "var result = 0;"
7258 "for (var i = 0; i < 7; i++) {"
7259 " result += o.y(42);"
7260 "}");
7261 CHECK_EQ(41 * 7, value->Int32Value());
7262}
7263
7264
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007265// Test the case when actual function to call sits on global object.
7266THREADED_TEST(InterceptorCallICCachedFromGlobal) {
7267 v8::HandleScope scope;
7268 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7269 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
7270
7271 LocalContext context;
7272 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7273
7274 v8::Handle<Value> value = CompileRun(
7275 "try {"
7276 " o.__proto__ = this;"
7277 " for (var i = 0; i < 10; i++) {"
7278 " var v = o.parseFloat('239');"
7279 " if (v != 239) throw v;"
7280 // Now it should be ICed and keep a reference to parseFloat.
7281 " }"
7282 " var result = 0;"
7283 " for (var i = 0; i < 10; i++) {"
7284 " result += o.parseFloat('239');"
7285 " }"
7286 " result"
7287 "} catch(e) {"
7288 " e"
7289 "};");
7290 CHECK_EQ(239 * 10, value->Int32Value());
7291}
7292
ager@chromium.org5c838252010-02-19 08:53:10 +00007293static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
7294 const AccessorInfo& info) {
7295 ApiTestFuzzer::Fuzz();
7296 int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data()));
7297 ++(*call_count);
7298 if ((*call_count) % 20 == 0) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +00007299 i::Heap::CollectAllGarbage(true);
ager@chromium.org5c838252010-02-19 08:53:10 +00007300 }
7301 return v8::Handle<Value>();
7302}
7303
7304static v8::Handle<Value> FastApiCallback_TrivialSignature(
7305 const v8::Arguments& args) {
7306 ApiTestFuzzer::Fuzz();
7307 CHECK_EQ(args.This(), args.Holder());
7308 CHECK(args.Data()->Equals(v8_str("method_data")));
7309 return v8::Integer::New(args[0]->Int32Value() + 1);
7310}
7311
7312static v8::Handle<Value> FastApiCallback_SimpleSignature(
7313 const v8::Arguments& args) {
7314 ApiTestFuzzer::Fuzz();
7315 CHECK_EQ(args.This()->GetPrototype(), args.Holder());
7316 CHECK(args.Data()->Equals(v8_str("method_data")));
7317 // Note, we're using HasRealNamedProperty instead of Has to avoid
7318 // invoking the interceptor again.
7319 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
7320 return v8::Integer::New(args[0]->Int32Value() + 1);
7321}
7322
7323// Helper to maximize the odds of object moving.
7324static void GenerateSomeGarbage() {
7325 CompileRun(
7326 "var garbage;"
7327 "for (var i = 0; i < 1000; i++) {"
7328 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
7329 "}"
7330 "garbage = undefined;");
7331}
7332
7333THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
7334 int interceptor_call_count = 0;
7335 v8::HandleScope scope;
7336 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7337 v8::Handle<v8::FunctionTemplate> method_templ =
7338 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
7339 v8_str("method_data"),
7340 v8::Handle<v8::Signature>());
7341 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7342 proto_templ->Set(v8_str("method"), method_templ);
7343 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7344 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7345 NULL, NULL, NULL, NULL,
7346 v8::External::Wrap(&interceptor_call_count));
7347 LocalContext context;
7348 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7349 GenerateSomeGarbage();
7350 context->Global()->Set(v8_str("o"), fun->NewInstance());
7351 v8::Handle<Value> value = CompileRun(
7352 "var result = 0;"
7353 "for (var i = 0; i < 100; i++) {"
7354 " result = o.method(41);"
7355 "}");
7356 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
7357 CHECK_EQ(100, interceptor_call_count);
7358}
7359
7360THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
7361 int interceptor_call_count = 0;
7362 v8::HandleScope scope;
7363 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7364 v8::Handle<v8::FunctionTemplate> method_templ =
7365 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7366 v8_str("method_data"),
7367 v8::Signature::New(fun_templ));
7368 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7369 proto_templ->Set(v8_str("method"), method_templ);
7370 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7371 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7372 NULL, NULL, NULL, NULL,
7373 v8::External::Wrap(&interceptor_call_count));
7374 LocalContext context;
7375 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7376 GenerateSomeGarbage();
7377 context->Global()->Set(v8_str("o"), fun->NewInstance());
7378 v8::Handle<Value> value = CompileRun(
7379 "o.foo = 17;"
7380 "var receiver = {};"
7381 "receiver.__proto__ = o;"
7382 "var result = 0;"
7383 "for (var i = 0; i < 100; i++) {"
7384 " result = receiver.method(41);"
7385 "}");
7386 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
7387 CHECK_EQ(100, interceptor_call_count);
7388}
7389
7390THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
7391 int interceptor_call_count = 0;
7392 v8::HandleScope scope;
7393 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7394 v8::Handle<v8::FunctionTemplate> method_templ =
7395 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7396 v8_str("method_data"),
7397 v8::Signature::New(fun_templ));
7398 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7399 proto_templ->Set(v8_str("method"), method_templ);
7400 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7401 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7402 NULL, NULL, NULL, NULL,
7403 v8::External::Wrap(&interceptor_call_count));
7404 LocalContext context;
7405 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7406 GenerateSomeGarbage();
7407 context->Global()->Set(v8_str("o"), fun->NewInstance());
7408 v8::Handle<Value> value = CompileRun(
7409 "o.foo = 17;"
7410 "var receiver = {};"
7411 "receiver.__proto__ = o;"
7412 "var result = 0;"
7413 "var saved_result = 0;"
7414 "for (var i = 0; i < 100; i++) {"
7415 " result = receiver.method(41);"
7416 " if (i == 50) {"
7417 " saved_result = result;"
7418 " receiver = {method: function(x) { return x - 1 }};"
7419 " }"
7420 "}");
7421 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
7422 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7423 CHECK_GE(interceptor_call_count, 50);
7424}
7425
7426THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
7427 int interceptor_call_count = 0;
7428 v8::HandleScope scope;
7429 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7430 v8::Handle<v8::FunctionTemplate> method_templ =
7431 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7432 v8_str("method_data"),
7433 v8::Signature::New(fun_templ));
7434 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7435 proto_templ->Set(v8_str("method"), method_templ);
7436 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7437 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7438 NULL, NULL, NULL, NULL,
7439 v8::External::Wrap(&interceptor_call_count));
7440 LocalContext context;
7441 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7442 GenerateSomeGarbage();
7443 context->Global()->Set(v8_str("o"), fun->NewInstance());
7444 v8::Handle<Value> value = CompileRun(
7445 "o.foo = 17;"
7446 "var receiver = {};"
7447 "receiver.__proto__ = o;"
7448 "var result = 0;"
7449 "var saved_result = 0;"
7450 "for (var i = 0; i < 100; i++) {"
7451 " result = receiver.method(41);"
7452 " if (i == 50) {"
7453 " saved_result = result;"
7454 " o.method = function(x) { return x - 1 };"
7455 " }"
7456 "}");
7457 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
7458 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7459 CHECK_GE(interceptor_call_count, 50);
7460}
7461
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00007462THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
7463 int interceptor_call_count = 0;
7464 v8::HandleScope scope;
7465 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7466 v8::Handle<v8::FunctionTemplate> method_templ =
7467 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7468 v8_str("method_data"),
7469 v8::Signature::New(fun_templ));
7470 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7471 proto_templ->Set(v8_str("method"), method_templ);
7472 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7473 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7474 NULL, NULL, NULL, NULL,
7475 v8::External::Wrap(&interceptor_call_count));
7476 LocalContext context;
7477 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7478 GenerateSomeGarbage();
7479 context->Global()->Set(v8_str("o"), fun->NewInstance());
7480 v8::TryCatch try_catch;
7481 v8::Handle<Value> value = CompileRun(
7482 "o.foo = 17;"
7483 "var receiver = {};"
7484 "receiver.__proto__ = o;"
7485 "var result = 0;"
7486 "var saved_result = 0;"
7487 "for (var i = 0; i < 100; i++) {"
7488 " result = receiver.method(41);"
7489 " if (i == 50) {"
7490 " saved_result = result;"
7491 " receiver = 333;"
7492 " }"
7493 "}");
7494 CHECK(try_catch.HasCaught());
7495 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
7496 try_catch.Exception()->ToString());
7497 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7498 CHECK_GE(interceptor_call_count, 50);
7499}
7500
ager@chromium.org5c838252010-02-19 08:53:10 +00007501THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
7502 int interceptor_call_count = 0;
7503 v8::HandleScope scope;
7504 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7505 v8::Handle<v8::FunctionTemplate> method_templ =
7506 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7507 v8_str("method_data"),
7508 v8::Signature::New(fun_templ));
7509 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7510 proto_templ->Set(v8_str("method"), method_templ);
7511 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7512 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7513 NULL, NULL, NULL, NULL,
7514 v8::External::Wrap(&interceptor_call_count));
7515 LocalContext context;
7516 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7517 GenerateSomeGarbage();
7518 context->Global()->Set(v8_str("o"), fun->NewInstance());
7519 v8::TryCatch try_catch;
7520 v8::Handle<Value> value = CompileRun(
7521 "o.foo = 17;"
7522 "var receiver = {};"
7523 "receiver.__proto__ = o;"
7524 "var result = 0;"
7525 "var saved_result = 0;"
7526 "for (var i = 0; i < 100; i++) {"
7527 " result = receiver.method(41);"
7528 " if (i == 50) {"
7529 " saved_result = result;"
7530 " receiver = {method: receiver.method};"
7531 " }"
7532 "}");
7533 CHECK(try_catch.HasCaught());
7534 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
7535 try_catch.Exception()->ToString());
7536 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7537 CHECK_GE(interceptor_call_count, 50);
7538}
7539
7540THREADED_TEST(CallICFastApi_TrivialSignature) {
7541 v8::HandleScope scope;
7542 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7543 v8::Handle<v8::FunctionTemplate> method_templ =
7544 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
7545 v8_str("method_data"),
7546 v8::Handle<v8::Signature>());
7547 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7548 proto_templ->Set(v8_str("method"), method_templ);
7549 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7550 LocalContext context;
7551 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7552 GenerateSomeGarbage();
7553 context->Global()->Set(v8_str("o"), fun->NewInstance());
7554 v8::Handle<Value> value = CompileRun(
7555 "var result = 0;"
7556 "for (var i = 0; i < 100; i++) {"
7557 " result = o.method(41);"
7558 "}");
7559
7560 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
7561}
7562
7563THREADED_TEST(CallICFastApi_SimpleSignature) {
7564 v8::HandleScope scope;
7565 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7566 v8::Handle<v8::FunctionTemplate> method_templ =
7567 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7568 v8_str("method_data"),
7569 v8::Signature::New(fun_templ));
7570 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7571 proto_templ->Set(v8_str("method"), method_templ);
7572 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7573 LocalContext context;
7574 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7575 GenerateSomeGarbage();
7576 context->Global()->Set(v8_str("o"), fun->NewInstance());
7577 v8::Handle<Value> value = CompileRun(
7578 "o.foo = 17;"
7579 "var receiver = {};"
7580 "receiver.__proto__ = o;"
7581 "var result = 0;"
7582 "for (var i = 0; i < 100; i++) {"
7583 " result = receiver.method(41);"
7584 "}");
7585
7586 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
7587}
7588
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00007589THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) {
ager@chromium.org5c838252010-02-19 08:53:10 +00007590 v8::HandleScope scope;
7591 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7592 v8::Handle<v8::FunctionTemplate> method_templ =
7593 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7594 v8_str("method_data"),
7595 v8::Signature::New(fun_templ));
7596 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7597 proto_templ->Set(v8_str("method"), method_templ);
7598 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7599 LocalContext context;
7600 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7601 GenerateSomeGarbage();
7602 context->Global()->Set(v8_str("o"), fun->NewInstance());
7603 v8::Handle<Value> value = CompileRun(
7604 "o.foo = 17;"
7605 "var receiver = {};"
7606 "receiver.__proto__ = o;"
7607 "var result = 0;"
7608 "var saved_result = 0;"
7609 "for (var i = 0; i < 100; i++) {"
7610 " result = receiver.method(41);"
7611 " if (i == 50) {"
7612 " saved_result = result;"
7613 " receiver = {method: function(x) { return x - 1 }};"
7614 " }"
7615 "}");
7616 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
7617 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7618}
7619
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00007620THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) {
7621 v8::HandleScope scope;
7622 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7623 v8::Handle<v8::FunctionTemplate> method_templ =
7624 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7625 v8_str("method_data"),
7626 v8::Signature::New(fun_templ));
7627 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7628 proto_templ->Set(v8_str("method"), method_templ);
7629 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7630 LocalContext context;
7631 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7632 GenerateSomeGarbage();
7633 context->Global()->Set(v8_str("o"), fun->NewInstance());
7634 v8::TryCatch try_catch;
7635 v8::Handle<Value> value = CompileRun(
7636 "o.foo = 17;"
7637 "var receiver = {};"
7638 "receiver.__proto__ = o;"
7639 "var result = 0;"
7640 "var saved_result = 0;"
7641 "for (var i = 0; i < 100; i++) {"
7642 " result = receiver.method(41);"
7643 " if (i == 50) {"
7644 " saved_result = result;"
7645 " receiver = 333;"
7646 " }"
7647 "}");
7648 CHECK(try_catch.HasCaught());
7649 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
7650 try_catch.Exception()->ToString());
7651 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7652}
7653
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007654
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007655v8::Handle<Value> keyed_call_ic_function;
7656
7657static v8::Handle<Value> InterceptorKeyedCallICGetter(
7658 Local<String> name, const AccessorInfo& info) {
7659 ApiTestFuzzer::Fuzz();
7660 if (v8_str("x")->Equals(name)) {
7661 return keyed_call_ic_function;
7662 }
7663 return v8::Handle<Value>();
7664}
7665
7666
7667// Test the case when we stored cacheable lookup into
7668// a stub, but the function name changed (to another cacheable function).
7669THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
7670 v8::HandleScope scope;
7671 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7672 templ->SetNamedPropertyHandler(NoBlockGetterX);
7673 LocalContext context;
7674 context->Global()->Set(v8_str("o"), templ->NewInstance());
7675 v8::Handle<Value> value = CompileRun(
7676 "proto = new Object();"
7677 "proto.y = function(x) { return x + 1; };"
7678 "proto.z = function(x) { return x - 1; };"
7679 "o.__proto__ = proto;"
7680 "var result = 0;"
7681 "var method = 'y';"
7682 "for (var i = 0; i < 10; i++) {"
7683 " if (i == 5) { method = 'z'; };"
7684 " result += o[method](41);"
7685 "}");
7686 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7687}
7688
7689
7690// Test the case when we stored cacheable lookup into
7691// a stub, but the function name changed (and the new function is present
7692// both before and after the interceptor in the prototype chain).
7693THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
7694 v8::HandleScope scope;
7695 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7696 templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
7697 LocalContext context;
7698 context->Global()->Set(v8_str("proto1"), templ->NewInstance());
7699 keyed_call_ic_function =
7700 v8_compile("function f(x) { return x - 1; }; f")->Run();
7701 v8::Handle<Value> value = CompileRun(
7702 "o = new Object();"
7703 "proto2 = new Object();"
7704 "o.y = function(x) { return x + 1; };"
7705 "proto2.y = function(x) { return x + 2; };"
7706 "o.__proto__ = proto1;"
7707 "proto1.__proto__ = proto2;"
7708 "var result = 0;"
7709 "var method = 'x';"
7710 "for (var i = 0; i < 10; i++) {"
7711 " if (i == 5) { method = 'y'; };"
7712 " result += o[method](41);"
7713 "}");
7714 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7715}
7716
7717
7718// Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
7719// on the global object.
7720THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
7721 v8::HandleScope scope;
7722 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7723 templ->SetNamedPropertyHandler(NoBlockGetterX);
7724 LocalContext context;
7725 context->Global()->Set(v8_str("o"), templ->NewInstance());
7726 v8::Handle<Value> value = CompileRun(
7727 "function inc(x) { return x + 1; };"
7728 "inc(1);"
7729 "function dec(x) { return x - 1; };"
7730 "dec(1);"
7731 "o.__proto__ = this;"
7732 "this.__proto__.x = inc;"
7733 "this.__proto__.y = dec;"
7734 "var result = 0;"
7735 "var method = 'x';"
7736 "for (var i = 0; i < 10; i++) {"
7737 " if (i == 5) { method = 'y'; };"
7738 " result += o[method](41);"
7739 "}");
7740 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7741}
7742
7743
7744// Test the case when actual function to call sits on global object.
7745THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
7746 v8::HandleScope scope;
7747 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7748 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
7749 LocalContext context;
7750 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7751
7752 v8::Handle<Value> value = CompileRun(
7753 "function len(x) { return x.length; };"
7754 "o.__proto__ = this;"
7755 "var m = 'parseFloat';"
7756 "var result = 0;"
7757 "for (var i = 0; i < 10; i++) {"
7758 " if (i == 5) {"
7759 " m = 'len';"
7760 " saved_result = result;"
7761 " };"
7762 " result = o[m]('239');"
7763 "}");
7764 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
7765 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7766}
7767
7768// Test the map transition before the interceptor.
7769THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
7770 v8::HandleScope scope;
7771 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7772 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
7773 LocalContext context;
7774 context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
7775
7776 v8::Handle<Value> value = CompileRun(
7777 "var o = new Object();"
7778 "o.__proto__ = proto;"
7779 "o.method = function(x) { return x + 1; };"
7780 "var m = 'method';"
7781 "var result = 0;"
7782 "for (var i = 0; i < 10; i++) {"
7783 " if (i == 5) { o.method = function(x) { return x - 1; }; };"
7784 " result += o[m](41);"
7785 "}");
7786 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7787}
7788
7789
7790// Test the map transition after the interceptor.
7791THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
7792 v8::HandleScope scope;
7793 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7794 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
7795 LocalContext context;
7796 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7797
7798 v8::Handle<Value> value = CompileRun(
7799 "var proto = new Object();"
7800 "o.__proto__ = proto;"
7801 "proto.method = function(x) { return x + 1; };"
7802 "var m = 'method';"
7803 "var result = 0;"
7804 "for (var i = 0; i < 10; i++) {"
7805 " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
7806 " result += o[m](41);"
7807 "}");
7808 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7809}
7810
7811
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007812static int interceptor_call_count = 0;
7813
7814static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
7815 const AccessorInfo& info) {
7816 ApiTestFuzzer::Fuzz();
7817 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
7818 return call_ic_function2;
7819 }
7820 return v8::Handle<Value>();
7821}
7822
7823
7824// This test should hit load and call ICs for the interceptor case.
7825// Once in a while, the interceptor will reply that a property was not
7826// found in which case we should get a reference error.
7827THREADED_TEST(InterceptorICReferenceErrors) {
7828 v8::HandleScope scope;
7829 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7830 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
7831 LocalContext context(0, templ, v8::Handle<Value>());
7832 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
7833 v8::Handle<Value> value = CompileRun(
7834 "function f() {"
7835 " for (var i = 0; i < 1000; i++) {"
7836 " try { x; } catch(e) { return true; }"
7837 " }"
7838 " return false;"
7839 "};"
7840 "f();");
7841 CHECK_EQ(true, value->BooleanValue());
7842 interceptor_call_count = 0;
7843 value = CompileRun(
7844 "function g() {"
7845 " for (var i = 0; i < 1000; i++) {"
7846 " try { x(42); } catch(e) { return true; }"
7847 " }"
7848 " return false;"
7849 "};"
7850 "g();");
7851 CHECK_EQ(true, value->BooleanValue());
7852}
7853
7854
7855static int interceptor_ic_exception_get_count = 0;
7856
7857static v8::Handle<Value> InterceptorICExceptionGetter(
7858 Local<String> name,
7859 const AccessorInfo& info) {
7860 ApiTestFuzzer::Fuzz();
7861 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
7862 return call_ic_function3;
7863 }
7864 if (interceptor_ic_exception_get_count == 20) {
7865 return v8::ThrowException(v8_num(42));
7866 }
7867 // Do not handle get for properties other than x.
7868 return v8::Handle<Value>();
7869}
7870
7871// Test interceptor load/call IC where the interceptor throws an
7872// exception once in a while.
7873THREADED_TEST(InterceptorICGetterExceptions) {
7874 interceptor_ic_exception_get_count = 0;
7875 v8::HandleScope scope;
7876 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7877 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
7878 LocalContext context(0, templ, v8::Handle<Value>());
7879 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
7880 v8::Handle<Value> value = CompileRun(
7881 "function f() {"
7882 " for (var i = 0; i < 100; i++) {"
7883 " try { x; } catch(e) { return true; }"
7884 " }"
7885 " return false;"
7886 "};"
7887 "f();");
7888 CHECK_EQ(true, value->BooleanValue());
7889 interceptor_ic_exception_get_count = 0;
7890 value = CompileRun(
7891 "function f() {"
7892 " for (var i = 0; i < 100; i++) {"
7893 " try { x(42); } catch(e) { return true; }"
7894 " }"
7895 " return false;"
7896 "};"
7897 "f();");
7898 CHECK_EQ(true, value->BooleanValue());
7899}
7900
7901
7902static int interceptor_ic_exception_set_count = 0;
7903
7904static v8::Handle<Value> InterceptorICExceptionSetter(
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007905 Local<String> key, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007906 ApiTestFuzzer::Fuzz();
7907 if (++interceptor_ic_exception_set_count > 20) {
7908 return v8::ThrowException(v8_num(42));
7909 }
7910 // Do not actually handle setting.
7911 return v8::Handle<Value>();
7912}
7913
7914// Test interceptor store IC where the interceptor throws an exception
7915// once in a while.
7916THREADED_TEST(InterceptorICSetterExceptions) {
7917 interceptor_ic_exception_set_count = 0;
7918 v8::HandleScope scope;
7919 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7920 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
7921 LocalContext context(0, templ, v8::Handle<Value>());
7922 v8::Handle<Value> value = CompileRun(
7923 "function f() {"
7924 " for (var i = 0; i < 100; i++) {"
7925 " try { x = 42; } catch(e) { return true; }"
7926 " }"
7927 " return false;"
7928 "};"
7929 "f();");
7930 CHECK_EQ(true, value->BooleanValue());
7931}
7932
7933
7934// Test that we ignore null interceptors.
7935THREADED_TEST(NullNamedInterceptor) {
7936 v8::HandleScope scope;
7937 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7938 templ->SetNamedPropertyHandler(0);
7939 LocalContext context;
7940 templ->Set("x", v8_num(42));
7941 v8::Handle<v8::Object> obj = templ->NewInstance();
7942 context->Global()->Set(v8_str("obj"), obj);
7943 v8::Handle<Value> value = CompileRun("obj.x");
7944 CHECK(value->IsInt32());
7945 CHECK_EQ(42, value->Int32Value());
7946}
7947
7948
7949// Test that we ignore null interceptors.
7950THREADED_TEST(NullIndexedInterceptor) {
7951 v8::HandleScope scope;
7952 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7953 templ->SetIndexedPropertyHandler(0);
7954 LocalContext context;
7955 templ->Set("42", v8_num(42));
7956 v8::Handle<v8::Object> obj = templ->NewInstance();
7957 context->Global()->Set(v8_str("obj"), obj);
7958 v8::Handle<Value> value = CompileRun("obj[42]");
7959 CHECK(value->IsInt32());
7960 CHECK_EQ(42, value->Int32Value());
7961}
7962
7963
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007964THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
7965 v8::HandleScope scope;
7966 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7967 templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7968 LocalContext env;
7969 env->Global()->Set(v8_str("obj"),
7970 templ->GetFunction()->NewInstance());
7971 ExpectTrue("obj.x === 42");
7972 ExpectTrue("!obj.propertyIsEnumerable('x')");
7973}
7974
7975
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007976static v8::Handle<Value> ParentGetter(Local<String> name,
7977 const AccessorInfo& info) {
7978 ApiTestFuzzer::Fuzz();
7979 return v8_num(1);
7980}
7981
7982
7983static v8::Handle<Value> ChildGetter(Local<String> name,
7984 const AccessorInfo& info) {
7985 ApiTestFuzzer::Fuzz();
7986 return v8_num(42);
7987}
7988
7989
7990THREADED_TEST(Overriding) {
7991 v8::HandleScope scope;
7992 LocalContext context;
7993
7994 // Parent template.
7995 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
7996 Local<ObjectTemplate> parent_instance_templ =
7997 parent_templ->InstanceTemplate();
7998 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
7999
8000 // Template that inherits from the parent template.
8001 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
8002 Local<ObjectTemplate> child_instance_templ =
8003 child_templ->InstanceTemplate();
8004 child_templ->Inherit(parent_templ);
8005 // Override 'f'. The child version of 'f' should get called for child
8006 // instances.
8007 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
8008 // Add 'g' twice. The 'g' added last should get called for instances.
8009 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
8010 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
8011
8012 // Add 'h' as an accessor to the proto template with ReadOnly attributes
8013 // so 'h' can be shadowed on the instance object.
8014 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
8015 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
8016 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
8017
8018 // Add 'i' as an accessor to the instance template with ReadOnly attributes
8019 // but the attribute does not have effect because it is duplicated with
8020 // NULL setter.
8021 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
8022 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
8023
8024
8025
8026 // Instantiate the child template.
8027 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
8028
8029 // Check that the child function overrides the parent one.
8030 context->Global()->Set(v8_str("o"), instance);
8031 Local<Value> value = v8_compile("o.f")->Run();
8032 // Check that the 'g' that was added last is hit.
8033 CHECK_EQ(42, value->Int32Value());
8034 value = v8_compile("o.g")->Run();
8035 CHECK_EQ(42, value->Int32Value());
8036
8037 // Check 'h' can be shadowed.
8038 value = v8_compile("o.h = 3; o.h")->Run();
8039 CHECK_EQ(3, value->Int32Value());
8040
8041 // Check 'i' is cannot be shadowed or changed.
8042 value = v8_compile("o.i = 3; o.i")->Run();
8043 CHECK_EQ(42, value->Int32Value());
8044}
8045
8046
8047static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
8048 ApiTestFuzzer::Fuzz();
8049 if (args.IsConstructCall()) {
8050 return v8::Boolean::New(true);
8051 }
8052 return v8::Boolean::New(false);
8053}
8054
8055
8056THREADED_TEST(IsConstructCall) {
8057 v8::HandleScope scope;
8058
8059 // Function template with call handler.
8060 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
8061 templ->SetCallHandler(IsConstructHandler);
8062
8063 LocalContext context;
8064
8065 context->Global()->Set(v8_str("f"), templ->GetFunction());
8066 Local<Value> value = v8_compile("f()")->Run();
8067 CHECK(!value->BooleanValue());
8068 value = v8_compile("new f()")->Run();
8069 CHECK(value->BooleanValue());
8070}
8071
8072
8073THREADED_TEST(ObjectProtoToString) {
8074 v8::HandleScope scope;
8075 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
8076 templ->SetClassName(v8_str("MyClass"));
8077
8078 LocalContext context;
8079
8080 Local<String> customized_tostring = v8_str("customized toString");
8081
8082 // Replace Object.prototype.toString
8083 v8_compile("Object.prototype.toString = function() {"
8084 " return 'customized toString';"
8085 "}")->Run();
8086
8087 // Normal ToString call should call replaced Object.prototype.toString
8088 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
8089 Local<String> value = instance->ToString();
8090 CHECK(value->IsString() && value->Equals(customized_tostring));
8091
8092 // ObjectProtoToString should not call replace toString function.
8093 value = instance->ObjectProtoToString();
8094 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
8095
8096 // Check global
8097 value = context->Global()->ObjectProtoToString();
8098 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
8099
8100 // Check ordinary object
8101 Local<Value> object = v8_compile("new Object()")->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008102 value = object.As<v8::Object>()->ObjectProtoToString();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008103 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
8104}
8105
8106
ager@chromium.orgbeb25712010-11-29 08:02:25 +00008107THREADED_TEST(ObjectGetConstructorName) {
8108 v8::HandleScope scope;
8109 LocalContext context;
8110 v8_compile("function Parent() {};"
8111 "function Child() {};"
8112 "Child.prototype = new Parent();"
8113 "var outer = { inner: function() { } };"
8114 "var p = new Parent();"
8115 "var c = new Child();"
8116 "var x = new outer.inner();")->Run();
8117
8118 Local<v8::Value> p = context->Global()->Get(v8_str("p"));
8119 CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
8120 v8_str("Parent")));
8121
8122 Local<v8::Value> c = context->Global()->Get(v8_str("c"));
8123 CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
8124 v8_str("Child")));
8125
8126 Local<v8::Value> x = context->Global()->Get(v8_str("x"));
8127 CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
8128 v8_str("outer.inner")));
8129}
8130
8131
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008132bool ApiTestFuzzer::fuzzing_ = false;
lrn@chromium.org32d961d2010-06-30 09:09:34 +00008133i::Semaphore* ApiTestFuzzer::all_tests_done_=
8134 i::OS::CreateSemaphore(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008135int ApiTestFuzzer::active_tests_;
8136int ApiTestFuzzer::tests_being_run_;
8137int ApiTestFuzzer::current_;
8138
8139
8140// We are in a callback and want to switch to another thread (if we
8141// are currently running the thread fuzzing test).
8142void ApiTestFuzzer::Fuzz() {
8143 if (!fuzzing_) return;
8144 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
8145 test->ContextSwitch();
8146}
8147
8148
8149// Let the next thread go. Since it is also waiting on the V8 lock it may
8150// not start immediately.
8151bool ApiTestFuzzer::NextThread() {
8152 int test_position = GetNextTestNumber();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008153 const char* test_name = RegisterThreadedTest::nth(current_)->name();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008154 if (test_position == current_) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008155 if (kLogThreading)
8156 printf("Stay with %s\n", test_name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008157 return false;
8158 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008159 if (kLogThreading) {
8160 printf("Switch from %s to %s\n",
8161 test_name,
8162 RegisterThreadedTest::nth(test_position)->name());
8163 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008164 current_ = test_position;
8165 RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
8166 return true;
8167}
8168
8169
8170void ApiTestFuzzer::Run() {
8171 // When it is our turn...
8172 gate_->Wait();
8173 {
8174 // ... get the V8 lock and start running the test.
8175 v8::Locker locker;
8176 CallTest();
8177 }
8178 // This test finished.
8179 active_ = false;
8180 active_tests_--;
8181 // If it was the last then signal that fact.
8182 if (active_tests_ == 0) {
8183 all_tests_done_->Signal();
8184 } else {
8185 // Otherwise select a new test and start that.
8186 NextThread();
8187 }
8188}
8189
8190
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008191static unsigned linear_congruential_generator;
8192
8193
8194void ApiTestFuzzer::Setup(PartOfTest part) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008195 linear_congruential_generator = i::FLAG_testing_prng_seed;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008196 fuzzing_ = true;
8197 int start = (part == FIRST_PART) ? 0 : (RegisterThreadedTest::count() >> 1);
8198 int end = (part == FIRST_PART)
8199 ? (RegisterThreadedTest::count() >> 1)
8200 : RegisterThreadedTest::count();
8201 active_tests_ = tests_being_run_ = end - start;
8202 for (int i = 0; i < tests_being_run_; i++) {
8203 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
8204 }
8205 for (int i = 0; i < active_tests_; i++) {
8206 RegisterThreadedTest::nth(i)->fuzzer_->Start();
8207 }
8208}
8209
8210
8211static void CallTestNumber(int test_number) {
8212 (RegisterThreadedTest::nth(test_number)->callback())();
8213}
8214
8215
8216void ApiTestFuzzer::RunAllTests() {
8217 // Set off the first test.
8218 current_ = -1;
8219 NextThread();
8220 // Wait till they are all done.
8221 all_tests_done_->Wait();
8222}
8223
8224
8225int ApiTestFuzzer::GetNextTestNumber() {
8226 int next_test;
8227 do {
8228 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
8229 linear_congruential_generator *= 1664525u;
8230 linear_congruential_generator += 1013904223u;
8231 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
8232 return next_test;
8233}
8234
8235
8236void ApiTestFuzzer::ContextSwitch() {
8237 // If the new thread is the same as the current thread there is nothing to do.
8238 if (NextThread()) {
8239 // Now it can start.
8240 v8::Unlocker unlocker;
8241 // Wait till someone starts us again.
8242 gate_->Wait();
8243 // And we're off.
8244 }
8245}
8246
8247
8248void ApiTestFuzzer::TearDown() {
8249 fuzzing_ = false;
ager@chromium.org41826e72009-03-30 13:30:57 +00008250 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
8251 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
8252 if (fuzzer != NULL) fuzzer->Join();
8253 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008254}
8255
8256
8257// Lets not be needlessly self-referential.
8258TEST(Threading) {
8259 ApiTestFuzzer::Setup(ApiTestFuzzer::FIRST_PART);
8260 ApiTestFuzzer::RunAllTests();
8261 ApiTestFuzzer::TearDown();
8262}
8263
8264TEST(Threading2) {
8265 ApiTestFuzzer::Setup(ApiTestFuzzer::SECOND_PART);
8266 ApiTestFuzzer::RunAllTests();
8267 ApiTestFuzzer::TearDown();
8268}
8269
8270
8271void ApiTestFuzzer::CallTest() {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008272 if (kLogThreading)
8273 printf("Start test %d\n", test_number_);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008274 CallTestNumber(test_number_);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008275 if (kLogThreading)
8276 printf("End test %d\n", test_number_);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008277}
8278
8279
8280static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008281 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008282 ApiTestFuzzer::Fuzz();
8283 v8::Unlocker unlocker;
8284 const char* code = "throw 7;";
8285 {
8286 v8::Locker nested_locker;
8287 v8::HandleScope scope;
8288 v8::Handle<Value> exception;
8289 { v8::TryCatch try_catch;
8290 v8::Handle<Value> value = CompileRun(code);
8291 CHECK(value.IsEmpty());
8292 CHECK(try_catch.HasCaught());
8293 // Make sure to wrap the exception in a new handle because
8294 // the handle returned from the TryCatch is destroyed
8295 // when the TryCatch is destroyed.
8296 exception = Local<Value>::New(try_catch.Exception());
8297 }
8298 return v8::ThrowException(exception);
8299 }
8300}
8301
8302
8303static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008304 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008305 ApiTestFuzzer::Fuzz();
8306 v8::Unlocker unlocker;
8307 const char* code = "throw 7;";
8308 {
8309 v8::Locker nested_locker;
8310 v8::HandleScope scope;
8311 v8::Handle<Value> value = CompileRun(code);
8312 CHECK(value.IsEmpty());
8313 return v8_str("foo");
8314 }
8315}
8316
8317
8318// These are locking tests that don't need to be run again
8319// as part of the locking aggregation tests.
8320TEST(NestedLockers) {
8321 v8::Locker locker;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008322 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008323 v8::HandleScope scope;
8324 LocalContext env;
8325 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
8326 Local<Function> fun = fun_templ->GetFunction();
8327 env->Global()->Set(v8_str("throw_in_js"), fun);
8328 Local<Script> script = v8_compile("(function () {"
8329 " try {"
8330 " throw_in_js();"
8331 " return 42;"
8332 " } catch (e) {"
8333 " return e * 13;"
8334 " }"
8335 "})();");
8336 CHECK_EQ(91, script->Run()->Int32Value());
8337}
8338
8339
8340// These are locking tests that don't need to be run again
8341// as part of the locking aggregation tests.
8342TEST(NestedLockersNoTryCatch) {
8343 v8::Locker locker;
8344 v8::HandleScope scope;
8345 LocalContext env;
8346 Local<v8::FunctionTemplate> fun_templ =
8347 v8::FunctionTemplate::New(ThrowInJSNoCatch);
8348 Local<Function> fun = fun_templ->GetFunction();
8349 env->Global()->Set(v8_str("throw_in_js"), fun);
8350 Local<Script> script = v8_compile("(function () {"
8351 " try {"
8352 " throw_in_js();"
8353 " return 42;"
8354 " } catch (e) {"
8355 " return e * 13;"
8356 " }"
8357 "})();");
8358 CHECK_EQ(91, script->Run()->Int32Value());
8359}
8360
8361
8362THREADED_TEST(RecursiveLocking) {
8363 v8::Locker locker;
8364 {
8365 v8::Locker locker2;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008366 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008367 }
8368}
8369
8370
8371static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
8372 ApiTestFuzzer::Fuzz();
8373 v8::Unlocker unlocker;
8374 return v8::Undefined();
8375}
8376
8377
8378THREADED_TEST(LockUnlockLock) {
8379 {
8380 v8::Locker locker;
8381 v8::HandleScope scope;
8382 LocalContext env;
8383 Local<v8::FunctionTemplate> fun_templ =
8384 v8::FunctionTemplate::New(UnlockForAMoment);
8385 Local<Function> fun = fun_templ->GetFunction();
8386 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
8387 Local<Script> script = v8_compile("(function () {"
8388 " unlock_for_a_moment();"
8389 " return 42;"
8390 "})();");
8391 CHECK_EQ(42, script->Run()->Int32Value());
8392 }
8393 {
8394 v8::Locker locker;
8395 v8::HandleScope scope;
8396 LocalContext env;
8397 Local<v8::FunctionTemplate> fun_templ =
8398 v8::FunctionTemplate::New(UnlockForAMoment);
8399 Local<Function> fun = fun_templ->GetFunction();
8400 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
8401 Local<Script> script = v8_compile("(function () {"
8402 " unlock_for_a_moment();"
8403 " return 42;"
8404 "})();");
8405 CHECK_EQ(42, script->Run()->Int32Value());
8406 }
8407}
8408
8409
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008410static int GetGlobalObjectsCount() {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008411 int count = 0;
lrn@chromium.org32d961d2010-06-30 09:09:34 +00008412 i::HeapIterator it;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008413 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
8414 if (object->IsJSGlobalObject()) count++;
8415 return count;
8416}
8417
8418
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00008419static void CheckSurvivingGlobalObjectsCount(int expected) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008420 // We need to collect all garbage twice to be sure that everything
8421 // has been collected. This is because inline caches are cleared in
8422 // the first garbage collection but some of the maps have already
8423 // been marked at that point. Therefore some of the maps are not
8424 // collected until the second garbage collection.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00008425 i::Heap::CollectAllGarbage(false);
8426 i::Heap::CollectAllGarbage(false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008427 int count = GetGlobalObjectsCount();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008428#ifdef DEBUG
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00008429 if (count != expected) i::Heap::TracePathToGlobal();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008430#endif
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00008431 CHECK_EQ(expected, count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008432}
8433
8434
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008435TEST(DontLeakGlobalObjects) {
8436 // Regression test for issues 1139850 and 1174891.
8437
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008438 v8::V8::Initialize();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008439
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008440 for (int i = 0; i < 5; i++) {
8441 { v8::HandleScope scope;
8442 LocalContext context;
8443 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00008444 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008445
8446 { v8::HandleScope scope;
8447 LocalContext context;
8448 v8_compile("Date")->Run();
8449 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00008450 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008451
8452 { v8::HandleScope scope;
8453 LocalContext context;
8454 v8_compile("/aaa/")->Run();
8455 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00008456 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008457
8458 { v8::HandleScope scope;
8459 const char* extension_list[] = { "v8/gc" };
8460 v8::ExtensionConfiguration extensions(1, extension_list);
8461 LocalContext context(&extensions);
8462 v8_compile("gc();")->Run();
8463 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00008464 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008465 }
8466}
8467
8468
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00008469v8::Persistent<v8::Object> some_object;
8470v8::Persistent<v8::Object> bad_handle;
8471
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00008472void NewPersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) {
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00008473 v8::HandleScope scope;
8474 bad_handle = v8::Persistent<v8::Object>::New(some_object);
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00008475 handle.Dispose();
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00008476}
8477
8478
8479THREADED_TEST(NewPersistentHandleFromWeakCallback) {
8480 LocalContext context;
8481
8482 v8::Persistent<v8::Object> handle1, handle2;
8483 {
8484 v8::HandleScope scope;
8485 some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
8486 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
8487 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
8488 }
8489 // Note: order is implementation dependent alas: currently
8490 // global handle nodes are processed by PostGarbageCollectionProcessing
8491 // in reverse allocation order, so if second allocated handle is deleted,
8492 // weak callback of the first handle would be able to 'reallocate' it.
8493 handle1.MakeWeak(NULL, NewPersistentHandleCallback);
8494 handle2.Dispose();
ager@chromium.orgab99eea2009-08-25 07:05:41 +00008495 i::Heap::CollectAllGarbage(false);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00008496}
8497
8498
8499v8::Persistent<v8::Object> to_be_disposed;
8500
8501void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
8502 to_be_disposed.Dispose();
ager@chromium.orgab99eea2009-08-25 07:05:41 +00008503 i::Heap::CollectAllGarbage(false);
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00008504 handle.Dispose();
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00008505}
8506
8507
8508THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
8509 LocalContext context;
8510
8511 v8::Persistent<v8::Object> handle1, handle2;
8512 {
8513 v8::HandleScope scope;
8514 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
8515 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
8516 }
8517 handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
8518 to_be_disposed = handle2;
ager@chromium.orgab99eea2009-08-25 07:05:41 +00008519 i::Heap::CollectAllGarbage(false);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00008520}
8521
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008522void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
8523 handle.Dispose();
8524}
8525
8526void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
8527 v8::HandleScope scope;
8528 v8::Persistent<v8::Object>::New(v8::Object::New());
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00008529 handle.Dispose();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008530}
8531
8532
8533THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
8534 LocalContext context;
8535
8536 v8::Persistent<v8::Object> handle1, handle2, handle3;
8537 {
8538 v8::HandleScope scope;
8539 handle3 = v8::Persistent<v8::Object>::New(v8::Object::New());
8540 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
8541 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
8542 }
8543 handle2.MakeWeak(NULL, DisposingCallback);
8544 handle3.MakeWeak(NULL, HandleCreatingCallback);
8545 i::Heap::CollectAllGarbage(false);
8546}
8547
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00008548
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008549THREADED_TEST(CheckForCrossContextObjectLiterals) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008550 v8::V8::Initialize();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008551
8552 const int nof = 2;
8553 const char* sources[nof] = {
8554 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
8555 "Object()"
8556 };
8557
8558 for (int i = 0; i < nof; i++) {
8559 const char* source = sources[i];
8560 { v8::HandleScope scope;
8561 LocalContext context;
8562 CompileRun(source);
8563 }
8564 { v8::HandleScope scope;
8565 LocalContext context;
8566 CompileRun(source);
8567 }
8568 }
8569}
8570
8571
8572static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
8573 v8::HandleScope inner;
8574 env->Enter();
8575 v8::Handle<Value> three = v8_num(3);
8576 v8::Handle<Value> value = inner.Close(three);
8577 env->Exit();
8578 return value;
8579}
8580
8581
8582THREADED_TEST(NestedHandleScopeAndContexts) {
8583 v8::HandleScope outer;
8584 v8::Persistent<Context> env = Context::New();
8585 env->Enter();
8586 v8::Handle<Value> value = NestedScope(env);
8587 v8::Handle<String> str = value->ToString();
8588 env->Exit();
8589 env.Dispose();
8590}
8591
8592
8593THREADED_TEST(ExternalAllocatedMemory) {
8594 v8::HandleScope outer;
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008595 v8::Persistent<Context> env = Context::New();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008596 const int kSize = 1024*1024;
8597 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
8598 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
8599}
8600
8601
8602THREADED_TEST(DisposeEnteredContext) {
8603 v8::HandleScope scope;
8604 LocalContext outer;
8605 { v8::Persistent<v8::Context> inner = v8::Context::New();
8606 inner->Enter();
8607 inner.Dispose();
8608 inner.Clear();
8609 inner->Exit();
8610 }
8611}
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008612
8613
8614// Regression test for issue 54, object templates with internal fields
8615// but no accessors or interceptors did not get their internal field
8616// count set on instances.
8617THREADED_TEST(Regress54) {
8618 v8::HandleScope outer;
8619 LocalContext context;
8620 static v8::Persistent<v8::ObjectTemplate> templ;
8621 if (templ.IsEmpty()) {
8622 v8::HandleScope inner;
8623 v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
8624 local->SetInternalFieldCount(1);
8625 templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
8626 }
8627 v8::Handle<v8::Object> result = templ->NewInstance();
8628 CHECK_EQ(1, result->InternalFieldCount());
8629}
8630
8631
8632// If part of the threaded tests, this test makes ThreadingTest fail
8633// on mac.
8634TEST(CatchStackOverflow) {
8635 v8::HandleScope scope;
8636 LocalContext context;
8637 v8::TryCatch try_catch;
8638 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
8639 "function f() {"
8640 " return f();"
8641 "}"
8642 ""
8643 "f();"));
8644 v8::Handle<v8::Value> result = script->Run();
8645 CHECK(result.IsEmpty());
8646}
8647
8648
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008649static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
8650 const char* resource_name,
8651 int line_offset) {
8652 v8::HandleScope scope;
8653 v8::TryCatch try_catch;
8654 v8::Handle<v8::Value> result = script->Run();
8655 CHECK(result.IsEmpty());
8656 CHECK(try_catch.HasCaught());
8657 v8::Handle<v8::Message> message = try_catch.Message();
8658 CHECK(!message.IsEmpty());
8659 CHECK_EQ(10 + line_offset, message->GetLineNumber());
8660 CHECK_EQ(91, message->GetStartPosition());
8661 CHECK_EQ(92, message->GetEndPosition());
8662 CHECK_EQ(2, message->GetStartColumn());
8663 CHECK_EQ(3, message->GetEndColumn());
8664 v8::String::AsciiValue line(message->GetSourceLine());
8665 CHECK_EQ(" throw 'nirk';", *line);
8666 v8::String::AsciiValue name(message->GetScriptResourceName());
8667 CHECK_EQ(resource_name, *name);
8668}
8669
8670
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008671THREADED_TEST(TryCatchSourceInfo) {
8672 v8::HandleScope scope;
8673 LocalContext context;
8674 v8::Handle<v8::String> source = v8::String::New(
8675 "function Foo() {\n"
8676 " return Bar();\n"
8677 "}\n"
8678 "\n"
8679 "function Bar() {\n"
8680 " return Baz();\n"
8681 "}\n"
8682 "\n"
8683 "function Baz() {\n"
8684 " throw 'nirk';\n"
8685 "}\n"
8686 "\n"
8687 "Foo();\n");
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008688
8689 const char* resource_name;
8690 v8::Handle<v8::Script> script;
8691 resource_name = "test.js";
8692 script = v8::Script::Compile(source, v8::String::New(resource_name));
8693 CheckTryCatchSourceInfo(script, resource_name, 0);
8694
8695 resource_name = "test1.js";
8696 v8::ScriptOrigin origin1(v8::String::New(resource_name));
8697 script = v8::Script::Compile(source, &origin1);
8698 CheckTryCatchSourceInfo(script, resource_name, 0);
8699
8700 resource_name = "test2.js";
8701 v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
8702 script = v8::Script::Compile(source, &origin2);
8703 CheckTryCatchSourceInfo(script, resource_name, 7);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008704}
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008705
8706
8707THREADED_TEST(CompilationCache) {
8708 v8::HandleScope scope;
8709 LocalContext context;
8710 v8::Handle<v8::String> source0 = v8::String::New("1234");
8711 v8::Handle<v8::String> source1 = v8::String::New("1234");
8712 v8::Handle<v8::Script> script0 =
8713 v8::Script::Compile(source0, v8::String::New("test.js"));
8714 v8::Handle<v8::Script> script1 =
8715 v8::Script::Compile(source1, v8::String::New("test.js"));
8716 v8::Handle<v8::Script> script2 =
8717 v8::Script::Compile(source0); // different origin
8718 CHECK_EQ(1234, script0->Run()->Int32Value());
8719 CHECK_EQ(1234, script1->Run()->Int32Value());
8720 CHECK_EQ(1234, script2->Run()->Int32Value());
8721}
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008722
8723
8724static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
8725 ApiTestFuzzer::Fuzz();
8726 return v8_num(42);
8727}
8728
8729
8730THREADED_TEST(CallbackFunctionName) {
8731 v8::HandleScope scope;
8732 LocalContext context;
8733 Local<ObjectTemplate> t = ObjectTemplate::New();
8734 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
8735 context->Global()->Set(v8_str("obj"), t->NewInstance());
8736 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
8737 CHECK(value->IsString());
8738 v8::String::AsciiValue name(value);
8739 CHECK_EQ("asdf", *name);
8740}
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008741
8742
8743THREADED_TEST(DateAccess) {
8744 v8::HandleScope scope;
8745 LocalContext context;
8746 v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
8747 CHECK(date->IsDate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008748 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008749}
8750
8751
8752void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008753 v8::Handle<v8::Object> obj = val.As<v8::Object>();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008754 v8::Handle<v8::Array> props = obj->GetPropertyNames();
8755 CHECK_EQ(elmc, props->Length());
8756 for (int i = 0; i < elmc; i++) {
8757 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
8758 CHECK_EQ(elmv[i], *elm);
8759 }
8760}
8761
8762
8763THREADED_TEST(PropertyEnumeration) {
8764 v8::HandleScope scope;
8765 LocalContext context;
8766 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
8767 "var result = [];"
8768 "result[0] = {};"
8769 "result[1] = {a: 1, b: 2};"
8770 "result[2] = [1, 2, 3];"
8771 "var proto = {x: 1, y: 2, z: 3};"
8772 "var x = { __proto__: proto, w: 0, z: 1 };"
8773 "result[3] = x;"
8774 "result;"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008775 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008776 CHECK_EQ(4, elms->Length());
8777 int elmc0 = 0;
8778 const char** elmv0 = NULL;
8779 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
8780 int elmc1 = 2;
8781 const char* elmv1[] = {"a", "b"};
8782 CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
8783 int elmc2 = 3;
8784 const char* elmv2[] = {"0", "1", "2"};
8785 CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
8786 int elmc3 = 4;
8787 const char* elmv3[] = {"w", "z", "x", "y"};
8788 CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
8789}
ager@chromium.org870a0b62008-11-04 11:43:05 +00008790
8791
ager@chromium.org870a0b62008-11-04 11:43:05 +00008792static bool NamedSetAccessBlocker(Local<v8::Object> obj,
8793 Local<Value> name,
8794 v8::AccessType type,
8795 Local<Value> data) {
8796 return type != v8::ACCESS_SET;
8797}
8798
8799
8800static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
8801 uint32_t key,
8802 v8::AccessType type,
8803 Local<Value> data) {
8804 return type != v8::ACCESS_SET;
8805}
8806
8807
8808THREADED_TEST(DisableAccessChecksWhileConfiguring) {
8809 v8::HandleScope scope;
8810 LocalContext context;
8811 Local<ObjectTemplate> templ = ObjectTemplate::New();
8812 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
8813 IndexedSetAccessBlocker);
8814 templ->Set(v8_str("x"), v8::True());
8815 Local<v8::Object> instance = templ->NewInstance();
8816 context->Global()->Set(v8_str("obj"), instance);
8817 Local<Value> value = CompileRun("obj.x");
8818 CHECK(value->BooleanValue());
8819}
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008820
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008821
ager@chromium.org32912102009-01-16 10:38:43 +00008822static bool NamedGetAccessBlocker(Local<v8::Object> obj,
8823 Local<Value> name,
8824 v8::AccessType type,
8825 Local<Value> data) {
8826 return false;
8827}
8828
8829
8830static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
8831 uint32_t key,
8832 v8::AccessType type,
8833 Local<Value> data) {
8834 return false;
8835}
8836
8837
8838
8839THREADED_TEST(AccessChecksReenabledCorrectly) {
8840 v8::HandleScope scope;
8841 LocalContext context;
8842 Local<ObjectTemplate> templ = ObjectTemplate::New();
8843 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
8844 IndexedGetAccessBlocker);
8845 templ->Set(v8_str("a"), v8_str("a"));
8846 // Add more than 8 (see kMaxFastProperties) properties
8847 // so that the constructor will force copying map.
8848 // Cannot sprintf, gcc complains unsafety.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008849 char buf[4];
ager@chromium.org32912102009-01-16 10:38:43 +00008850 for (char i = '0'; i <= '9' ; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008851 buf[0] = i;
ager@chromium.org32912102009-01-16 10:38:43 +00008852 for (char j = '0'; j <= '9'; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008853 buf[1] = j;
ager@chromium.org32912102009-01-16 10:38:43 +00008854 for (char k = '0'; k <= '9'; k++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008855 buf[2] = k;
8856 buf[3] = 0;
ager@chromium.org32912102009-01-16 10:38:43 +00008857 templ->Set(v8_str(buf), v8::Number::New(k));
8858 }
8859 }
8860 }
8861
8862 Local<v8::Object> instance_1 = templ->NewInstance();
8863 context->Global()->Set(v8_str("obj_1"), instance_1);
8864
8865 Local<Value> value_1 = CompileRun("obj_1.a");
8866 CHECK(value_1->IsUndefined());
8867
8868 Local<v8::Object> instance_2 = templ->NewInstance();
8869 context->Global()->Set(v8_str("obj_2"), instance_2);
8870
8871 Local<Value> value_2 = CompileRun("obj_2.a");
8872 CHECK(value_2->IsUndefined());
8873}
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008874
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008875
ager@chromium.org8bb60582008-12-11 12:02:20 +00008876// This tests that access check information remains on the global
8877// object template when creating contexts.
8878THREADED_TEST(AccessControlRepeatedContextCreation) {
8879 v8::HandleScope handle_scope;
8880 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
8881 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
8882 IndexedSetAccessBlocker);
8883 i::Handle<i::ObjectTemplateInfo> internal_template =
8884 v8::Utils::OpenHandle(*global_template);
8885 CHECK(!internal_template->constructor()->IsUndefined());
8886 i::Handle<i::FunctionTemplateInfo> constructor(
8887 i::FunctionTemplateInfo::cast(internal_template->constructor()));
8888 CHECK(!constructor->access_check_info()->IsUndefined());
8889 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
8890 CHECK(!constructor->access_check_info()->IsUndefined());
8891}
8892
8893
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008894THREADED_TEST(TurnOnAccessCheck) {
8895 v8::HandleScope handle_scope;
8896
8897 // Create an environment with access check to the global object disabled by
8898 // default.
8899 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
8900 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
8901 IndexedGetAccessBlocker,
8902 v8::Handle<v8::Value>(),
8903 false);
8904 v8::Persistent<Context> context = Context::New(NULL, global_template);
8905 Context::Scope context_scope(context);
8906
8907 // Set up a property and a number of functions.
8908 context->Global()->Set(v8_str("a"), v8_num(1));
8909 CompileRun("function f1() {return a;}"
8910 "function f2() {return a;}"
8911 "function g1() {return h();}"
8912 "function g2() {return h();}"
8913 "function h() {return 1;}");
8914 Local<Function> f1 =
8915 Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
8916 Local<Function> f2 =
8917 Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
8918 Local<Function> g1 =
8919 Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
8920 Local<Function> g2 =
8921 Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
8922 Local<Function> h =
8923 Local<Function>::Cast(context->Global()->Get(v8_str("h")));
8924
8925 // Get the global object.
8926 v8::Handle<v8::Object> global = context->Global();
8927
8928 // Call f1 one time and f2 a number of times. This will ensure that f1 still
8929 // uses the runtime system to retreive property a whereas f2 uses global load
8930 // inline cache.
8931 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
8932 for (int i = 0; i < 4; i++) {
8933 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
8934 }
8935
8936 // Same for g1 and g2.
8937 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
8938 for (int i = 0; i < 4; i++) {
8939 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
8940 }
8941
8942 // Detach the global and turn on access check.
8943 context->DetachGlobal();
8944 context->Global()->TurnOnAccessCheck();
8945
8946 // Failing access check to property get results in undefined.
8947 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
8948 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
8949
8950 // Failing access check to function call results in exception.
8951 CHECK(g1->Call(global, 0, NULL).IsEmpty());
8952 CHECK(g2->Call(global, 0, NULL).IsEmpty());
8953
8954 // No failing access check when just returning a constant.
8955 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
8956}
8957
8958
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008959v8::Handle<v8::String> a;
8960v8::Handle<v8::String> h;
8961
8962static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
8963 Local<Value> name,
8964 v8::AccessType type,
8965 Local<Value> data) {
8966 return !(name->Equals(a) || name->Equals(h));
8967}
8968
8969
8970THREADED_TEST(TurnOnAccessCheckAndRecompile) {
8971 v8::HandleScope handle_scope;
8972
8973 // Create an environment with access check to the global object disabled by
8974 // default. When the registered access checker will block access to properties
8975 // a and h
8976 a = v8_str("a");
8977 h = v8_str("h");
8978 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
8979 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
8980 IndexedGetAccessBlocker,
8981 v8::Handle<v8::Value>(),
8982 false);
8983 v8::Persistent<Context> context = Context::New(NULL, global_template);
8984 Context::Scope context_scope(context);
8985
8986 // Set up a property and a number of functions.
8987 context->Global()->Set(v8_str("a"), v8_num(1));
8988 static const char* source = "function f1() {return a;}"
8989 "function f2() {return a;}"
8990 "function g1() {return h();}"
8991 "function g2() {return h();}"
8992 "function h() {return 1;}";
8993
8994 CompileRun(source);
8995 Local<Function> f1;
8996 Local<Function> f2;
8997 Local<Function> g1;
8998 Local<Function> g2;
8999 Local<Function> h;
9000 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
9001 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
9002 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
9003 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
9004 h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
9005
9006 // Get the global object.
9007 v8::Handle<v8::Object> global = context->Global();
9008
9009 // Call f1 one time and f2 a number of times. This will ensure that f1 still
9010 // uses the runtime system to retreive property a whereas f2 uses global load
9011 // inline cache.
9012 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
9013 for (int i = 0; i < 4; i++) {
9014 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
9015 }
9016
9017 // Same for g1 and g2.
9018 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
9019 for (int i = 0; i < 4; i++) {
9020 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
9021 }
9022
9023 // Detach the global and turn on access check now blocking access to property
9024 // a and function h.
9025 context->DetachGlobal();
9026 context->Global()->TurnOnAccessCheck();
9027
9028 // Failing access check to property get results in undefined.
9029 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
9030 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
9031
9032 // Failing access check to function call results in exception.
9033 CHECK(g1->Call(global, 0, NULL).IsEmpty());
9034 CHECK(g2->Call(global, 0, NULL).IsEmpty());
9035
9036 // No failing access check when just returning a constant.
9037 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
9038
9039 // Now compile the source again. And get the newly compiled functions, except
9040 // for h for which access is blocked.
9041 CompileRun(source);
9042 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
9043 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
9044 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
9045 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
9046 CHECK(context->Global()->Get(v8_str("h"))->IsUndefined());
9047
9048 // Failing access check to property get results in undefined.
9049 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
9050 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
9051
9052 // Failing access check to function call results in exception.
9053 CHECK(g1->Call(global, 0, NULL).IsEmpty());
9054 CHECK(g2->Call(global, 0, NULL).IsEmpty());
9055}
9056
9057
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009058// This test verifies that pre-compilation (aka preparsing) can be called
9059// without initializing the whole VM. Thus we cannot run this test in a
9060// multi-threaded setup.
9061TEST(PreCompile) {
9062 // TODO(155): This test would break without the initialization of V8. This is
9063 // a workaround for now to make this test not fail.
9064 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009065 const char* script = "function foo(a) { return a+1; }";
9066 v8::ScriptData* sd =
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009067 v8::ScriptData::PreCompile(script, i::StrLength(script));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009068 CHECK_NE(sd->Length(), 0);
9069 CHECK_NE(sd->Data(), NULL);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009070 CHECK(!sd->HasError());
9071 delete sd;
9072}
9073
9074
9075TEST(PreCompileWithError) {
9076 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009077 const char* script = "function foo(a) { return 1 * * 2; }";
9078 v8::ScriptData* sd =
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009079 v8::ScriptData::PreCompile(script, i::StrLength(script));
9080 CHECK(sd->HasError());
9081 delete sd;
9082}
9083
9084
9085TEST(Regress31661) {
9086 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009087 const char* script = " The Definintive Guide";
9088 v8::ScriptData* sd =
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009089 v8::ScriptData::PreCompile(script, i::StrLength(script));
9090 CHECK(sd->HasError());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009091 delete sd;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009092}
9093
9094
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009095// Tests that ScriptData can be serialized and deserialized.
9096TEST(PreCompileSerialization) {
9097 v8::V8::Initialize();
9098 const char* script = "function foo(a) { return a+1; }";
9099 v8::ScriptData* sd =
9100 v8::ScriptData::PreCompile(script, i::StrLength(script));
9101
9102 // Serialize.
9103 int serialized_data_length = sd->Length();
9104 char* serialized_data = i::NewArray<char>(serialized_data_length);
9105 memcpy(serialized_data, sd->Data(), serialized_data_length);
9106
9107 // Deserialize.
9108 v8::ScriptData* deserialized_sd =
9109 v8::ScriptData::New(serialized_data, serialized_data_length);
9110
9111 // Verify that the original is the same as the deserialized.
9112 CHECK_EQ(sd->Length(), deserialized_sd->Length());
9113 CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
9114 CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
9115
9116 delete sd;
9117 delete deserialized_sd;
9118}
9119
9120
9121// Attempts to deserialize bad data.
9122TEST(PreCompileDeserializationError) {
9123 v8::V8::Initialize();
9124 const char* data = "DONT CARE";
9125 int invalid_size = 3;
9126 v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
9127
9128 CHECK_EQ(0, sd->Length());
9129
9130 delete sd;
9131}
9132
9133
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00009134// Attempts to deserialize bad data.
9135TEST(PreCompileInvalidPreparseDataError) {
9136 v8::V8::Initialize();
9137 v8::HandleScope scope;
9138 LocalContext context;
9139
9140 const char* script = "function foo(){ return 5;}\n"
9141 "function bar(){ return 6 + 7;} foo();";
9142 v8::ScriptData* sd =
9143 v8::ScriptData::PreCompile(script, i::StrLength(script));
9144 CHECK(!sd->HasError());
9145 // ScriptDataImpl private implementation details
ager@chromium.orgbeb25712010-11-29 08:02:25 +00009146 const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00009147 const int kFunctionEntrySize = i::FunctionEntry::kSize;
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00009148 const int kFunctionEntryStartOffset = 0;
9149 const int kFunctionEntryEndOffset = 1;
9150 unsigned* sd_data =
9151 reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00009152
9153 // Overwrite function bar's end position with 0.
9154 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
9155 v8::TryCatch try_catch;
9156
9157 Local<String> source = String::New(script);
9158 Local<Script> compiled_script = Script::New(source, NULL, sd);
9159 CHECK(try_catch.HasCaught());
9160 String::AsciiValue exception_value(try_catch.Message()->Get());
9161 CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
9162 *exception_value);
9163
9164 try_catch.Reset();
9165 // Overwrite function bar's start position with 200. The function entry
9166 // will not be found when searching for it by position.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00009167 sd = v8::ScriptData::PreCompile(script, i::StrLength(script));
9168 sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00009169 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
9170 200;
9171 compiled_script = Script::New(source, NULL, sd);
9172 CHECK(try_catch.HasCaught());
9173 String::AsciiValue second_exception_value(try_catch.Message()->Get());
9174 CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
9175 *second_exception_value);
9176
9177 delete sd;
9178}
9179
9180
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00009181// Verifies that the Handle<String> and const char* versions of the API produce
9182// the same results (at least for one trivial case).
9183TEST(PreCompileAPIVariationsAreSame) {
9184 v8::V8::Initialize();
9185 v8::HandleScope scope;
9186
9187 const char* cstring = "function foo(a) { return a+1; }";
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009188
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00009189 v8::ScriptData* sd_from_cstring =
9190 v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
9191
9192 TestAsciiResource* resource = new TestAsciiResource(cstring);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009193 v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile(
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00009194 v8::String::NewExternal(resource));
9195
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009196 v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile(
9197 v8::String::New(cstring));
9198
9199 CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00009200 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009201 sd_from_external_string->Data(),
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00009202 sd_from_cstring->Length()));
9203
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009204 CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length());
9205 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
9206 sd_from_string->Data(),
9207 sd_from_cstring->Length()));
9208
9209
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00009210 delete sd_from_cstring;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009211 delete sd_from_external_string;
9212 delete sd_from_string;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00009213}
9214
9215
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009216// This tests that we do not allow dictionary load/call inline caches
9217// to use functions that have not yet been compiled. The potential
9218// problem of loading a function that has not yet been compiled can
9219// arise because we share code between contexts via the compilation
9220// cache.
9221THREADED_TEST(DictionaryICLoadedFunction) {
9222 v8::HandleScope scope;
9223 // Test LoadIC.
9224 for (int i = 0; i < 2; i++) {
9225 LocalContext context;
9226 context->Global()->Set(v8_str("tmp"), v8::True());
9227 context->Global()->Delete(v8_str("tmp"));
9228 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
9229 }
9230 // Test CallIC.
9231 for (int i = 0; i < 2; i++) {
9232 LocalContext context;
9233 context->Global()->Set(v8_str("tmp"), v8::True());
9234 context->Global()->Delete(v8_str("tmp"));
9235 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
9236 }
9237}
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009238
9239
9240// Test that cross-context new calls use the context of the callee to
9241// create the new JavaScript object.
9242THREADED_TEST(CrossContextNew) {
9243 v8::HandleScope scope;
9244 v8::Persistent<Context> context0 = Context::New();
9245 v8::Persistent<Context> context1 = Context::New();
9246
9247 // Allow cross-domain access.
9248 Local<String> token = v8_str("<security token>");
9249 context0->SetSecurityToken(token);
9250 context1->SetSecurityToken(token);
9251
9252 // Set an 'x' property on the Object prototype and define a
9253 // constructor function in context0.
9254 context0->Enter();
9255 CompileRun("Object.prototype.x = 42; function C() {};");
9256 context0->Exit();
9257
9258 // Call the constructor function from context0 and check that the
9259 // result has the 'x' property.
9260 context1->Enter();
9261 context1->Global()->Set(v8_str("other"), context0->Global());
9262 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
9263 CHECK(value->IsInt32());
9264 CHECK_EQ(42, value->Int32Value());
9265 context1->Exit();
9266
9267 // Dispose the contexts to allow them to be garbage collected.
9268 context0.Dispose();
9269 context1.Dispose();
9270}
ager@chromium.org381abbb2009-02-25 13:23:22 +00009271
9272
9273class RegExpInterruptTest {
9274 public:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009275 RegExpInterruptTest() : block_(NULL) {}
9276 ~RegExpInterruptTest() { delete block_; }
ager@chromium.org381abbb2009-02-25 13:23:22 +00009277 void RunTest() {
9278 block_ = i::OS::CreateSemaphore(0);
9279 gc_count_ = 0;
9280 gc_during_regexp_ = 0;
9281 regexp_success_ = false;
9282 gc_success_ = false;
9283 GCThread gc_thread(this);
9284 gc_thread.Start();
9285 v8::Locker::StartPreemption(1);
9286
9287 LongRunningRegExp();
9288 {
9289 v8::Unlocker unlock;
9290 gc_thread.Join();
9291 }
9292 v8::Locker::StopPreemption();
9293 CHECK(regexp_success_);
9294 CHECK(gc_success_);
9295 }
9296 private:
9297 // Number of garbage collections required.
9298 static const int kRequiredGCs = 5;
9299
9300 class GCThread : public i::Thread {
9301 public:
9302 explicit GCThread(RegExpInterruptTest* test)
9303 : test_(test) {}
9304 virtual void Run() {
9305 test_->CollectGarbage();
9306 }
9307 private:
9308 RegExpInterruptTest* test_;
9309 };
9310
9311 void CollectGarbage() {
9312 block_->Wait();
9313 while (gc_during_regexp_ < kRequiredGCs) {
9314 {
9315 v8::Locker lock;
9316 // TODO(lrn): Perhaps create some garbage before collecting.
ager@chromium.orgab99eea2009-08-25 07:05:41 +00009317 i::Heap::CollectAllGarbage(false);
ager@chromium.org381abbb2009-02-25 13:23:22 +00009318 gc_count_++;
9319 }
9320 i::OS::Sleep(1);
9321 }
9322 gc_success_ = true;
9323 }
9324
9325 void LongRunningRegExp() {
9326 block_->Signal(); // Enable garbage collection thread on next preemption.
9327 int rounds = 0;
9328 while (gc_during_regexp_ < kRequiredGCs) {
9329 int gc_before = gc_count_;
9330 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009331 // Match 15-30 "a"'s against 14 and a "b".
ager@chromium.org381abbb2009-02-25 13:23:22 +00009332 const char* c_source =
9333 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
9334 ".exec('aaaaaaaaaaaaaaab') === null";
9335 Local<String> source = String::New(c_source);
9336 Local<Script> script = Script::Compile(source);
9337 Local<Value> result = script->Run();
9338 if (!result->BooleanValue()) {
9339 gc_during_regexp_ = kRequiredGCs; // Allow gc thread to exit.
9340 return;
9341 }
9342 }
9343 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009344 // Match 15-30 "a"'s against 15 and a "b".
ager@chromium.org381abbb2009-02-25 13:23:22 +00009345 const char* c_source =
9346 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
9347 ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
9348 Local<String> source = String::New(c_source);
9349 Local<Script> script = Script::Compile(source);
9350 Local<Value> result = script->Run();
9351 if (!result->BooleanValue()) {
9352 gc_during_regexp_ = kRequiredGCs;
9353 return;
9354 }
9355 }
9356 int gc_after = gc_count_;
9357 gc_during_regexp_ += gc_after - gc_before;
9358 rounds++;
9359 i::OS::Sleep(1);
9360 }
9361 regexp_success_ = true;
9362 }
9363
9364 i::Semaphore* block_;
9365 int gc_count_;
9366 int gc_during_regexp_;
9367 bool regexp_success_;
9368 bool gc_success_;
9369};
9370
9371
9372// Test that a regular expression execution can be interrupted and
9373// survive a garbage collection.
9374TEST(RegExpInterruption) {
9375 v8::Locker lock;
9376 v8::V8::Initialize();
9377 v8::HandleScope scope;
9378 Local<Context> local_env;
9379 {
9380 LocalContext env;
9381 local_env = env.local();
9382 }
9383
9384 // Local context should still be live.
9385 CHECK(!local_env.IsEmpty());
9386 local_env->Enter();
9387
9388 // Should complete without problems.
9389 RegExpInterruptTest().RunTest();
9390
9391 local_env->Exit();
9392}
ager@chromium.org3b45ab52009-03-19 22:21:34 +00009393
9394
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009395class ApplyInterruptTest {
9396 public:
9397 ApplyInterruptTest() : block_(NULL) {}
9398 ~ApplyInterruptTest() { delete block_; }
9399 void RunTest() {
9400 block_ = i::OS::CreateSemaphore(0);
9401 gc_count_ = 0;
9402 gc_during_apply_ = 0;
9403 apply_success_ = false;
9404 gc_success_ = false;
9405 GCThread gc_thread(this);
9406 gc_thread.Start();
9407 v8::Locker::StartPreemption(1);
9408
9409 LongRunningApply();
9410 {
9411 v8::Unlocker unlock;
9412 gc_thread.Join();
9413 }
9414 v8::Locker::StopPreemption();
9415 CHECK(apply_success_);
9416 CHECK(gc_success_);
9417 }
9418 private:
9419 // Number of garbage collections required.
9420 static const int kRequiredGCs = 2;
9421
9422 class GCThread : public i::Thread {
9423 public:
9424 explicit GCThread(ApplyInterruptTest* test)
9425 : test_(test) {}
9426 virtual void Run() {
9427 test_->CollectGarbage();
9428 }
9429 private:
9430 ApplyInterruptTest* test_;
9431 };
9432
9433 void CollectGarbage() {
9434 block_->Wait();
9435 while (gc_during_apply_ < kRequiredGCs) {
9436 {
9437 v8::Locker lock;
ager@chromium.orgab99eea2009-08-25 07:05:41 +00009438 i::Heap::CollectAllGarbage(false);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009439 gc_count_++;
9440 }
9441 i::OS::Sleep(1);
9442 }
9443 gc_success_ = true;
9444 }
9445
9446 void LongRunningApply() {
9447 block_->Signal();
9448 int rounds = 0;
9449 while (gc_during_apply_ < kRequiredGCs) {
9450 int gc_before = gc_count_;
9451 {
9452 const char* c_source =
9453 "function do_very_little(bar) {"
9454 " this.foo = bar;"
9455 "}"
9456 "for (var i = 0; i < 100000; i++) {"
9457 " do_very_little.apply(this, ['bar']);"
9458 "}";
9459 Local<String> source = String::New(c_source);
9460 Local<Script> script = Script::Compile(source);
9461 Local<Value> result = script->Run();
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00009462 // Check that no exception was thrown.
9463 CHECK(!result.IsEmpty());
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009464 }
9465 int gc_after = gc_count_;
9466 gc_during_apply_ += gc_after - gc_before;
9467 rounds++;
9468 }
9469 apply_success_ = true;
9470 }
9471
9472 i::Semaphore* block_;
9473 int gc_count_;
9474 int gc_during_apply_;
9475 bool apply_success_;
9476 bool gc_success_;
9477};
9478
9479
9480// Test that nothing bad happens if we get a preemption just when we were
9481// about to do an apply().
9482TEST(ApplyInterruption) {
9483 v8::Locker lock;
9484 v8::V8::Initialize();
9485 v8::HandleScope scope;
9486 Local<Context> local_env;
9487 {
9488 LocalContext env;
9489 local_env = env.local();
9490 }
9491
9492 // Local context should still be live.
9493 CHECK(!local_env.IsEmpty());
9494 local_env->Enter();
9495
9496 // Should complete without problems.
9497 ApplyInterruptTest().RunTest();
9498
9499 local_env->Exit();
9500}
9501
9502
ager@chromium.org3b45ab52009-03-19 22:21:34 +00009503// Verify that we can clone an object
9504TEST(ObjectClone) {
9505 v8::HandleScope scope;
9506 LocalContext env;
9507
9508 const char* sample =
9509 "var rv = {};" \
9510 "rv.alpha = 'hello';" \
9511 "rv.beta = 123;" \
9512 "rv;";
9513
9514 // Create an object, verify basics.
9515 Local<Value> val = CompileRun(sample);
9516 CHECK(val->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009517 Local<v8::Object> obj = val.As<v8::Object>();
ager@chromium.org3b45ab52009-03-19 22:21:34 +00009518 obj->Set(v8_str("gamma"), v8_str("cloneme"));
9519
9520 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
9521 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
9522 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
9523
9524 // Clone it.
9525 Local<v8::Object> clone = obj->Clone();
9526 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
9527 CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
9528 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
9529
9530 // Set a property on the clone, verify each object.
9531 clone->Set(v8_str("beta"), v8::Integer::New(456));
9532 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
9533 CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
9534}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009535
9536
ager@chromium.org5ec48922009-05-05 07:25:34 +00009537class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
9538 public:
9539 explicit AsciiVectorResource(i::Vector<const char> vector)
9540 : data_(vector) {}
9541 virtual ~AsciiVectorResource() {}
9542 virtual size_t length() const { return data_.length(); }
9543 virtual const char* data() const { return data_.start(); }
9544 private:
9545 i::Vector<const char> data_;
9546};
9547
9548
9549class UC16VectorResource : public v8::String::ExternalStringResource {
9550 public:
9551 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
9552 : data_(vector) {}
9553 virtual ~UC16VectorResource() {}
9554 virtual size_t length() const { return data_.length(); }
9555 virtual const i::uc16* data() const { return data_.start(); }
9556 private:
9557 i::Vector<const i::uc16> data_;
9558};
9559
9560
9561static void MorphAString(i::String* string,
9562 AsciiVectorResource* ascii_resource,
9563 UC16VectorResource* uc16_resource) {
9564 CHECK(i::StringShape(string).IsExternal());
9565 if (string->IsAsciiRepresentation()) {
9566 // Check old map is not symbol or long.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009567 CHECK(string->map() == i::Heap::external_ascii_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009568 // Morph external string to be TwoByte string.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009569 string->set_map(i::Heap::external_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009570 i::ExternalTwoByteString* morphed =
9571 i::ExternalTwoByteString::cast(string);
9572 morphed->set_resource(uc16_resource);
9573 } else {
9574 // Check old map is not symbol or long.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009575 CHECK(string->map() == i::Heap::external_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009576 // Morph external string to be ASCII string.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009577 string->set_map(i::Heap::external_ascii_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009578 i::ExternalAsciiString* morphed =
9579 i::ExternalAsciiString::cast(string);
9580 morphed->set_resource(ascii_resource);
9581 }
9582}
9583
9584
9585// Test that we can still flatten a string if the components it is built up
9586// from have been turned into 16 bit strings in the mean time.
9587THREADED_TEST(MorphCompositeStringTest) {
9588 const char* c_string = "Now is the time for all good men"
9589 " to come to the aid of the party";
9590 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
9591 {
9592 v8::HandleScope scope;
9593 LocalContext env;
9594 AsciiVectorResource ascii_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009595 i::Vector<const char>(c_string, i::StrLength(c_string)));
ager@chromium.org5ec48922009-05-05 07:25:34 +00009596 UC16VectorResource uc16_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009597 i::Vector<const uint16_t>(two_byte_string,
9598 i::StrLength(c_string)));
ager@chromium.org5ec48922009-05-05 07:25:34 +00009599
9600 Local<String> lhs(v8::Utils::ToLocal(
9601 i::Factory::NewExternalStringFromAscii(&ascii_resource)));
9602 Local<String> rhs(v8::Utils::ToLocal(
9603 i::Factory::NewExternalStringFromAscii(&ascii_resource)));
9604
9605 env->Global()->Set(v8_str("lhs"), lhs);
9606 env->Global()->Set(v8_str("rhs"), rhs);
9607
9608 CompileRun(
9609 "var cons = lhs + rhs;"
9610 "var slice = lhs.substring(1, lhs.length - 1);"
9611 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
9612
9613 MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
9614 MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
9615
9616 // Now do some stuff to make sure the strings are flattened, etc.
9617 CompileRun(
9618 "/[^a-z]/.test(cons);"
9619 "/[^a-z]/.test(slice);"
9620 "/[^a-z]/.test(slice_on_cons);");
9621 const char* expected_cons =
9622 "Now is the time for all good men to come to the aid of the party"
9623 "Now is the time for all good men to come to the aid of the party";
9624 const char* expected_slice =
9625 "ow is the time for all good men to come to the aid of the part";
9626 const char* expected_slice_on_cons =
9627 "ow is the time for all good men to come to the aid of the party"
9628 "Now is the time for all good men to come to the aid of the part";
9629 CHECK_EQ(String::New(expected_cons),
9630 env->Global()->Get(v8_str("cons")));
9631 CHECK_EQ(String::New(expected_slice),
9632 env->Global()->Get(v8_str("slice")));
9633 CHECK_EQ(String::New(expected_slice_on_cons),
9634 env->Global()->Get(v8_str("slice_on_cons")));
9635 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009636 i::DeleteArray(two_byte_string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009637}
9638
9639
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009640TEST(CompileExternalTwoByteSource) {
9641 v8::HandleScope scope;
9642 LocalContext context;
9643
9644 // This is a very short list of sources, which currently is to check for a
9645 // regression caused by r2703.
9646 const char* ascii_sources[] = {
9647 "0.5",
9648 "-0.5", // This mainly testes PushBack in the Scanner.
9649 "--0.5", // This mainly testes PushBack in the Scanner.
9650 NULL
9651 };
9652
9653 // Compile the sources as external two byte strings.
9654 for (int i = 0; ascii_sources[i] != NULL; i++) {
9655 uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
9656 UC16VectorResource uc16_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009657 i::Vector<const uint16_t>(two_byte_string,
9658 i::StrLength(ascii_sources[i])));
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009659 v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
9660 v8::Script::Compile(source);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009661 i::DeleteArray(two_byte_string);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009662 }
9663}
9664
9665
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009666class RegExpStringModificationTest {
9667 public:
9668 RegExpStringModificationTest()
9669 : block_(i::OS::CreateSemaphore(0)),
9670 morphs_(0),
9671 morphs_during_regexp_(0),
9672 ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
9673 uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
9674 ~RegExpStringModificationTest() { delete block_; }
9675 void RunTest() {
9676 regexp_success_ = false;
9677 morph_success_ = false;
9678
9679 // Initialize the contents of two_byte_content_ to be a uc16 representation
9680 // of "aaaaaaaaaaaaaab".
9681 for (int i = 0; i < 14; i++) {
9682 two_byte_content_[i] = 'a';
9683 }
9684 two_byte_content_[14] = 'b';
9685
9686 // Create the input string for the regexp - the one we are going to change
9687 // properties of.
9688 input_ = i::Factory::NewExternalStringFromAscii(&ascii_resource_);
9689
9690 // Inject the input as a global variable.
9691 i::Handle<i::String> input_name =
9692 i::Factory::NewStringFromAscii(i::Vector<const char>("input", 5));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009693 i::Top::global_context()->global()->SetProperty(*input_name,
9694 *input_,
9695 NONE)->ToObjectChecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009696
9697
9698 MorphThread morph_thread(this);
9699 morph_thread.Start();
9700 v8::Locker::StartPreemption(1);
9701 LongRunningRegExp();
9702 {
9703 v8::Unlocker unlock;
9704 morph_thread.Join();
9705 }
9706 v8::Locker::StopPreemption();
9707 CHECK(regexp_success_);
9708 CHECK(morph_success_);
9709 }
9710 private:
9711
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009712 // Number of string modifications required.
9713 static const int kRequiredModifications = 5;
9714 static const int kMaxModifications = 100;
9715
9716 class MorphThread : public i::Thread {
9717 public:
9718 explicit MorphThread(RegExpStringModificationTest* test)
9719 : test_(test) {}
9720 virtual void Run() {
9721 test_->MorphString();
9722 }
9723 private:
9724 RegExpStringModificationTest* test_;
9725 };
9726
9727 void MorphString() {
9728 block_->Wait();
9729 while (morphs_during_regexp_ < kRequiredModifications &&
9730 morphs_ < kMaxModifications) {
9731 {
9732 v8::Locker lock;
9733 // Swap string between ascii and two-byte representation.
9734 i::String* string = *input_;
ager@chromium.org5ec48922009-05-05 07:25:34 +00009735 MorphAString(string, &ascii_resource_, &uc16_resource_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009736 morphs_++;
9737 }
9738 i::OS::Sleep(1);
9739 }
9740 morph_success_ = true;
9741 }
9742
9743 void LongRunningRegExp() {
9744 block_->Signal(); // Enable morphing thread on next preemption.
9745 while (morphs_during_regexp_ < kRequiredModifications &&
9746 morphs_ < kMaxModifications) {
9747 int morphs_before = morphs_;
9748 {
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00009749 v8::HandleScope scope;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009750 // Match 15-30 "a"'s against 14 and a "b".
9751 const char* c_source =
9752 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
9753 ".exec(input) === null";
9754 Local<String> source = String::New(c_source);
9755 Local<Script> script = Script::Compile(source);
9756 Local<Value> result = script->Run();
9757 CHECK(result->IsTrue());
9758 }
9759 int morphs_after = morphs_;
9760 morphs_during_regexp_ += morphs_after - morphs_before;
9761 }
9762 regexp_success_ = true;
9763 }
9764
9765 i::uc16 two_byte_content_[15];
9766 i::Semaphore* block_;
9767 int morphs_;
9768 int morphs_during_regexp_;
9769 bool regexp_success_;
9770 bool morph_success_;
9771 i::Handle<i::String> input_;
9772 AsciiVectorResource ascii_resource_;
9773 UC16VectorResource uc16_resource_;
9774};
9775
9776
9777// Test that a regular expression execution can be interrupted and
9778// the string changed without failing.
9779TEST(RegExpStringModification) {
9780 v8::Locker lock;
9781 v8::V8::Initialize();
9782 v8::HandleScope scope;
9783 Local<Context> local_env;
9784 {
9785 LocalContext env;
9786 local_env = env.local();
9787 }
9788
9789 // Local context should still be live.
9790 CHECK(!local_env.IsEmpty());
9791 local_env->Enter();
9792
9793 // Should complete without problems.
9794 RegExpStringModificationTest().RunTest();
9795
9796 local_env->Exit();
9797}
9798
9799
9800// Test that we can set a property on the global object even if there
9801// is a read-only property in the prototype chain.
9802TEST(ReadOnlyPropertyInGlobalProto) {
9803 v8::HandleScope scope;
9804 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9805 LocalContext context(0, templ);
9806 v8::Handle<v8::Object> global = context->Global();
9807 v8::Handle<v8::Object> global_proto =
9808 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
9809 global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
9810 global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
9811 // Check without 'eval' or 'with'.
9812 v8::Handle<v8::Value> res =
9813 CompileRun("function f() { x = 42; return x; }; f()");
9814 // Check with 'eval'.
9815 res = CompileRun("function f() { eval('1'); y = 42; return y; }; f()");
9816 CHECK_EQ(v8::Integer::New(42), res);
9817 // Check with 'with'.
9818 res = CompileRun("function f() { with (this) { y = 42 }; return y; }; f()");
9819 CHECK_EQ(v8::Integer::New(42), res);
9820}
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009821
9822static int force_set_set_count = 0;
9823static int force_set_get_count = 0;
9824bool pass_on_get = false;
9825
9826static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
9827 const v8::AccessorInfo& info) {
9828 force_set_get_count++;
9829 if (pass_on_get) {
9830 return v8::Handle<v8::Value>();
9831 } else {
9832 return v8::Int32::New(3);
9833 }
9834}
9835
9836static void ForceSetSetter(v8::Local<v8::String> name,
9837 v8::Local<v8::Value> value,
9838 const v8::AccessorInfo& info) {
9839 force_set_set_count++;
9840}
9841
9842static v8::Handle<v8::Value> ForceSetInterceptSetter(
9843 v8::Local<v8::String> name,
9844 v8::Local<v8::Value> value,
9845 const v8::AccessorInfo& info) {
9846 force_set_set_count++;
9847 return v8::Undefined();
9848}
9849
9850TEST(ForceSet) {
9851 force_set_get_count = 0;
9852 force_set_set_count = 0;
9853 pass_on_get = false;
9854
9855 v8::HandleScope scope;
9856 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9857 v8::Handle<v8::String> access_property = v8::String::New("a");
9858 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
9859 LocalContext context(NULL, templ);
9860 v8::Handle<v8::Object> global = context->Global();
9861
9862 // Ordinary properties
9863 v8::Handle<v8::String> simple_property = v8::String::New("p");
9864 global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
9865 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
9866 // This should fail because the property is read-only
9867 global->Set(simple_property, v8::Int32::New(5));
9868 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
9869 // This should succeed even though the property is read-only
9870 global->ForceSet(simple_property, v8::Int32::New(6));
9871 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
9872
9873 // Accessors
9874 CHECK_EQ(0, force_set_set_count);
9875 CHECK_EQ(0, force_set_get_count);
9876 CHECK_EQ(3, global->Get(access_property)->Int32Value());
9877 // CHECK_EQ the property shouldn't override it, just call the setter
9878 // which in this case does nothing.
9879 global->Set(access_property, v8::Int32::New(7));
9880 CHECK_EQ(3, global->Get(access_property)->Int32Value());
9881 CHECK_EQ(1, force_set_set_count);
9882 CHECK_EQ(2, force_set_get_count);
9883 // Forcing the property to be set should override the accessor without
9884 // calling it
9885 global->ForceSet(access_property, v8::Int32::New(8));
9886 CHECK_EQ(8, global->Get(access_property)->Int32Value());
9887 CHECK_EQ(1, force_set_set_count);
9888 CHECK_EQ(2, force_set_get_count);
9889}
9890
9891TEST(ForceSetWithInterceptor) {
9892 force_set_get_count = 0;
9893 force_set_set_count = 0;
9894 pass_on_get = false;
9895
9896 v8::HandleScope scope;
9897 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9898 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
9899 LocalContext context(NULL, templ);
9900 v8::Handle<v8::Object> global = context->Global();
9901
9902 v8::Handle<v8::String> some_property = v8::String::New("a");
9903 CHECK_EQ(0, force_set_set_count);
9904 CHECK_EQ(0, force_set_get_count);
9905 CHECK_EQ(3, global->Get(some_property)->Int32Value());
9906 // Setting the property shouldn't override it, just call the setter
9907 // which in this case does nothing.
9908 global->Set(some_property, v8::Int32::New(7));
9909 CHECK_EQ(3, global->Get(some_property)->Int32Value());
9910 CHECK_EQ(1, force_set_set_count);
9911 CHECK_EQ(2, force_set_get_count);
9912 // Getting the property when the interceptor returns an empty handle
9913 // should yield undefined, since the property isn't present on the
9914 // object itself yet.
9915 pass_on_get = true;
9916 CHECK(global->Get(some_property)->IsUndefined());
9917 CHECK_EQ(1, force_set_set_count);
9918 CHECK_EQ(3, force_set_get_count);
9919 // Forcing the property to be set should cause the value to be
9920 // set locally without calling the interceptor.
9921 global->ForceSet(some_property, v8::Int32::New(8));
9922 CHECK_EQ(8, global->Get(some_property)->Int32Value());
9923 CHECK_EQ(1, force_set_set_count);
9924 CHECK_EQ(4, force_set_get_count);
9925 // Reenabling the interceptor should cause it to take precedence over
9926 // the property
9927 pass_on_get = false;
9928 CHECK_EQ(3, global->Get(some_property)->Int32Value());
9929 CHECK_EQ(1, force_set_set_count);
9930 CHECK_EQ(5, force_set_get_count);
9931 // The interceptor should also work for other properties
9932 CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
9933 CHECK_EQ(1, force_set_set_count);
9934 CHECK_EQ(6, force_set_get_count);
9935}
ager@chromium.org1bf0cd02009-05-20 11:34:19 +00009936
9937
ager@chromium.orge2902be2009-06-08 12:21:35 +00009938THREADED_TEST(ForceDelete) {
9939 v8::HandleScope scope;
9940 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9941 LocalContext context(NULL, templ);
9942 v8::Handle<v8::Object> global = context->Global();
9943
9944 // Ordinary properties
9945 v8::Handle<v8::String> simple_property = v8::String::New("p");
9946 global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
9947 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
9948 // This should fail because the property is dont-delete.
9949 CHECK(!global->Delete(simple_property));
9950 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
9951 // This should succeed even though the property is dont-delete.
9952 CHECK(global->ForceDelete(simple_property));
9953 CHECK(global->Get(simple_property)->IsUndefined());
9954}
9955
9956
9957static int force_delete_interceptor_count = 0;
9958static bool pass_on_delete = false;
9959
9960
9961static v8::Handle<v8::Boolean> ForceDeleteDeleter(
9962 v8::Local<v8::String> name,
9963 const v8::AccessorInfo& info) {
9964 force_delete_interceptor_count++;
9965 if (pass_on_delete) {
9966 return v8::Handle<v8::Boolean>();
9967 } else {
9968 return v8::True();
9969 }
9970}
9971
9972
9973THREADED_TEST(ForceDeleteWithInterceptor) {
9974 force_delete_interceptor_count = 0;
9975 pass_on_delete = false;
9976
9977 v8::HandleScope scope;
9978 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9979 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
9980 LocalContext context(NULL, templ);
9981 v8::Handle<v8::Object> global = context->Global();
9982
9983 v8::Handle<v8::String> some_property = v8::String::New("a");
9984 global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
9985
9986 // Deleting a property should get intercepted and nothing should
9987 // happen.
9988 CHECK_EQ(0, force_delete_interceptor_count);
9989 CHECK(global->Delete(some_property));
9990 CHECK_EQ(1, force_delete_interceptor_count);
9991 CHECK_EQ(42, global->Get(some_property)->Int32Value());
9992 // Deleting the property when the interceptor returns an empty
9993 // handle should not delete the property since it is DontDelete.
9994 pass_on_delete = true;
9995 CHECK(!global->Delete(some_property));
9996 CHECK_EQ(2, force_delete_interceptor_count);
9997 CHECK_EQ(42, global->Get(some_property)->Int32Value());
9998 // Forcing the property to be deleted should delete the value
9999 // without calling the interceptor.
10000 CHECK(global->ForceDelete(some_property));
10001 CHECK(global->Get(some_property)->IsUndefined());
10002 CHECK_EQ(2, force_delete_interceptor_count);
10003}
10004
10005
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000010006// Make sure that forcing a delete invalidates any IC stubs, so we
10007// don't read the hole value.
10008THREADED_TEST(ForceDeleteIC) {
10009 v8::HandleScope scope;
10010 LocalContext context;
10011 // Create a DontDelete variable on the global object.
10012 CompileRun("this.__proto__ = { foo: 'horse' };"
10013 "var foo = 'fish';"
10014 "function f() { return foo.length; }");
10015 // Initialize the IC for foo in f.
10016 CompileRun("for (var i = 0; i < 4; i++) f();");
10017 // Make sure the value of foo is correct before the deletion.
10018 CHECK_EQ(4, CompileRun("f()")->Int32Value());
10019 // Force the deletion of foo.
10020 CHECK(context->Global()->ForceDelete(v8_str("foo")));
10021 // Make sure the value for foo is read from the prototype, and that
10022 // we don't get in trouble with reading the deleted cell value
10023 // sentinel.
10024 CHECK_EQ(5, CompileRun("f()")->Int32Value());
10025}
10026
10027
ager@chromium.org1bf0cd02009-05-20 11:34:19 +000010028v8::Persistent<Context> calling_context0;
10029v8::Persistent<Context> calling_context1;
10030v8::Persistent<Context> calling_context2;
10031
10032
10033// Check that the call to the callback is initiated in
10034// calling_context2, the directly calling context is calling_context1
10035// and the callback itself is in calling_context0.
10036static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
10037 ApiTestFuzzer::Fuzz();
10038 CHECK(Context::GetCurrent() == calling_context0);
10039 CHECK(Context::GetCalling() == calling_context1);
10040 CHECK(Context::GetEntered() == calling_context2);
10041 return v8::Integer::New(42);
10042}
10043
10044
10045THREADED_TEST(GetCallingContext) {
10046 v8::HandleScope scope;
10047
10048 calling_context0 = Context::New();
10049 calling_context1 = Context::New();
10050 calling_context2 = Context::New();
10051
10052 // Allow cross-domain access.
10053 Local<String> token = v8_str("<security token>");
10054 calling_context0->SetSecurityToken(token);
10055 calling_context1->SetSecurityToken(token);
10056 calling_context2->SetSecurityToken(token);
10057
10058 // Create an object with a C++ callback in context0.
10059 calling_context0->Enter();
10060 Local<v8::FunctionTemplate> callback_templ =
10061 v8::FunctionTemplate::New(GetCallingContextCallback);
10062 calling_context0->Global()->Set(v8_str("callback"),
10063 callback_templ->GetFunction());
10064 calling_context0->Exit();
10065
10066 // Expose context0 in context1 and setup a function that calls the
10067 // callback function.
10068 calling_context1->Enter();
10069 calling_context1->Global()->Set(v8_str("context0"),
10070 calling_context0->Global());
10071 CompileRun("function f() { context0.callback() }");
10072 calling_context1->Exit();
10073
10074 // Expose context1 in context2 and call the callback function in
10075 // context0 indirectly through f in context1.
10076 calling_context2->Enter();
10077 calling_context2->Global()->Set(v8_str("context1"),
10078 calling_context1->Global());
10079 CompileRun("context1.f()");
10080 calling_context2->Exit();
10081
10082 // Dispose the contexts to allow them to be garbage collected.
10083 calling_context0.Dispose();
10084 calling_context1.Dispose();
10085 calling_context2.Dispose();
10086 calling_context0.Clear();
10087 calling_context1.Clear();
10088 calling_context2.Clear();
10089}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010090
10091
10092// Check that a variable declaration with no explicit initialization
10093// value does not shadow an existing property in the prototype chain.
10094//
10095// This is consistent with Firefox and Safari.
10096//
10097// See http://crbug.com/12548.
10098THREADED_TEST(InitGlobalVarInProtoChain) {
10099 v8::HandleScope scope;
10100 LocalContext context;
10101 // Introduce a variable in the prototype chain.
10102 CompileRun("__proto__.x = 42");
10103 v8::Handle<v8::Value> result = CompileRun("var x; x");
10104 CHECK(!result->IsUndefined());
10105 CHECK_EQ(42, result->Int32Value());
10106}
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000010107
10108
10109// Regression test for issue 398.
10110// If a function is added to an object, creating a constant function
10111// field, and the result is cloned, replacing the constant function on the
10112// original should not affect the clone.
10113// See http://code.google.com/p/v8/issues/detail?id=398
10114THREADED_TEST(ReplaceConstantFunction) {
10115 v8::HandleScope scope;
10116 LocalContext context;
10117 v8::Handle<v8::Object> obj = v8::Object::New();
10118 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
10119 v8::Handle<v8::String> foo_string = v8::String::New("foo");
10120 obj->Set(foo_string, func_templ->GetFunction());
10121 v8::Handle<v8::Object> obj_clone = obj->Clone();
10122 obj_clone->Set(foo_string, v8::String::New("Hello"));
10123 CHECK(!obj->Get(foo_string)->IsUndefined());
10124}
kasperl@chromium.orge959c182009-07-27 08:59:04 +000010125
10126
10127// Regression test for http://crbug.com/16276.
10128THREADED_TEST(Regress16276) {
10129 v8::HandleScope scope;
10130 LocalContext context;
10131 // Force the IC in f to be a dictionary load IC.
10132 CompileRun("function f(obj) { return obj.x; }\n"
10133 "var obj = { x: { foo: 42 }, y: 87 };\n"
10134 "var x = obj.x;\n"
10135 "delete obj.y;\n"
10136 "for (var i = 0; i < 5; i++) f(obj);");
10137 // Detach the global object to make 'this' refer directly to the
10138 // global object (not the proxy), and make sure that the dictionary
10139 // load IC doesn't mess up loading directly from the global object.
10140 context->DetachGlobal();
10141 CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
10142}
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010143
10144
10145THREADED_TEST(PixelArray) {
10146 v8::HandleScope scope;
10147 LocalContext context;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010148 const int kElementCount = 260;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010149 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
10150 i::Handle<i::PixelArray> pixels = i::Factory::NewPixelArray(kElementCount,
10151 pixel_data);
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010152 i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010153 for (int i = 0; i < kElementCount; i++) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010154 pixels->set(i, i % 256);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010155 }
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010156 i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010157 for (int i = 0; i < kElementCount; i++) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010158 CHECK_EQ(i % 256, pixels->get(i));
10159 CHECK_EQ(i % 256, pixel_data[i]);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010160 }
10161
10162 v8::Handle<v8::Object> obj = v8::Object::New();
10163 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
10164 // Set the elements to be the pixels.
10165 // jsobj->set_elements(*pixels);
10166 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010167 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010168 obj->Set(v8_str("field"), v8::Int32::New(1503));
10169 context->Global()->Set(v8_str("pixels"), obj);
10170 v8::Handle<v8::Value> result = CompileRun("pixels.field");
10171 CHECK_EQ(1503, result->Int32Value());
10172 result = CompileRun("pixels[1]");
10173 CHECK_EQ(1, result->Int32Value());
sgjesse@chromium.org9eceac12009-09-30 07:18:41 +000010174
10175 result = CompileRun("var sum = 0;"
10176 "for (var i = 0; i < 8; i++) {"
10177 " sum += pixels[i] = pixels[i] = -i;"
10178 "}"
10179 "sum;");
10180 CHECK_EQ(-28, result->Int32Value());
10181
10182 result = CompileRun("var sum = 0;"
10183 "for (var i = 0; i < 8; i++) {"
10184 " sum += pixels[i] = pixels[i] = 0;"
10185 "}"
10186 "sum;");
10187 CHECK_EQ(0, result->Int32Value());
10188
10189 result = CompileRun("var sum = 0;"
10190 "for (var i = 0; i < 8; i++) {"
10191 " sum += pixels[i] = pixels[i] = 255;"
10192 "}"
10193 "sum;");
10194 CHECK_EQ(8 * 255, result->Int32Value());
10195
10196 result = CompileRun("var sum = 0;"
10197 "for (var i = 0; i < 8; i++) {"
10198 " sum += pixels[i] = pixels[i] = 256 + i;"
10199 "}"
10200 "sum;");
10201 CHECK_EQ(2076, result->Int32Value());
10202
10203 result = CompileRun("var sum = 0;"
10204 "for (var i = 0; i < 8; i++) {"
10205 " sum += pixels[i] = pixels[i] = i;"
10206 "}"
10207 "sum;");
10208 CHECK_EQ(28, result->Int32Value());
10209
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010210 result = CompileRun("var sum = 0;"
10211 "for (var i = 0; i < 8; i++) {"
10212 " sum += pixels[i];"
10213 "}"
10214 "sum;");
10215 CHECK_EQ(28, result->Int32Value());
10216
10217 i::Handle<i::Smi> value(i::Smi::FromInt(2));
10218 i::SetElement(jsobj, 1, value);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010219 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010220 *value.location() = i::Smi::FromInt(256);
10221 i::SetElement(jsobj, 1, value);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010222 CHECK_EQ(255,
10223 i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010224 *value.location() = i::Smi::FromInt(-1);
10225 i::SetElement(jsobj, 1, value);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010226 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010227
10228 result = CompileRun("for (var i = 0; i < 8; i++) {"
10229 " pixels[i] = (i * 65) - 109;"
10230 "}"
10231 "pixels[1] + pixels[6];");
10232 CHECK_EQ(255, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010233 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
10234 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
10235 CHECK_EQ(21,
10236 i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
10237 CHECK_EQ(86,
10238 i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
10239 CHECK_EQ(151,
10240 i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
10241 CHECK_EQ(216,
10242 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
10243 CHECK_EQ(255,
10244 i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
10245 CHECK_EQ(255,
10246 i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010247 result = CompileRun("var sum = 0;"
10248 "for (var i = 0; i < 8; i++) {"
10249 " sum += pixels[i];"
10250 "}"
10251 "sum;");
10252 CHECK_EQ(984, result->Int32Value());
10253
10254 result = CompileRun("for (var i = 0; i < 8; i++) {"
10255 " pixels[i] = (i * 1.1);"
10256 "}"
10257 "pixels[1] + pixels[6];");
10258 CHECK_EQ(8, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010259 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
10260 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
10261 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
10262 CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
10263 CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
10264 CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
10265 CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
10266 CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010267
10268 result = CompileRun("for (var i = 0; i < 8; i++) {"
10269 " pixels[7] = undefined;"
10270 "}"
10271 "pixels[7];");
10272 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010273 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010274
10275 result = CompileRun("for (var i = 0; i < 8; i++) {"
10276 " pixels[6] = '2.3';"
10277 "}"
10278 "pixels[6];");
10279 CHECK_EQ(2, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010280 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010281
10282 result = CompileRun("for (var i = 0; i < 8; i++) {"
10283 " pixels[5] = NaN;"
10284 "}"
10285 "pixels[5];");
10286 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010287 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010288
10289 result = CompileRun("for (var i = 0; i < 8; i++) {"
10290 " pixels[8] = Infinity;"
10291 "}"
10292 "pixels[8];");
10293 CHECK_EQ(255, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010294 CHECK_EQ(255,
10295 i::Smi::cast(jsobj->GetElement(8)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010296
10297 result = CompileRun("for (var i = 0; i < 8; i++) {"
10298 " pixels[9] = -Infinity;"
10299 "}"
10300 "pixels[9];");
10301 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010302 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010303
10304 result = CompileRun("pixels[3] = 33;"
10305 "delete pixels[3];"
10306 "pixels[3];");
10307 CHECK_EQ(33, result->Int32Value());
10308
10309 result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
10310 "pixels[2] = 12; pixels[3] = 13;"
10311 "pixels.__defineGetter__('2',"
10312 "function() { return 120; });"
10313 "pixels[2];");
10314 CHECK_EQ(12, result->Int32Value());
10315
10316 result = CompileRun("var js_array = new Array(40);"
10317 "js_array[0] = 77;"
10318 "js_array;");
10319 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
10320
10321 result = CompileRun("pixels[1] = 23;"
10322 "pixels.__proto__ = [];"
10323 "js_array.__proto__ = pixels;"
10324 "js_array.concat(pixels);");
10325 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
10326 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
10327
sgjesse@chromium.org9eceac12009-09-30 07:18:41 +000010328 result = CompileRun("pixels[1] = 23;");
10329 CHECK_EQ(23, result->Int32Value());
10330
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010331 // Test for index greater than 255. Regression test for:
10332 // http://code.google.com/p/chromium/issues/detail?id=26337.
10333 result = CompileRun("pixels[256] = 255;");
10334 CHECK_EQ(255, result->Int32Value());
10335 result = CompileRun("var i = 0;"
10336 "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
10337 "i");
10338 CHECK_EQ(255, result->Int32Value());
10339
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010340 free(pixel_data);
10341}
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000010342
ager@chromium.org96c75b52009-08-26 09:13:16 +000010343
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000010344THREADED_TEST(PixelArrayInfo) {
10345 v8::HandleScope scope;
10346 LocalContext context;
10347 for (int size = 0; size < 100; size += 10) {
10348 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
10349 v8::Handle<v8::Object> obj = v8::Object::New();
10350 obj->SetIndexedPropertiesToPixelData(pixel_data, size);
10351 CHECK(obj->HasIndexedPropertiesInPixelData());
10352 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
10353 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
10354 free(pixel_data);
10355 }
10356}
10357
10358
10359static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
10360 switch (array_type) {
10361 case v8::kExternalByteArray:
10362 case v8::kExternalUnsignedByteArray:
10363 return 1;
10364 break;
10365 case v8::kExternalShortArray:
10366 case v8::kExternalUnsignedShortArray:
10367 return 2;
10368 break;
10369 case v8::kExternalIntArray:
10370 case v8::kExternalUnsignedIntArray:
10371 case v8::kExternalFloatArray:
10372 return 4;
10373 break;
10374 default:
10375 UNREACHABLE();
10376 return -1;
10377 }
10378 UNREACHABLE();
10379 return -1;
10380}
10381
10382
ager@chromium.org3811b432009-10-28 14:53:37 +000010383template <class ExternalArrayClass, class ElementType>
10384static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
10385 int64_t low,
10386 int64_t high) {
10387 v8::HandleScope scope;
10388 LocalContext context;
10389 const int kElementCount = 40;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000010390 int element_size = ExternalArrayElementSize(array_type);
ager@chromium.org3811b432009-10-28 14:53:37 +000010391 ElementType* array_data =
10392 static_cast<ElementType*>(malloc(kElementCount * element_size));
10393 i::Handle<ExternalArrayClass> array =
10394 i::Handle<ExternalArrayClass>::cast(
10395 i::Factory::NewExternalArray(kElementCount, array_type, array_data));
10396 i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
10397 for (int i = 0; i < kElementCount; i++) {
10398 array->set(i, static_cast<ElementType>(i));
10399 }
10400 i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
10401 for (int i = 0; i < kElementCount; i++) {
10402 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array->get(i)));
10403 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
10404 }
10405
10406 v8::Handle<v8::Object> obj = v8::Object::New();
10407 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
10408 // Set the elements to be the external array.
10409 obj->SetIndexedPropertiesToExternalArrayData(array_data,
10410 array_type,
10411 kElementCount);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010412 CHECK_EQ(
10413 1, static_cast<int>(jsobj->GetElement(1)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000010414 obj->Set(v8_str("field"), v8::Int32::New(1503));
10415 context->Global()->Set(v8_str("ext_array"), obj);
10416 v8::Handle<v8::Value> result = CompileRun("ext_array.field");
10417 CHECK_EQ(1503, result->Int32Value());
10418 result = CompileRun("ext_array[1]");
10419 CHECK_EQ(1, result->Int32Value());
10420
10421 // Check pass through of assigned smis
10422 result = CompileRun("var sum = 0;"
10423 "for (var i = 0; i < 8; i++) {"
10424 " sum += ext_array[i] = ext_array[i] = -i;"
10425 "}"
10426 "sum;");
10427 CHECK_EQ(-28, result->Int32Value());
10428
10429 // Check assigned smis
10430 result = CompileRun("for (var i = 0; i < 8; i++) {"
10431 " ext_array[i] = i;"
10432 "}"
10433 "var sum = 0;"
10434 "for (var i = 0; i < 8; i++) {"
10435 " sum += ext_array[i];"
10436 "}"
10437 "sum;");
10438 CHECK_EQ(28, result->Int32Value());
10439
10440 // Check assigned smis in reverse order
10441 result = CompileRun("for (var i = 8; --i >= 0; ) {"
10442 " ext_array[i] = i;"
10443 "}"
10444 "var sum = 0;"
10445 "for (var i = 0; i < 8; i++) {"
10446 " sum += ext_array[i];"
10447 "}"
10448 "sum;");
10449 CHECK_EQ(28, result->Int32Value());
10450
10451 // Check pass through of assigned HeapNumbers
10452 result = CompileRun("var sum = 0;"
10453 "for (var i = 0; i < 16; i+=2) {"
10454 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
10455 "}"
10456 "sum;");
10457 CHECK_EQ(-28, result->Int32Value());
10458
10459 // Check assigned HeapNumbers
10460 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
10461 " ext_array[i] = (i * 0.5);"
10462 "}"
10463 "var sum = 0;"
10464 "for (var i = 0; i < 16; i+=2) {"
10465 " sum += ext_array[i];"
10466 "}"
10467 "sum;");
10468 CHECK_EQ(28, result->Int32Value());
10469
10470 // Check assigned HeapNumbers in reverse order
10471 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
10472 " ext_array[i] = (i * 0.5);"
10473 "}"
10474 "var sum = 0;"
10475 "for (var i = 0; i < 16; i+=2) {"
10476 " sum += ext_array[i];"
10477 "}"
10478 "sum;");
10479 CHECK_EQ(28, result->Int32Value());
10480
10481 i::ScopedVector<char> test_buf(1024);
10482
10483 // Check legal boundary conditions.
10484 // The repeated loads and stores ensure the ICs are exercised.
10485 const char* boundary_program =
10486 "var res = 0;"
10487 "for (var i = 0; i < 16; i++) {"
10488 " ext_array[i] = %lld;"
10489 " if (i > 8) {"
10490 " res = ext_array[i];"
10491 " }"
10492 "}"
10493 "res;";
10494 i::OS::SNPrintF(test_buf,
10495 boundary_program,
10496 low);
10497 result = CompileRun(test_buf.start());
10498 CHECK_EQ(low, result->IntegerValue());
10499
10500 i::OS::SNPrintF(test_buf,
10501 boundary_program,
10502 high);
10503 result = CompileRun(test_buf.start());
10504 CHECK_EQ(high, result->IntegerValue());
10505
10506 // Check misprediction of type in IC.
10507 result = CompileRun("var tmp_array = ext_array;"
10508 "var sum = 0;"
10509 "for (var i = 0; i < 8; i++) {"
10510 " tmp_array[i] = i;"
10511 " sum += tmp_array[i];"
10512 " if (i == 4) {"
10513 " tmp_array = {};"
10514 " }"
10515 "}"
10516 "sum;");
10517 i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
10518 CHECK_EQ(28, result->Int32Value());
10519
10520 // Make sure out-of-range loads do not throw.
10521 i::OS::SNPrintF(test_buf,
10522 "var caught_exception = false;"
10523 "try {"
10524 " ext_array[%d];"
10525 "} catch (e) {"
10526 " caught_exception = true;"
10527 "}"
10528 "caught_exception;",
10529 kElementCount);
10530 result = CompileRun(test_buf.start());
10531 CHECK_EQ(false, result->BooleanValue());
10532
10533 // Make sure out-of-range stores do not throw.
10534 i::OS::SNPrintF(test_buf,
10535 "var caught_exception = false;"
10536 "try {"
10537 " ext_array[%d] = 1;"
10538 "} catch (e) {"
10539 " caught_exception = true;"
10540 "}"
10541 "caught_exception;",
10542 kElementCount);
10543 result = CompileRun(test_buf.start());
10544 CHECK_EQ(false, result->BooleanValue());
10545
10546 // Check other boundary conditions, values and operations.
10547 result = CompileRun("for (var i = 0; i < 8; i++) {"
10548 " ext_array[7] = undefined;"
10549 "}"
10550 "ext_array[7];");
10551 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010552 CHECK_EQ(
10553 0, static_cast<int>(jsobj->GetElement(7)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000010554
10555 result = CompileRun("for (var i = 0; i < 8; i++) {"
10556 " ext_array[6] = '2.3';"
10557 "}"
10558 "ext_array[6];");
10559 CHECK_EQ(2, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010560 CHECK_EQ(
10561 2, static_cast<int>(jsobj->GetElement(6)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000010562
10563 if (array_type != v8::kExternalFloatArray) {
10564 // Though the specification doesn't state it, be explicit about
10565 // converting NaNs and +/-Infinity to zero.
10566 result = CompileRun("for (var i = 0; i < 8; i++) {"
10567 " ext_array[i] = 5;"
10568 "}"
10569 "for (var i = 0; i < 8; i++) {"
10570 " ext_array[i] = NaN;"
10571 "}"
10572 "ext_array[5];");
10573 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010574 CHECK_EQ(0,
10575 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
ager@chromium.org3811b432009-10-28 14:53:37 +000010576
10577 result = CompileRun("for (var i = 0; i < 8; i++) {"
10578 " ext_array[i] = 5;"
10579 "}"
10580 "for (var i = 0; i < 8; i++) {"
10581 " ext_array[i] = Infinity;"
10582 "}"
10583 "ext_array[5];");
10584 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010585 CHECK_EQ(0,
10586 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
ager@chromium.org3811b432009-10-28 14:53:37 +000010587
10588 result = CompileRun("for (var i = 0; i < 8; i++) {"
10589 " ext_array[i] = 5;"
10590 "}"
10591 "for (var i = 0; i < 8; i++) {"
10592 " ext_array[i] = -Infinity;"
10593 "}"
10594 "ext_array[5];");
10595 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010596 CHECK_EQ(0,
10597 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000010598
10599 // Check truncation behavior of integral arrays.
10600 const char* unsigned_data =
10601 "var source_data = [0.6, 10.6];"
10602 "var expected_results = [0, 10];";
10603 const char* signed_data =
10604 "var source_data = [0.6, 10.6, -0.6, -10.6];"
10605 "var expected_results = [0, 10, 0, -10];";
10606 bool is_unsigned =
10607 (array_type == v8::kExternalUnsignedByteArray ||
10608 array_type == v8::kExternalUnsignedShortArray ||
10609 array_type == v8::kExternalUnsignedIntArray);
10610
10611 i::OS::SNPrintF(test_buf,
10612 "%s"
10613 "var all_passed = true;"
10614 "for (var i = 0; i < source_data.length; i++) {"
10615 " for (var j = 0; j < 8; j++) {"
10616 " ext_array[j] = source_data[i];"
10617 " }"
10618 " all_passed = all_passed &&"
10619 " (ext_array[5] == expected_results[i]);"
10620 "}"
10621 "all_passed;",
10622 (is_unsigned ? unsigned_data : signed_data));
10623 result = CompileRun(test_buf.start());
10624 CHECK_EQ(true, result->BooleanValue());
ager@chromium.org3811b432009-10-28 14:53:37 +000010625 }
10626
10627 result = CompileRun("ext_array[3] = 33;"
10628 "delete ext_array[3];"
10629 "ext_array[3];");
10630 CHECK_EQ(33, result->Int32Value());
10631
10632 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
10633 "ext_array[2] = 12; ext_array[3] = 13;"
10634 "ext_array.__defineGetter__('2',"
10635 "function() { return 120; });"
10636 "ext_array[2];");
10637 CHECK_EQ(12, result->Int32Value());
10638
10639 result = CompileRun("var js_array = new Array(40);"
10640 "js_array[0] = 77;"
10641 "js_array;");
10642 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
10643
10644 result = CompileRun("ext_array[1] = 23;"
10645 "ext_array.__proto__ = [];"
10646 "js_array.__proto__ = ext_array;"
10647 "js_array.concat(ext_array);");
10648 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
10649 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
10650
10651 result = CompileRun("ext_array[1] = 23;");
10652 CHECK_EQ(23, result->Int32Value());
10653
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010654 // Test more complex manipulations which cause eax to contain values
10655 // that won't be completely overwritten by loads from the arrays.
10656 // This catches bugs in the instructions used for the KeyedLoadIC
10657 // for byte and word types.
10658 {
10659 const int kXSize = 300;
10660 const int kYSize = 300;
10661 const int kLargeElementCount = kXSize * kYSize * 4;
10662 ElementType* large_array_data =
10663 static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
10664 i::Handle<ExternalArrayClass> large_array =
10665 i::Handle<ExternalArrayClass>::cast(
10666 i::Factory::NewExternalArray(kLargeElementCount,
10667 array_type,
10668 array_data));
10669 v8::Handle<v8::Object> large_obj = v8::Object::New();
10670 // Set the elements to be the external array.
10671 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
10672 array_type,
10673 kLargeElementCount);
10674 context->Global()->Set(v8_str("large_array"), large_obj);
10675 // Initialize contents of a few rows.
10676 for (int x = 0; x < 300; x++) {
10677 int row = 0;
10678 int offset = row * 300 * 4;
10679 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
10680 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
10681 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
10682 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
10683 row = 150;
10684 offset = row * 300 * 4;
10685 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
10686 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
10687 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
10688 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
10689 row = 298;
10690 offset = row * 300 * 4;
10691 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
10692 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
10693 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
10694 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
10695 }
10696 // The goal of the code below is to make "offset" large enough
10697 // that the computation of the index (which goes into eax) has
10698 // high bits set which will not be overwritten by a byte or short
10699 // load.
10700 result = CompileRun("var failed = false;"
10701 "var offset = 0;"
10702 "for (var i = 0; i < 300; i++) {"
10703 " if (large_array[4 * i] != 127 ||"
10704 " large_array[4 * i + 1] != 0 ||"
10705 " large_array[4 * i + 2] != 0 ||"
10706 " large_array[4 * i + 3] != 127) {"
10707 " failed = true;"
10708 " }"
10709 "}"
10710 "offset = 150 * 300 * 4;"
10711 "for (var i = 0; i < 300; i++) {"
10712 " if (large_array[offset + 4 * i] != 127 ||"
10713 " large_array[offset + 4 * i + 1] != 0 ||"
10714 " large_array[offset + 4 * i + 2] != 0 ||"
10715 " large_array[offset + 4 * i + 3] != 127) {"
10716 " failed = true;"
10717 " }"
10718 "}"
10719 "offset = 298 * 300 * 4;"
10720 "for (var i = 0; i < 300; i++) {"
10721 " if (large_array[offset + 4 * i] != 127 ||"
10722 " large_array[offset + 4 * i + 1] != 0 ||"
10723 " large_array[offset + 4 * i + 2] != 0 ||"
10724 " large_array[offset + 4 * i + 3] != 127) {"
10725 " failed = true;"
10726 " }"
10727 "}"
10728 "!failed;");
10729 CHECK_EQ(true, result->BooleanValue());
10730 free(large_array_data);
10731 }
10732
ager@chromium.org3811b432009-10-28 14:53:37 +000010733 free(array_data);
10734}
10735
10736
10737THREADED_TEST(ExternalByteArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010738 ExternalArrayTestHelper<i::ExternalByteArray, int8_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000010739 v8::kExternalByteArray,
10740 -128,
10741 127);
10742}
10743
10744
10745THREADED_TEST(ExternalUnsignedByteArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010746 ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000010747 v8::kExternalUnsignedByteArray,
10748 0,
10749 255);
10750}
10751
10752
10753THREADED_TEST(ExternalShortArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010754 ExternalArrayTestHelper<i::ExternalShortArray, int16_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000010755 v8::kExternalShortArray,
10756 -32768,
10757 32767);
10758}
10759
10760
10761THREADED_TEST(ExternalUnsignedShortArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010762 ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000010763 v8::kExternalUnsignedShortArray,
10764 0,
10765 65535);
10766}
10767
10768
10769THREADED_TEST(ExternalIntArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010770 ExternalArrayTestHelper<i::ExternalIntArray, int32_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000010771 v8::kExternalIntArray,
10772 INT_MIN, // -2147483648
10773 INT_MAX); // 2147483647
10774}
10775
10776
10777THREADED_TEST(ExternalUnsignedIntArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010778 ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000010779 v8::kExternalUnsignedIntArray,
10780 0,
10781 UINT_MAX); // 4294967295
10782}
10783
10784
10785THREADED_TEST(ExternalFloatArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010786 ExternalArrayTestHelper<i::ExternalFloatArray, float>(
ager@chromium.org3811b432009-10-28 14:53:37 +000010787 v8::kExternalFloatArray,
10788 -500,
10789 500);
10790}
10791
10792
10793THREADED_TEST(ExternalArrays) {
10794 TestExternalByteArray();
10795 TestExternalUnsignedByteArray();
10796 TestExternalShortArray();
10797 TestExternalUnsignedShortArray();
10798 TestExternalIntArray();
10799 TestExternalUnsignedIntArray();
10800 TestExternalFloatArray();
10801}
10802
10803
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000010804void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
10805 v8::HandleScope scope;
10806 LocalContext context;
10807 for (int size = 0; size < 100; size += 10) {
10808 int element_size = ExternalArrayElementSize(array_type);
10809 void* external_data = malloc(size * element_size);
10810 v8::Handle<v8::Object> obj = v8::Object::New();
10811 obj->SetIndexedPropertiesToExternalArrayData(
10812 external_data, array_type, size);
10813 CHECK(obj->HasIndexedPropertiesInExternalArrayData());
10814 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
10815 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
10816 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
10817 free(external_data);
10818 }
10819}
10820
10821
10822THREADED_TEST(ExternalArrayInfo) {
10823 ExternalArrayInfoTestHelper(v8::kExternalByteArray);
10824 ExternalArrayInfoTestHelper(v8::kExternalUnsignedByteArray);
10825 ExternalArrayInfoTestHelper(v8::kExternalShortArray);
10826 ExternalArrayInfoTestHelper(v8::kExternalUnsignedShortArray);
10827 ExternalArrayInfoTestHelper(v8::kExternalIntArray);
10828 ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray);
10829 ExternalArrayInfoTestHelper(v8::kExternalFloatArray);
10830}
10831
10832
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000010833THREADED_TEST(ScriptContextDependence) {
10834 v8::HandleScope scope;
10835 LocalContext c1;
10836 const char *source = "foo";
10837 v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
10838 v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
10839 c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
10840 CHECK_EQ(dep->Run()->Int32Value(), 100);
10841 CHECK_EQ(indep->Run()->Int32Value(), 100);
10842 LocalContext c2;
10843 c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
10844 CHECK_EQ(dep->Run()->Int32Value(), 100);
10845 CHECK_EQ(indep->Run()->Int32Value(), 101);
10846}
10847
ager@chromium.org96c75b52009-08-26 09:13:16 +000010848
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000010849THREADED_TEST(StackTrace) {
10850 v8::HandleScope scope;
10851 LocalContext context;
10852 v8::TryCatch try_catch;
10853 const char *source = "function foo() { FAIL.FAIL; }; foo();";
10854 v8::Handle<v8::String> src = v8::String::New(source);
10855 v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
10856 v8::Script::New(src, origin)->Run();
10857 CHECK(try_catch.HasCaught());
10858 v8::String::Utf8Value stack(try_catch.StackTrace());
10859 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
10860}
ager@chromium.org96c75b52009-08-26 09:13:16 +000010861
10862
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000010863// Checks that a StackFrame has certain expected values.
10864void checkStackFrame(const char* expected_script_name,
10865 const char* expected_func_name, int expected_line_number,
10866 int expected_column, bool is_eval, bool is_constructor,
10867 v8::Handle<v8::StackFrame> frame) {
10868 v8::HandleScope scope;
10869 v8::String::Utf8Value func_name(frame->GetFunctionName());
10870 v8::String::Utf8Value script_name(frame->GetScriptName());
10871 if (*script_name == NULL) {
10872 // The situation where there is no associated script, like for evals.
10873 CHECK(expected_script_name == NULL);
10874 } else {
10875 CHECK(strstr(*script_name, expected_script_name) != NULL);
10876 }
10877 CHECK(strstr(*func_name, expected_func_name) != NULL);
10878 CHECK_EQ(expected_line_number, frame->GetLineNumber());
10879 CHECK_EQ(expected_column, frame->GetColumn());
10880 CHECK_EQ(is_eval, frame->IsEval());
10881 CHECK_EQ(is_constructor, frame->IsConstructor());
10882}
10883
10884
10885v8::Handle<Value> AnalyzeStackInNativeCode(const v8::Arguments& args) {
10886 v8::HandleScope scope;
10887 const char* origin = "capture-stack-trace-test";
10888 const int kOverviewTest = 1;
10889 const int kDetailedTest = 2;
10890
10891 ASSERT(args.Length() == 1);
10892
10893 int testGroup = args[0]->Int32Value();
10894 if (testGroup == kOverviewTest) {
10895 v8::Handle<v8::StackTrace> stackTrace =
10896 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
10897 CHECK_EQ(4, stackTrace->GetFrameCount());
10898 checkStackFrame(origin, "bar", 2, 10, false, false,
10899 stackTrace->GetFrame(0));
10900 checkStackFrame(origin, "foo", 6, 3, false, false,
10901 stackTrace->GetFrame(1));
10902 checkStackFrame(NULL, "", 1, 1, false, false,
10903 stackTrace->GetFrame(2));
10904 // The last frame is an anonymous function that has the initial call.
10905 checkStackFrame(origin, "", 8, 7, false, false,
10906 stackTrace->GetFrame(3));
10907
10908 CHECK(stackTrace->AsArray()->IsArray());
10909 } else if (testGroup == kDetailedTest) {
10910 v8::Handle<v8::StackTrace> stackTrace =
10911 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
10912 CHECK_EQ(4, stackTrace->GetFrameCount());
10913 checkStackFrame(origin, "bat", 4, 22, false, false,
10914 stackTrace->GetFrame(0));
10915 checkStackFrame(origin, "baz", 8, 3, false, true,
10916 stackTrace->GetFrame(1));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010917#ifdef ENABLE_DEBUGGER_SUPPORT
10918 bool is_eval = true;
10919#else // ENABLE_DEBUGGER_SUPPORT
10920 bool is_eval = false;
10921#endif // ENABLE_DEBUGGER_SUPPORT
10922
10923 checkStackFrame(NULL, "", 1, 1, is_eval, false,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000010924 stackTrace->GetFrame(2));
10925 // The last frame is an anonymous function that has the initial call to foo.
10926 checkStackFrame(origin, "", 10, 1, false, false,
10927 stackTrace->GetFrame(3));
10928
10929 CHECK(stackTrace->AsArray()->IsArray());
10930 }
10931 return v8::Undefined();
10932}
10933
10934
10935// Tests the C++ StackTrace API.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010936// TODO(3074796): Reenable this as a THREADED_TEST once it passes.
10937// THREADED_TEST(CaptureStackTrace) {
10938TEST(CaptureStackTrace) {
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000010939 v8::HandleScope scope;
10940 v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
10941 Local<ObjectTemplate> templ = ObjectTemplate::New();
10942 templ->Set(v8_str("AnalyzeStackInNativeCode"),
10943 v8::FunctionTemplate::New(AnalyzeStackInNativeCode));
10944 LocalContext context(0, templ);
10945
10946 // Test getting OVERVIEW information. Should ignore information that is not
10947 // script name, function name, line number, and column offset.
10948 const char *overview_source =
10949 "function bar() {\n"
10950 " var y; AnalyzeStackInNativeCode(1);\n"
10951 "}\n"
10952 "function foo() {\n"
10953 "\n"
10954 " bar();\n"
10955 "}\n"
10956 "var x;eval('new foo();');";
10957 v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
10958 v8::Handle<Value> overview_result =
10959 v8::Script::New(overview_src, origin)->Run();
10960 ASSERT(!overview_result.IsEmpty());
10961 ASSERT(overview_result->IsObject());
10962
10963 // Test getting DETAILED information.
10964 const char *detailed_source =
10965 "function bat() {AnalyzeStackInNativeCode(2);\n"
10966 "}\n"
10967 "\n"
10968 "function baz() {\n"
10969 " bat();\n"
10970 "}\n"
10971 "eval('new baz();');";
10972 v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
10973 // Make the script using a non-zero line and column offset.
10974 v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
10975 v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
10976 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
10977 v8::Handle<v8::Script> detailed_script(
10978 v8::Script::New(detailed_src, &detailed_origin));
10979 v8::Handle<Value> detailed_result = detailed_script->Run();
10980 ASSERT(!detailed_result.IsEmpty());
10981 ASSERT(detailed_result->IsObject());
10982}
10983
10984
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010985static void StackTraceForUncaughtExceptionListener(
10986 v8::Handle<v8::Message> message,
10987 v8::Handle<Value>) {
10988 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
10989 CHECK_EQ(2, stack_trace->GetFrameCount());
10990 checkStackFrame("origin", "foo", 2, 3, false, false,
10991 stack_trace->GetFrame(0));
10992 checkStackFrame("origin", "bar", 5, 3, false, false,
10993 stack_trace->GetFrame(1));
10994}
10995
10996TEST(CaptureStackTraceForUncaughtException) {
10997 report_count = 0;
10998 v8::HandleScope scope;
10999 LocalContext env;
11000 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
11001 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
11002
11003 Script::Compile(v8_str("function foo() {\n"
11004 " throw 1;\n"
11005 "};\n"
11006 "function bar() {\n"
11007 " foo();\n"
11008 "};"),
11009 v8_str("origin"))->Run();
11010 v8::Local<v8::Object> global = env->Global();
11011 Local<Value> trouble = global->Get(v8_str("bar"));
11012 CHECK(trouble->IsFunction());
11013 Function::Cast(*trouble)->Call(global, 0, NULL);
11014 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
11015 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
11016}
11017
11018
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000011019v8::Handle<Value> AnalyzeStackOfEvalWithSourceURL(const v8::Arguments& args) {
11020 v8::HandleScope scope;
11021 v8::Handle<v8::StackTrace> stackTrace =
11022 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
11023 CHECK_EQ(5, stackTrace->GetFrameCount());
11024 v8::Handle<v8::String> url = v8_str("eval_url");
11025 for (int i = 0; i < 3; i++) {
11026 v8::Handle<v8::String> name =
11027 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
11028 CHECK(!name.IsEmpty());
11029 CHECK_EQ(url, name);
11030 }
11031 return v8::Undefined();
11032}
11033
11034
11035TEST(SourceURLInStackTrace) {
11036 v8::HandleScope scope;
11037 Local<ObjectTemplate> templ = ObjectTemplate::New();
11038 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
11039 v8::FunctionTemplate::New(AnalyzeStackOfEvalWithSourceURL));
11040 LocalContext context(0, templ);
11041
11042 const char *source =
11043 "function outer() {\n"
11044 "function bar() {\n"
11045 " AnalyzeStackOfEvalWithSourceURL();\n"
11046 "}\n"
11047 "function foo() {\n"
11048 "\n"
11049 " bar();\n"
11050 "}\n"
11051 "foo();\n"
11052 "}\n"
11053 "eval('(' + outer +')()//@ sourceURL=eval_url');";
11054 CHECK(CompileRun(source)->IsUndefined());
11055}
11056
11057
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000011058// Test that idle notification can be handled and eventually returns true.
ager@chromium.org96c75b52009-08-26 09:13:16 +000011059THREADED_TEST(IdleNotification) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000011060 bool rv = false;
11061 for (int i = 0; i < 100; i++) {
11062 rv = v8::V8::IdleNotification();
11063 if (rv)
11064 break;
11065 }
11066 CHECK(rv == true);
11067}
11068
11069
11070static uint32_t* stack_limit;
11071
11072static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +000011073 stack_limit = reinterpret_cast<uint32_t*>(i::StackGuard::real_climit());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000011074 return v8::Undefined();
11075}
11076
11077
11078// Uses the address of a local variable to determine the stack top now.
11079// Given a size, returns an address that is that far from the current
11080// top of stack.
11081static uint32_t* ComputeStackLimit(uint32_t size) {
11082 uint32_t* answer = &size - (size / sizeof(size));
11083 // If the size is very large and the stack is very near the bottom of
11084 // memory then the calculation above may wrap around and give an address
11085 // that is above the (downwards-growing) stack. In that case we return
11086 // a very low address.
11087 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
11088 return answer;
11089}
11090
11091
11092TEST(SetResourceConstraints) {
11093 static const int K = 1024;
11094 uint32_t* set_limit = ComputeStackLimit(128 * K);
11095
11096 // Set stack limit.
11097 v8::ResourceConstraints constraints;
11098 constraints.set_stack_limit(set_limit);
11099 CHECK(v8::SetResourceConstraints(&constraints));
11100
11101 // Execute a script.
11102 v8::HandleScope scope;
11103 LocalContext env;
11104 Local<v8::FunctionTemplate> fun_templ =
11105 v8::FunctionTemplate::New(GetStackLimitCallback);
11106 Local<Function> fun = fun_templ->GetFunction();
11107 env->Global()->Set(v8_str("get_stack_limit"), fun);
11108 CompileRun("get_stack_limit();");
11109
11110 CHECK(stack_limit == set_limit);
11111}
11112
11113
11114TEST(SetResourceConstraintsInThread) {
11115 uint32_t* set_limit;
11116 {
11117 v8::Locker locker;
11118 static const int K = 1024;
11119 set_limit = ComputeStackLimit(128 * K);
11120
11121 // Set stack limit.
11122 v8::ResourceConstraints constraints;
11123 constraints.set_stack_limit(set_limit);
11124 CHECK(v8::SetResourceConstraints(&constraints));
11125
11126 // Execute a script.
11127 v8::HandleScope scope;
11128 LocalContext env;
11129 Local<v8::FunctionTemplate> fun_templ =
11130 v8::FunctionTemplate::New(GetStackLimitCallback);
11131 Local<Function> fun = fun_templ->GetFunction();
11132 env->Global()->Set(v8_str("get_stack_limit"), fun);
11133 CompileRun("get_stack_limit();");
11134
11135 CHECK(stack_limit == set_limit);
11136 }
11137 {
11138 v8::Locker locker;
11139 CHECK(stack_limit == set_limit);
11140 }
ager@chromium.org96c75b52009-08-26 09:13:16 +000011141}
ager@chromium.org3811b432009-10-28 14:53:37 +000011142
11143
11144THREADED_TEST(GetHeapStatistics) {
11145 v8::HandleScope scope;
11146 LocalContext c1;
11147 v8::HeapStatistics heap_statistics;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011148 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
11149 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
ager@chromium.org3811b432009-10-28 14:53:37 +000011150 v8::V8::GetHeapStatistics(&heap_statistics);
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011151 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
11152 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
ager@chromium.org3811b432009-10-28 14:53:37 +000011153}
11154
11155
11156static double DoubleFromBits(uint64_t value) {
11157 double target;
11158#ifdef BIG_ENDIAN_FLOATING_POINT
11159 const int kIntSize = 4;
11160 // Somebody swapped the lower and higher half of doubles.
11161 memcpy(&target, reinterpret_cast<char*>(&value) + kIntSize, kIntSize);
11162 memcpy(reinterpret_cast<char*>(&target) + kIntSize, &value, kIntSize);
11163#else
11164 memcpy(&target, &value, sizeof(target));
11165#endif
11166 return target;
11167}
11168
11169
11170static uint64_t DoubleToBits(double value) {
11171 uint64_t target;
11172#ifdef BIG_ENDIAN_FLOATING_POINT
11173 const int kIntSize = 4;
11174 // Somebody swapped the lower and higher half of doubles.
11175 memcpy(&target, reinterpret_cast<char*>(&value) + kIntSize, kIntSize);
11176 memcpy(reinterpret_cast<char*>(&target) + kIntSize, &value, kIntSize);
11177#else
11178 memcpy(&target, &value, sizeof(target));
11179#endif
11180 return target;
11181}
11182
11183
11184static double DoubleToDateTime(double input) {
11185 double date_limit = 864e13;
11186 if (IsNaN(input) || input < -date_limit || input > date_limit) {
11187 return i::OS::nan_value();
11188 }
11189 return (input < 0) ? -(floor(-input)) : floor(input);
11190}
11191
11192// We don't have a consistent way to write 64-bit constants syntactically, so we
11193// split them into two 32-bit constants and combine them programmatically.
11194static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
11195 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
11196}
11197
11198
11199THREADED_TEST(QuietSignalingNaNs) {
11200 v8::HandleScope scope;
11201 LocalContext context;
11202 v8::TryCatch try_catch;
11203
11204 // Special double values.
11205 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
11206 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
11207 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
11208 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
11209 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
11210 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
11211 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
11212
11213 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
11214 // on either side of the epoch.
11215 double date_limit = 864e13;
11216
11217 double test_values[] = {
11218 snan,
11219 qnan,
11220 infinity,
11221 max_normal,
11222 date_limit + 1,
11223 date_limit,
11224 min_normal,
11225 max_denormal,
11226 min_denormal,
11227 0,
11228 -0,
11229 -min_denormal,
11230 -max_denormal,
11231 -min_normal,
11232 -date_limit,
11233 -date_limit - 1,
11234 -max_normal,
11235 -infinity,
11236 -qnan,
11237 -snan
11238 };
11239 int num_test_values = 20;
11240
11241 for (int i = 0; i < num_test_values; i++) {
11242 double test_value = test_values[i];
11243
11244 // Check that Number::New preserves non-NaNs and quiets SNaNs.
11245 v8::Handle<v8::Value> number = v8::Number::New(test_value);
11246 double stored_number = number->NumberValue();
11247 if (!IsNaN(test_value)) {
11248 CHECK_EQ(test_value, stored_number);
11249 } else {
11250 uint64_t stored_bits = DoubleToBits(stored_number);
11251 // Check if quiet nan (bits 51..62 all set).
11252 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
11253 }
11254
11255 // Check that Date::New preserves non-NaNs in the date range and
11256 // quiets SNaNs.
11257 v8::Handle<v8::Value> date = v8::Date::New(test_value);
11258 double expected_stored_date = DoubleToDateTime(test_value);
11259 double stored_date = date->NumberValue();
11260 if (!IsNaN(expected_stored_date)) {
11261 CHECK_EQ(expected_stored_date, stored_date);
11262 } else {
11263 uint64_t stored_bits = DoubleToBits(stored_date);
11264 // Check if quiet nan (bits 51..62 all set).
11265 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
11266 }
11267 }
11268}
christian.plesner.hansen@gmail.comb9ce6372009-11-03 11:38:18 +000011269
11270
11271static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
11272 v8::HandleScope scope;
11273 v8::TryCatch tc;
11274 v8::Handle<v8::String> str = args[0]->ToString();
11275 if (tc.HasCaught())
11276 return tc.ReThrow();
11277 return v8::Undefined();
11278}
11279
11280
11281// Test that an exception can be propagated down through a spaghetti
11282// stack using ReThrow.
11283THREADED_TEST(SpaghettiStackReThrow) {
11284 v8::HandleScope scope;
11285 LocalContext context;
11286 context->Global()->Set(
11287 v8::String::New("s"),
11288 v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
11289 v8::TryCatch try_catch;
11290 CompileRun(
11291 "var i = 0;"
11292 "var o = {"
11293 " toString: function () {"
11294 " if (i == 10) {"
11295 " throw 'Hey!';"
11296 " } else {"
11297 " i++;"
11298 " return s(o);"
11299 " }"
11300 " }"
11301 "};"
11302 "s(o);");
11303 CHECK(try_catch.HasCaught());
11304 v8::String::Utf8Value value(try_catch.Exception());
11305 CHECK_EQ(0, strcmp(*value, "Hey!"));
11306}
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011307
11308
sgjesse@chromium.org98180592009-12-02 08:17:28 +000011309TEST(Regress528) {
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011310 v8::V8::Initialize();
11311
11312 v8::HandleScope scope;
11313 v8::Persistent<Context> context;
ager@chromium.org60121232009-12-03 11:25:37 +000011314 v8::Persistent<Context> other_context;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011315 int gc_count;
11316
ager@chromium.org60121232009-12-03 11:25:37 +000011317 // Create a context used to keep the code from aging in the compilation
11318 // cache.
11319 other_context = Context::New();
11320
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011321 // Context-dependent context data creates reference from the compilation
11322 // cache to the global object.
ager@chromium.org60121232009-12-03 11:25:37 +000011323 const char* source_simple = "1";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011324 context = Context::New();
11325 {
11326 v8::HandleScope scope;
11327
11328 context->Enter();
11329 Local<v8::String> obj = v8::String::New("");
11330 context->SetData(obj);
ager@chromium.org60121232009-12-03 11:25:37 +000011331 CompileRun(source_simple);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011332 context->Exit();
11333 }
11334 context.Dispose();
11335 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000011336 other_context->Enter();
11337 CompileRun(source_simple);
11338 other_context->Exit();
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011339 i::Heap::CollectAllGarbage(false);
ager@chromium.org60121232009-12-03 11:25:37 +000011340 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011341 }
ager@chromium.org60121232009-12-03 11:25:37 +000011342 CHECK_GE(2, gc_count);
11343 CHECK_EQ(1, GetGlobalObjectsCount());
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011344
11345 // Eval in a function creates reference from the compilation cache to the
11346 // global object.
ager@chromium.org60121232009-12-03 11:25:37 +000011347 const char* source_eval = "function f(){eval('1')}; f()";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011348 context = Context::New();
11349 {
11350 v8::HandleScope scope;
11351
11352 context->Enter();
ager@chromium.org60121232009-12-03 11:25:37 +000011353 CompileRun(source_eval);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011354 context->Exit();
11355 }
11356 context.Dispose();
11357 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000011358 other_context->Enter();
11359 CompileRun(source_eval);
11360 other_context->Exit();
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011361 i::Heap::CollectAllGarbage(false);
ager@chromium.org60121232009-12-03 11:25:37 +000011362 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011363 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011364 CHECK_GE(2, gc_count);
sgjesse@chromium.org98180592009-12-02 08:17:28 +000011365 CHECK_EQ(1, GetGlobalObjectsCount());
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011366
11367 // Looking up the line number for an exception creates reference from the
11368 // compilation cache to the global object.
ager@chromium.org60121232009-12-03 11:25:37 +000011369 const char* source_exception = "function f(){throw 1;} f()";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011370 context = Context::New();
11371 {
11372 v8::HandleScope scope;
11373
11374 context->Enter();
11375 v8::TryCatch try_catch;
ager@chromium.org60121232009-12-03 11:25:37 +000011376 CompileRun(source_exception);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011377 CHECK(try_catch.HasCaught());
11378 v8::Handle<v8::Message> message = try_catch.Message();
11379 CHECK(!message.IsEmpty());
11380 CHECK_EQ(1, message->GetLineNumber());
11381 context->Exit();
11382 }
11383 context.Dispose();
11384 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000011385 other_context->Enter();
11386 CompileRun(source_exception);
11387 other_context->Exit();
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011388 i::Heap::CollectAllGarbage(false);
ager@chromium.org60121232009-12-03 11:25:37 +000011389 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011390 }
ager@chromium.org60121232009-12-03 11:25:37 +000011391 CHECK_GE(2, gc_count);
11392 CHECK_EQ(1, GetGlobalObjectsCount());
11393
11394 other_context.Dispose();
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011395}
ager@chromium.org5c838252010-02-19 08:53:10 +000011396
11397
11398THREADED_TEST(ScriptOrigin) {
11399 v8::HandleScope scope;
11400 LocalContext env;
11401 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
11402 v8::Handle<v8::String> script = v8::String::New(
11403 "function f() {}\n\nfunction g() {}");
11404 v8::Script::Compile(script, &origin)->Run();
11405 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
11406 env->Global()->Get(v8::String::New("f")));
11407 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
11408 env->Global()->Get(v8::String::New("g")));
11409
11410 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
11411 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
11412 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
11413
11414 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
11415 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
11416 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
11417}
11418
11419
11420THREADED_TEST(ScriptLineNumber) {
11421 v8::HandleScope scope;
11422 LocalContext env;
11423 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
11424 v8::Handle<v8::String> script = v8::String::New(
11425 "function f() {}\n\nfunction g() {}");
11426 v8::Script::Compile(script, &origin)->Run();
11427 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
11428 env->Global()->Get(v8::String::New("f")));
11429 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
11430 env->Global()->Get(v8::String::New("g")));
11431 CHECK_EQ(0, f->GetScriptLineNumber());
11432 CHECK_EQ(2, g->GetScriptLineNumber());
11433}
11434
11435
11436static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
11437 const AccessorInfo& info) {
11438 return v8_num(42);
11439}
11440
11441
11442static void SetterWhichSetsYOnThisTo23(Local<String> name,
11443 Local<Value> value,
11444 const AccessorInfo& info) {
11445 info.This()->Set(v8_str("y"), v8_num(23));
11446}
11447
11448
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011449TEST(SetterOnConstructorPrototype) {
ager@chromium.org5c838252010-02-19 08:53:10 +000011450 v8::HandleScope scope;
11451 Local<ObjectTemplate> templ = ObjectTemplate::New();
11452 templ->SetAccessor(v8_str("x"),
11453 GetterWhichReturns42,
11454 SetterWhichSetsYOnThisTo23);
11455 LocalContext context;
11456 context->Global()->Set(v8_str("P"), templ->NewInstance());
11457 CompileRun("function C1() {"
11458 " this.x = 23;"
11459 "};"
11460 "C1.prototype = P;"
11461 "function C2() {"
11462 " this.x = 23"
11463 "};"
11464 "C2.prototype = { };"
11465 "C2.prototype.__proto__ = P;");
11466
11467 v8::Local<v8::Script> script;
11468 script = v8::Script::Compile(v8_str("new C1();"));
11469 for (int i = 0; i < 10; i++) {
11470 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
11471 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
11472 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
11473 }
11474
11475 script = v8::Script::Compile(v8_str("new C2();"));
11476 for (int i = 0; i < 10; i++) {
11477 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
11478 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
11479 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
11480 }
11481}
11482
11483
11484static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
11485 Local<String> name, const AccessorInfo& info) {
11486 return v8_num(42);
11487}
11488
11489
11490static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
11491 Local<String> name, Local<Value> value, const AccessorInfo& info) {
11492 if (name->Equals(v8_str("x"))) {
11493 info.This()->Set(v8_str("y"), v8_num(23));
11494 }
11495 return v8::Handle<Value>();
11496}
11497
11498
11499THREADED_TEST(InterceptorOnConstructorPrototype) {
11500 v8::HandleScope scope;
11501 Local<ObjectTemplate> templ = ObjectTemplate::New();
11502 templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
11503 NamedPropertySetterWhichSetsYOnThisTo23);
11504 LocalContext context;
11505 context->Global()->Set(v8_str("P"), templ->NewInstance());
11506 CompileRun("function C1() {"
11507 " this.x = 23;"
11508 "};"
11509 "C1.prototype = P;"
11510 "function C2() {"
11511 " this.x = 23"
11512 "};"
11513 "C2.prototype = { };"
11514 "C2.prototype.__proto__ = P;");
11515
11516 v8::Local<v8::Script> script;
11517 script = v8::Script::Compile(v8_str("new C1();"));
11518 for (int i = 0; i < 10; i++) {
11519 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
11520 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
11521 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
11522 }
11523
11524 script = v8::Script::Compile(v8_str("new C2();"));
11525 for (int i = 0; i < 10; i++) {
11526 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
11527 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
11528 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
11529 }
11530}
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011531
11532
11533TEST(Bug618) {
11534 const char* source = "function C1() {"
11535 " this.x = 23;"
11536 "};"
11537 "C1.prototype = P;";
11538
11539 v8::HandleScope scope;
11540 LocalContext context;
11541 v8::Local<v8::Script> script;
11542
11543 // Use a simple object as prototype.
11544 v8::Local<v8::Object> prototype = v8::Object::New();
11545 prototype->Set(v8_str("y"), v8_num(42));
11546 context->Global()->Set(v8_str("P"), prototype);
11547
11548 // This compile will add the code to the compilation cache.
11549 CompileRun(source);
11550
11551 script = v8::Script::Compile(v8_str("new C1();"));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011552 // Allow enough iterations for the inobject slack tracking logic
11553 // to finalize instance size and install the fast construct stub.
11554 for (int i = 0; i < 256; i++) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011555 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
11556 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
11557 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
11558 }
11559
11560 // Use an API object with accessors as prototype.
11561 Local<ObjectTemplate> templ = ObjectTemplate::New();
11562 templ->SetAccessor(v8_str("x"),
11563 GetterWhichReturns42,
11564 SetterWhichSetsYOnThisTo23);
11565 context->Global()->Set(v8_str("P"), templ->NewInstance());
11566
11567 // This compile will get the code from the compilation cache.
11568 CompileRun(source);
11569
11570 script = v8::Script::Compile(v8_str("new C1();"));
11571 for (int i = 0; i < 10; i++) {
11572 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
11573 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
11574 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
11575 }
11576}
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011577
11578int prologue_call_count = 0;
11579int epilogue_call_count = 0;
11580int prologue_call_count_second = 0;
11581int epilogue_call_count_second = 0;
11582
11583void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
11584 ++prologue_call_count;
11585}
11586
11587void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
11588 ++epilogue_call_count;
11589}
11590
11591void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
11592 ++prologue_call_count_second;
11593}
11594
11595void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
11596 ++epilogue_call_count_second;
11597}
11598
11599TEST(GCCallbacks) {
11600 LocalContext context;
11601
11602 v8::V8::AddGCPrologueCallback(PrologueCallback);
11603 v8::V8::AddGCEpilogueCallback(EpilogueCallback);
11604 CHECK_EQ(0, prologue_call_count);
11605 CHECK_EQ(0, epilogue_call_count);
11606 i::Heap::CollectAllGarbage(false);
11607 CHECK_EQ(1, prologue_call_count);
11608 CHECK_EQ(1, epilogue_call_count);
11609 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
11610 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
11611 i::Heap::CollectAllGarbage(false);
11612 CHECK_EQ(2, prologue_call_count);
11613 CHECK_EQ(2, epilogue_call_count);
11614 CHECK_EQ(1, prologue_call_count_second);
11615 CHECK_EQ(1, epilogue_call_count_second);
11616 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
11617 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
11618 i::Heap::CollectAllGarbage(false);
11619 CHECK_EQ(2, prologue_call_count);
11620 CHECK_EQ(2, epilogue_call_count);
11621 CHECK_EQ(2, prologue_call_count_second);
11622 CHECK_EQ(2, epilogue_call_count_second);
11623 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
11624 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
11625 i::Heap::CollectAllGarbage(false);
11626 CHECK_EQ(2, prologue_call_count);
11627 CHECK_EQ(2, epilogue_call_count);
11628 CHECK_EQ(2, prologue_call_count_second);
11629 CHECK_EQ(2, epilogue_call_count_second);
11630}
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000011631
11632
11633THREADED_TEST(AddToJSFunctionResultCache) {
11634 i::FLAG_allow_natives_syntax = true;
11635 v8::HandleScope scope;
11636
11637 LocalContext context;
11638
11639 const char* code =
11640 "(function() {"
11641 " var key0 = 'a';"
11642 " var key1 = 'b';"
11643 " var r0 = %_GetFromCache(0, key0);"
11644 " var r1 = %_GetFromCache(0, key1);"
11645 " var r0_ = %_GetFromCache(0, key0);"
11646 " if (r0 !== r0_)"
11647 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
11648 " var r1_ = %_GetFromCache(0, key1);"
11649 " if (r1 !== r1_)"
11650 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
11651 " return 'PASSED';"
11652 "})()";
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011653 i::Heap::ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000011654 ExpectString(code, "PASSED");
11655}
11656
11657
11658static const int k0CacheSize = 16;
11659
11660THREADED_TEST(FillJSFunctionResultCache) {
11661 i::FLAG_allow_natives_syntax = true;
11662 v8::HandleScope scope;
11663
11664 LocalContext context;
11665
11666 const char* code =
11667 "(function() {"
11668 " var k = 'a';"
11669 " var r = %_GetFromCache(0, k);"
11670 " for (var i = 0; i < 16; i++) {"
11671 " %_GetFromCache(0, 'a' + i);"
11672 " };"
11673 " if (r === %_GetFromCache(0, k))"
11674 " return 'FAILED: k0CacheSize is too small';"
11675 " return 'PASSED';"
11676 "})()";
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011677 i::Heap::ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000011678 ExpectString(code, "PASSED");
11679}
11680
11681
11682THREADED_TEST(RoundRobinGetFromCache) {
11683 i::FLAG_allow_natives_syntax = true;
11684 v8::HandleScope scope;
11685
11686 LocalContext context;
11687
11688 const char* code =
11689 "(function() {"
11690 " var keys = [];"
11691 " for (var i = 0; i < 16; i++) keys.push(i);"
11692 " var values = [];"
11693 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
11694 " for (var i = 0; i < 16; i++) {"
11695 " var v = %_GetFromCache(0, keys[i]);"
11696 " if (v !== values[i])"
11697 " return 'Wrong value for ' + "
11698 " keys[i] + ': ' + v + ' vs. ' + values[i];"
11699 " };"
11700 " return 'PASSED';"
11701 "})()";
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011702 i::Heap::ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000011703 ExpectString(code, "PASSED");
11704}
11705
11706
11707THREADED_TEST(ReverseGetFromCache) {
11708 i::FLAG_allow_natives_syntax = true;
11709 v8::HandleScope scope;
11710
11711 LocalContext context;
11712
11713 const char* code =
11714 "(function() {"
11715 " var keys = [];"
11716 " for (var i = 0; i < 16; i++) keys.push(i);"
11717 " var values = [];"
11718 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
11719 " for (var i = 15; i >= 16; i--) {"
11720 " var v = %_GetFromCache(0, keys[i]);"
11721 " if (v !== values[i])"
11722 " return 'Wrong value for ' + "
11723 " keys[i] + ': ' + v + ' vs. ' + values[i];"
11724 " };"
11725 " return 'PASSED';"
11726 "})()";
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011727 i::Heap::ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000011728 ExpectString(code, "PASSED");
11729}
11730
11731
11732THREADED_TEST(TestEviction) {
11733 i::FLAG_allow_natives_syntax = true;
11734 v8::HandleScope scope;
11735
11736 LocalContext context;
11737
11738 const char* code =
11739 "(function() {"
11740 " for (var i = 0; i < 2*16; i++) {"
11741 " %_GetFromCache(0, 'a' + i);"
11742 " };"
11743 " return 'PASSED';"
11744 "})()";
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011745 i::Heap::ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000011746 ExpectString(code, "PASSED");
11747}
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011748
11749
11750THREADED_TEST(TwoByteStringInAsciiCons) {
11751 // See Chromium issue 47824.
11752 v8::HandleScope scope;
11753
11754 LocalContext context;
11755 const char* init_code =
11756 "var str1 = 'abelspendabel';"
11757 "var str2 = str1 + str1 + str1;"
11758 "str2;";
11759 Local<Value> result = CompileRun(init_code);
11760
11761 CHECK(result->IsString());
11762 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
11763 int length = string->length();
11764 CHECK(string->IsAsciiRepresentation());
11765
11766 FlattenString(string);
11767 i::Handle<i::String> flat_string = FlattenGetString(string);
11768
11769 CHECK(string->IsAsciiRepresentation());
11770 CHECK(flat_string->IsAsciiRepresentation());
11771
11772 // Create external resource.
11773 uint16_t* uc16_buffer = new uint16_t[length + 1];
11774
11775 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
11776 uc16_buffer[length] = 0;
11777
11778 TestResource resource(uc16_buffer);
11779
11780 flat_string->MakeExternal(&resource);
11781
11782 CHECK(flat_string->IsTwoByteRepresentation());
11783
11784 // At this point, we should have a Cons string which is flat and ASCII,
11785 // with a first half that is a two-byte string (although it only contains
11786 // ASCII characters). This is a valid sequence of steps, and it can happen
11787 // in real pages.
11788
11789 CHECK(string->IsAsciiRepresentation());
11790 i::ConsString* cons = i::ConsString::cast(*string);
11791 CHECK_EQ(0, cons->second()->length());
11792 CHECK(cons->first()->IsTwoByteRepresentation());
11793
11794 // Check that some string operations work.
11795
11796 // Atom RegExp.
11797 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
11798 CHECK_EQ(6, reresult->Int32Value());
11799
11800 // Nonatom RegExp.
11801 reresult = CompileRun("str2.match(/abe./g).length;");
11802 CHECK_EQ(6, reresult->Int32Value());
11803
11804 reresult = CompileRun("str2.search(/bel/g);");
11805 CHECK_EQ(1, reresult->Int32Value());
11806
11807 reresult = CompileRun("str2.search(/be./g);");
11808 CHECK_EQ(1, reresult->Int32Value());
11809
11810 ExpectTrue("/bel/g.test(str2);");
11811
11812 ExpectTrue("/be./g.test(str2);");
11813
11814 reresult = CompileRun("/bel/g.exec(str2);");
11815 CHECK(!reresult->IsNull());
11816
11817 reresult = CompileRun("/be./g.exec(str2);");
11818 CHECK(!reresult->IsNull());
11819
11820 ExpectString("str2.substring(2, 10);", "elspenda");
11821
11822 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
11823
11824 ExpectString("str2.charAt(2);", "e");
11825
11826 reresult = CompileRun("str2.charCodeAt(2);");
11827 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
11828}
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000011829
11830
11831// Failed access check callback that performs a GC on each invocation.
11832void FailedAccessCheckCallbackGC(Local<v8::Object> target,
11833 v8::AccessType type,
11834 Local<v8::Value> data) {
11835 i::Heap::CollectAllGarbage(true);
11836}
11837
11838
11839TEST(GCInFailedAccessCheckCallback) {
11840 // Install a failed access check callback that performs a GC on each
11841 // invocation. Then force the callback to be called from va
11842
11843 v8::V8::Initialize();
11844 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
11845
11846 v8::HandleScope scope;
11847
11848 // Create an ObjectTemplate for global objects and install access
11849 // check callbacks that will block access.
11850 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
11851 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
11852 IndexedGetAccessBlocker,
11853 v8::Handle<v8::Value>(),
11854 false);
11855
11856 // Create a context and set an x property on it's global object.
11857 LocalContext context0(NULL, global_template);
11858 context0->Global()->Set(v8_str("x"), v8_num(42));
11859 v8::Handle<v8::Object> global0 = context0->Global();
11860
11861 // Create a context with a different security token so that the
11862 // failed access check callback will be called on each access.
11863 LocalContext context1(NULL, global_template);
11864 context1->Global()->Set(v8_str("other"), global0);
11865
11866 // Get property with failed access check.
11867 ExpectUndefined("other.x");
11868
11869 // Get element with failed access check.
11870 ExpectUndefined("other[0]");
11871
11872 // Set property with failed access check.
11873 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
11874 CHECK(result->IsObject());
11875
11876 // Set element with failed access check.
11877 result = CompileRun("other[0] = new Object()");
11878 CHECK(result->IsObject());
11879
11880 // Get property attribute with failed access check.
11881 ExpectFalse("\'x\' in other");
11882
11883 // Get property attribute for element with failed access check.
11884 ExpectFalse("0 in other");
11885
11886 // Delete property.
11887 ExpectFalse("delete other.x");
11888
11889 // Delete element.
11890 CHECK_EQ(false, global0->Delete(0));
11891
11892 // DefineAccessor.
11893 CHECK_EQ(false,
11894 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
11895
11896 // Define JavaScript accessor.
11897 ExpectUndefined("Object.prototype.__defineGetter__.call("
11898 " other, \'x\', function() { return 42; })");
11899
11900 // LookupAccessor.
11901 ExpectUndefined("Object.prototype.__lookupGetter__.call("
11902 " other, \'x\')");
11903
11904 // HasLocalElement.
11905 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
11906
11907 CHECK_EQ(false, global0->HasRealIndexedProperty(0));
11908 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
11909 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
11910
11911 // Reset the failed access check callback so it does not influence
11912 // the other tests.
11913 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
11914}
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011915
11916
11917TEST(StringCheckMultipleContexts) {
11918 const char* code =
11919 "(function() { return \"a\".charAt(0); })()";
11920
11921 {
11922 // Run the code twice in the first context to initialize the call IC.
11923 v8::HandleScope scope;
11924 LocalContext context1;
11925 ExpectString(code, "a");
11926 ExpectString(code, "a");
11927 }
11928
11929 {
11930 // Change the String.prototype in the second context and check
11931 // that the right function gets called.
11932 v8::HandleScope scope;
11933 LocalContext context2;
11934 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
11935 ExpectString(code, "not a");
11936 }
11937}
11938
11939
11940TEST(NumberCheckMultipleContexts) {
11941 const char* code =
11942 "(function() { return (42).toString(); })()";
11943
11944 {
11945 // Run the code twice in the first context to initialize the call IC.
11946 v8::HandleScope scope;
11947 LocalContext context1;
11948 ExpectString(code, "42");
11949 ExpectString(code, "42");
11950 }
11951
11952 {
11953 // Change the Number.prototype in the second context and check
11954 // that the right function gets called.
11955 v8::HandleScope scope;
11956 LocalContext context2;
11957 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
11958 ExpectString(code, "not 42");
11959 }
11960}
11961
11962
11963TEST(BooleanCheckMultipleContexts) {
11964 const char* code =
11965 "(function() { return true.toString(); })()";
11966
11967 {
11968 // Run the code twice in the first context to initialize the call IC.
11969 v8::HandleScope scope;
11970 LocalContext context1;
11971 ExpectString(code, "true");
11972 ExpectString(code, "true");
11973 }
11974
11975 {
11976 // Change the Boolean.prototype in the second context and check
11977 // that the right function gets called.
11978 v8::HandleScope scope;
11979 LocalContext context2;
11980 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
11981 ExpectString(code, "");
11982 }
11983}
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000011984
11985
11986TEST(DontDeleteCellLoadIC) {
11987 const char* function_code =
11988 "function readCell() { while (true) { return cell; } }";
11989
11990 {
11991 // Run the code twice in the first context to initialize the load
11992 // IC for a don't delete cell.
11993 v8::HandleScope scope;
11994 LocalContext context1;
11995 CompileRun("var cell = \"first\";");
11996 ExpectBoolean("delete cell", false);
11997 CompileRun(function_code);
11998 ExpectString("readCell()", "first");
11999 ExpectString("readCell()", "first");
12000 }
12001
12002 {
12003 // Use a deletable cell in the second context.
12004 v8::HandleScope scope;
12005 LocalContext context2;
12006 CompileRun("cell = \"second\";");
12007 CompileRun(function_code);
12008 ExpectString("readCell()", "second");
12009 ExpectBoolean("delete cell", true);
12010 ExpectString("(function() {"
12011 " try {"
12012 " return readCell();"
12013 " } catch(e) {"
12014 " return e.toString();"
12015 " }"
12016 "})()",
12017 "ReferenceError: cell is not defined");
12018 CompileRun("cell = \"new_second\";");
12019 i::Heap::CollectAllGarbage(true);
12020 ExpectString("readCell()", "new_second");
12021 ExpectString("readCell()", "new_second");
12022 }
12023}
12024
12025
12026TEST(DontDeleteCellLoadICForceDelete) {
12027 const char* function_code =
12028 "function readCell() { while (true) { return cell; } }";
12029
12030 // Run the code twice to initialize the load IC for a don't delete
12031 // cell.
12032 v8::HandleScope scope;
12033 LocalContext context;
12034 CompileRun("var cell = \"value\";");
12035 ExpectBoolean("delete cell", false);
12036 CompileRun(function_code);
12037 ExpectString("readCell()", "value");
12038 ExpectString("readCell()", "value");
12039
12040 // Delete the cell using the API and check the inlined code works
12041 // correctly.
12042 CHECK(context->Global()->ForceDelete(v8_str("cell")));
12043 ExpectString("(function() {"
12044 " try {"
12045 " return readCell();"
12046 " } catch(e) {"
12047 " return e.toString();"
12048 " }"
12049 "})()",
12050 "ReferenceError: cell is not defined");
12051}
12052
12053
12054TEST(DontDeleteCellLoadICAPI) {
12055 const char* function_code =
12056 "function readCell() { while (true) { return cell; } }";
12057
12058 // Run the code twice to initialize the load IC for a don't delete
12059 // cell created using the API.
12060 v8::HandleScope scope;
12061 LocalContext context;
12062 context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
12063 ExpectBoolean("delete cell", false);
12064 CompileRun(function_code);
12065 ExpectString("readCell()", "value");
12066 ExpectString("readCell()", "value");
12067
12068 // Delete the cell using the API and check the inlined code works
12069 // correctly.
12070 CHECK(context->Global()->ForceDelete(v8_str("cell")));
12071 ExpectString("(function() {"
12072 " try {"
12073 " return readCell();"
12074 " } catch(e) {"
12075 " return e.toString();"
12076 " }"
12077 "})()",
12078 "ReferenceError: cell is not defined");
12079}
12080
12081
12082TEST(GlobalLoadICGC) {
12083 const char* function_code =
12084 "function readCell() { while (true) { return cell; } }";
12085
12086 // Check inline load code for a don't delete cell is cleared during
12087 // GC.
12088 {
12089 v8::HandleScope scope;
12090 LocalContext context;
12091 CompileRun("var cell = \"value\";");
12092 ExpectBoolean("delete cell", false);
12093 CompileRun(function_code);
12094 ExpectString("readCell()", "value");
12095 ExpectString("readCell()", "value");
12096 }
12097 {
12098 v8::HandleScope scope;
12099 LocalContext context2;
12100 // Hold the code object in the second context.
12101 CompileRun(function_code);
12102 CheckSurvivingGlobalObjectsCount(1);
12103 }
12104
12105 // Check inline load code for a deletable cell is cleared during GC.
12106 {
12107 v8::HandleScope scope;
12108 LocalContext context;
12109 CompileRun("cell = \"value\";");
12110 CompileRun(function_code);
12111 ExpectString("readCell()", "value");
12112 ExpectString("readCell()", "value");
12113 }
12114 {
12115 v8::HandleScope scope;
12116 LocalContext context2;
12117 // Hold the code object in the second context.
12118 CompileRun(function_code);
12119 CheckSurvivingGlobalObjectsCount(1);
12120 }
12121}
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000012122
12123
12124TEST(RegExp) {
12125 v8::HandleScope scope;
12126 LocalContext context;
12127
12128 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
12129 CHECK(re->IsRegExp());
12130 CHECK(re->GetSource()->Equals(v8_str("foo")));
12131 CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
12132
12133 re = v8::RegExp::New(v8_str("bar"),
12134 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
12135 v8::RegExp::kGlobal));
12136 CHECK(re->IsRegExp());
12137 CHECK(re->GetSource()->Equals(v8_str("bar")));
12138 CHECK_EQ(static_cast<int>(re->GetFlags()),
12139 v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal);
12140
12141 re = v8::RegExp::New(v8_str("baz"),
12142 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
12143 v8::RegExp::kMultiline));
12144 CHECK(re->IsRegExp());
12145 CHECK(re->GetSource()->Equals(v8_str("baz")));
12146 CHECK_EQ(static_cast<int>(re->GetFlags()),
12147 v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline);
12148
12149 re = CompileRun("/quux/").As<v8::RegExp>();
12150 CHECK(re->IsRegExp());
12151 CHECK(re->GetSource()->Equals(v8_str("quux")));
12152 CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
12153
12154 re = CompileRun("/quux/gm").As<v8::RegExp>();
12155 CHECK(re->IsRegExp());
12156 CHECK(re->GetSource()->Equals(v8_str("quux")));
12157 CHECK_EQ(static_cast<int>(re->GetFlags()),
12158 v8::RegExp::kGlobal | v8::RegExp::kMultiline);
12159
12160 // Override the RegExp constructor and check the API constructor
12161 // still works.
12162 CompileRun("RegExp = function() {}");
12163
12164 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
12165 CHECK(re->IsRegExp());
12166 CHECK(re->GetSource()->Equals(v8_str("foobar")));
12167 CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
12168
12169 re = v8::RegExp::New(v8_str("foobarbaz"),
12170 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
12171 v8::RegExp::kMultiline));
12172 CHECK(re->IsRegExp());
12173 CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
12174 CHECK_EQ(static_cast<int>(re->GetFlags()),
12175 v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline);
12176
12177 context->Global()->Set(v8_str("re"), re);
12178 ExpectTrue("re.test('FoobarbaZ')");
12179
12180 v8::TryCatch try_catch;
12181 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
12182 CHECK(re.IsEmpty());
12183 CHECK(try_catch.HasCaught());
12184 context->Global()->Set(v8_str("ex"), try_catch.Exception());
12185 ExpectTrue("ex instanceof SyntaxError");
12186}
12187
12188
12189static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
12190 const v8::AccessorInfo& info ) {
12191 return v8_str("42!");
12192}
12193
12194
12195static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo& info) {
12196 v8::Handle<v8::Array> result = v8::Array::New();
12197 result->Set(0, v8_str("universalAnswer"));
12198 return result;
12199}
12200
12201
12202TEST(NamedEnumeratorAndForIn) {
12203 v8::HandleScope handle_scope;
12204 LocalContext context;
12205 v8::Context::Scope context_scope(context.local());
12206
12207 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New();
12208 tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
12209 context->Global()->Set(v8_str("o"), tmpl->NewInstance());
12210 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
12211 "var result = []; for (var k in o) result.push(k); result"));
12212 CHECK_EQ(1, result->Length());
12213 CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
12214}