blob: 5d197bebbd30c4b96a9c2b7b1b583d561be7a56a [file] [log] [blame]
Ben Murdoch8b112d22011-06-08 16:22:53 +01001// Copyright 2011 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +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
Steve Block3ce2e202009-11-05 08:53:23 +000028#include <limits.h>
Steve Blocka7e24c12009-10-30 11:49:00 +000029
30#include "v8.h"
31
32#include "api.h"
Ben Murdoch257744e2011-11-30 15:57:28 +000033#include "isolate.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000034#include "compilation-cache.h"
35#include "execution.h"
36#include "snapshot.h"
37#include "platform.h"
Steve Block3ce2e202009-11-05 08:53:23 +000038#include "utils.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000039#include "cctest.h"
Iain Merrick9ac36c92010-09-13 15:29:50 +010040#include "parser.h"
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -080041#include "unicode-inl.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000042
Ben Murdoch257744e2011-11-30 15:57:28 +000043static const bool kLogThreading = false;
Steve Blockd0582a62009-12-15 09:54:21 +000044
Steve Blocka7e24c12009-10-30 11:49:00 +000045static bool IsNaN(double x) {
46#ifdef WIN32
47 return _isnan(x);
48#else
49 return isnan(x);
50#endif
51}
52
Steve Blocka7e24c12009-10-30 11:49:00 +000053using ::v8::AccessorInfo;
Ben Murdoch8b112d22011-06-08 16:22:53 +010054using ::v8::Arguments;
Steve Block44f0eee2011-05-26 01:26:41 +010055using ::v8::Context;
Steve Blocka7e24c12009-10-30 11:49:00 +000056using ::v8::Extension;
Steve Block44f0eee2011-05-26 01:26:41 +010057using ::v8::Function;
Ben Murdoch8b112d22011-06-08 16:22:53 +010058using ::v8::FunctionTemplate;
59using ::v8::Handle;
Steve Block44f0eee2011-05-26 01:26:41 +010060using ::v8::HandleScope;
61using ::v8::Local;
Ben Murdoch8b112d22011-06-08 16:22:53 +010062using ::v8::Message;
63using ::v8::MessageCallback;
Steve Block44f0eee2011-05-26 01:26:41 +010064using ::v8::Object;
65using ::v8::ObjectTemplate;
66using ::v8::Persistent;
67using ::v8::Script;
Ben Murdoch8b112d22011-06-08 16:22:53 +010068using ::v8::StackTrace;
Steve Block44f0eee2011-05-26 01:26:41 +010069using ::v8::String;
Ben Murdoch8b112d22011-06-08 16:22:53 +010070using ::v8::TryCatch;
71using ::v8::Undefined;
Steve Block44f0eee2011-05-26 01:26:41 +010072using ::v8::V8;
Ben Murdoch8b112d22011-06-08 16:22:53 +010073using ::v8::Value;
Steve Blocka7e24c12009-10-30 11:49:00 +000074
Steve Block8defd9f2010-07-08 12:39:36 +010075namespace i = ::i;
Steve Blocka7e24c12009-10-30 11:49:00 +000076
Steve Blocka7e24c12009-10-30 11:49:00 +000077
Leon Clarked91b9f72010-01-27 17:25:45 +000078static void ExpectString(const char* code, const char* expected) {
79 Local<Value> result = CompileRun(code);
80 CHECK(result->IsString());
81 String::AsciiValue ascii(result);
82 CHECK_EQ(expected, *ascii);
83}
84
85
86static void ExpectBoolean(const char* code, bool expected) {
87 Local<Value> result = CompileRun(code);
88 CHECK(result->IsBoolean());
89 CHECK_EQ(expected, result->BooleanValue());
90}
91
92
Leon Clarkef7060e22010-06-03 12:02:55 +010093static void ExpectTrue(const char* code) {
94 ExpectBoolean(code, true);
95}
96
97
Iain Merrick75681382010-08-19 15:07:18 +010098static void ExpectFalse(const char* code) {
99 ExpectBoolean(code, false);
100}
101
102
Leon Clarked91b9f72010-01-27 17:25:45 +0000103static void ExpectObject(const char* code, Local<Value> expected) {
104 Local<Value> result = CompileRun(code);
105 CHECK(result->Equals(expected));
106}
107
108
Iain Merrick75681382010-08-19 15:07:18 +0100109static void ExpectUndefined(const char* code) {
110 Local<Value> result = CompileRun(code);
111 CHECK(result->IsUndefined());
112}
113
114
Steve Blocka7e24c12009-10-30 11:49:00 +0000115static int signature_callback_count;
116static v8::Handle<Value> IncrementingSignatureCallback(
117 const v8::Arguments& args) {
118 ApiTestFuzzer::Fuzz();
119 signature_callback_count++;
120 v8::Handle<v8::Array> result = v8::Array::New(args.Length());
121 for (int i = 0; i < args.Length(); i++)
122 result->Set(v8::Integer::New(i), args[i]);
123 return result;
124}
125
126
127static v8::Handle<Value> SignatureCallback(const v8::Arguments& args) {
128 ApiTestFuzzer::Fuzz();
129 v8::Handle<v8::Array> result = v8::Array::New(args.Length());
130 for (int i = 0; i < args.Length(); i++) {
131 result->Set(v8::Integer::New(i), args[i]);
132 }
133 return result;
134}
135
136
137THREADED_TEST(Handles) {
138 v8::HandleScope scope;
139 Local<Context> local_env;
140 {
141 LocalContext env;
142 local_env = env.local();
143 }
144
145 // Local context should still be live.
146 CHECK(!local_env.IsEmpty());
147 local_env->Enter();
148
149 v8::Handle<v8::Primitive> undef = v8::Undefined();
150 CHECK(!undef.IsEmpty());
151 CHECK(undef->IsUndefined());
152
153 const char* c_source = "1 + 2 + 3";
154 Local<String> source = String::New(c_source);
155 Local<Script> script = Script::Compile(source);
156 CHECK_EQ(6, script->Run()->Int32Value());
157
158 local_env->Exit();
159}
160
161
Steve Blocka7e24c12009-10-30 11:49:00 +0000162THREADED_TEST(ReceiverSignature) {
163 v8::HandleScope scope;
164 LocalContext env;
165 v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
166 v8::Handle<v8::Signature> sig = v8::Signature::New(fun);
167 fun->PrototypeTemplate()->Set(
168 v8_str("m"),
169 v8::FunctionTemplate::New(IncrementingSignatureCallback,
170 v8::Handle<Value>(),
171 sig));
172 env->Global()->Set(v8_str("Fun"), fun->GetFunction());
173 signature_callback_count = 0;
174 CompileRun(
175 "var o = new Fun();"
176 "o.m();");
177 CHECK_EQ(1, signature_callback_count);
178 v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New();
179 sub_fun->Inherit(fun);
180 env->Global()->Set(v8_str("SubFun"), sub_fun->GetFunction());
181 CompileRun(
182 "var o = new SubFun();"
183 "o.m();");
184 CHECK_EQ(2, signature_callback_count);
185
186 v8::TryCatch try_catch;
187 CompileRun(
188 "var o = { };"
189 "o.m = Fun.prototype.m;"
190 "o.m();");
191 CHECK_EQ(2, signature_callback_count);
192 CHECK(try_catch.HasCaught());
193 try_catch.Reset();
194 v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New();
195 sub_fun->Inherit(fun);
196 env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
197 CompileRun(
198 "var o = new UnrelFun();"
199 "o.m = Fun.prototype.m;"
200 "o.m();");
201 CHECK_EQ(2, signature_callback_count);
202 CHECK(try_catch.HasCaught());
203}
204
205
Steve Blocka7e24c12009-10-30 11:49:00 +0000206THREADED_TEST(ArgumentSignature) {
207 v8::HandleScope scope;
208 LocalContext env;
209 v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New();
210 cons->SetClassName(v8_str("Cons"));
211 v8::Handle<v8::Signature> sig =
212 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 1, &cons);
213 v8::Handle<v8::FunctionTemplate> fun =
214 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig);
215 env->Global()->Set(v8_str("Cons"), cons->GetFunction());
216 env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
217
218 v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
219 CHECK(value1->IsTrue());
220
221 v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
222 CHECK(value2->IsTrue());
223
224 v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
225 CHECK(value3->IsTrue());
226
227 v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New();
228 cons1->SetClassName(v8_str("Cons1"));
229 v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New();
230 cons2->SetClassName(v8_str("Cons2"));
231 v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New();
232 cons3->SetClassName(v8_str("Cons3"));
233
234 v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
235 v8::Handle<v8::Signature> wsig =
236 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 3, args);
237 v8::Handle<v8::FunctionTemplate> fun2 =
238 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig);
239
240 env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
241 env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
242 env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
243 env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
244 v8::Handle<Value> value4 = CompileRun(
245 "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
246 "'[object Cons1],[object Cons2],[object Cons3]'");
247 CHECK(value4->IsTrue());
248
249 v8::Handle<Value> value5 = CompileRun(
250 "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
251 CHECK(value5->IsTrue());
252
253 v8::Handle<Value> value6 = CompileRun(
254 "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
255 CHECK(value6->IsTrue());
256
257 v8::Handle<Value> value7 = CompileRun(
258 "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
259 "'[object Cons1],[object Cons2],[object Cons3],d';");
260 CHECK(value7->IsTrue());
261
262 v8::Handle<Value> value8 = CompileRun(
263 "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
264 CHECK(value8->IsTrue());
265}
266
267
268THREADED_TEST(HulIgennem) {
269 v8::HandleScope scope;
270 LocalContext env;
271 v8::Handle<v8::Primitive> undef = v8::Undefined();
272 Local<String> undef_str = undef->ToString();
273 char* value = i::NewArray<char>(undef_str->Length() + 1);
274 undef_str->WriteAscii(value);
275 CHECK_EQ(0, strcmp(value, "undefined"));
276 i::DeleteArray(value);
277}
278
279
280THREADED_TEST(Access) {
281 v8::HandleScope scope;
282 LocalContext env;
283 Local<v8::Object> obj = v8::Object::New();
284 Local<Value> foo_before = obj->Get(v8_str("foo"));
285 CHECK(foo_before->IsUndefined());
286 Local<String> bar_str = v8_str("bar");
287 obj->Set(v8_str("foo"), bar_str);
288 Local<Value> foo_after = obj->Get(v8_str("foo"));
289 CHECK(!foo_after->IsUndefined());
290 CHECK(foo_after->IsString());
291 CHECK_EQ(bar_str, foo_after);
292}
293
294
Steve Block6ded16b2010-05-10 14:33:55 +0100295THREADED_TEST(AccessElement) {
296 v8::HandleScope scope;
297 LocalContext env;
298 Local<v8::Object> obj = v8::Object::New();
299 Local<Value> before = obj->Get(1);
300 CHECK(before->IsUndefined());
301 Local<String> bar_str = v8_str("bar");
302 obj->Set(1, bar_str);
303 Local<Value> after = obj->Get(1);
304 CHECK(!after->IsUndefined());
305 CHECK(after->IsString());
306 CHECK_EQ(bar_str, after);
307
308 Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
309 CHECK_EQ(v8_str("a"), value->Get(0));
310 CHECK_EQ(v8_str("b"), value->Get(1));
311}
312
313
Steve Blocka7e24c12009-10-30 11:49:00 +0000314THREADED_TEST(Script) {
315 v8::HandleScope scope;
316 LocalContext env;
317 const char* c_source = "1 + 2 + 3";
318 Local<String> source = String::New(c_source);
319 Local<Script> script = Script::Compile(source);
320 CHECK_EQ(6, script->Run()->Int32Value());
321}
322
323
324static uint16_t* AsciiToTwoByteString(const char* source) {
Steve Blockd0582a62009-12-15 09:54:21 +0000325 int array_length = i::StrLength(source) + 1;
Steve Blocka7e24c12009-10-30 11:49:00 +0000326 uint16_t* converted = i::NewArray<uint16_t>(array_length);
Steve Blockd0582a62009-12-15 09:54:21 +0000327 for (int i = 0; i < array_length; i++) converted[i] = source[i];
Steve Blocka7e24c12009-10-30 11:49:00 +0000328 return converted;
329}
330
331
332class TestResource: public String::ExternalStringResource {
333 public:
334 static int dispose_count;
335
336 explicit TestResource(uint16_t* data)
337 : data_(data), length_(0) {
338 while (data[length_]) ++length_;
339 }
340
341 ~TestResource() {
342 i::DeleteArray(data_);
343 ++dispose_count;
344 }
345
346 const uint16_t* data() const {
347 return data_;
348 }
349
350 size_t length() const {
351 return length_;
352 }
353 private:
354 uint16_t* data_;
355 size_t length_;
356};
357
358
359int TestResource::dispose_count = 0;
360
361
362class TestAsciiResource: public String::ExternalAsciiStringResource {
363 public:
364 static int dispose_count;
365
366 explicit TestAsciiResource(const char* data)
367 : data_(data),
368 length_(strlen(data)) { }
369
370 ~TestAsciiResource() {
371 i::DeleteArray(data_);
372 ++dispose_count;
373 }
374
375 const char* data() const {
376 return data_;
377 }
378
379 size_t length() const {
380 return length_;
381 }
382 private:
383 const char* data_;
384 size_t length_;
385};
386
387
388int TestAsciiResource::dispose_count = 0;
389
390
391THREADED_TEST(ScriptUsingStringResource) {
392 TestResource::dispose_count = 0;
393 const char* c_source = "1 + 2 * 3";
394 uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
395 {
396 v8::HandleScope scope;
397 LocalContext env;
398 TestResource* resource = new TestResource(two_byte_source);
399 Local<String> source = String::NewExternal(resource);
400 Local<Script> script = Script::Compile(source);
401 Local<Value> value = script->Run();
402 CHECK(value->IsNumber());
403 CHECK_EQ(7, value->Int32Value());
404 CHECK(source->IsExternal());
405 CHECK_EQ(resource,
406 static_cast<TestResource*>(source->GetExternalStringResource()));
Steve Block44f0eee2011-05-26 01:26:41 +0100407 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000408 CHECK_EQ(0, TestResource::dispose_count);
409 }
Steve Block44f0eee2011-05-26 01:26:41 +0100410 v8::internal::Isolate::Current()->compilation_cache()->Clear();
411 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000412 CHECK_EQ(1, TestResource::dispose_count);
413}
414
415
416THREADED_TEST(ScriptUsingAsciiStringResource) {
417 TestAsciiResource::dispose_count = 0;
418 const char* c_source = "1 + 2 * 3";
419 {
420 v8::HandleScope scope;
421 LocalContext env;
422 Local<String> source =
423 String::NewExternal(new TestAsciiResource(i::StrDup(c_source)));
424 Local<Script> script = Script::Compile(source);
425 Local<Value> value = script->Run();
426 CHECK(value->IsNumber());
427 CHECK_EQ(7, value->Int32Value());
Steve Block44f0eee2011-05-26 01:26:41 +0100428 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000429 CHECK_EQ(0, TestAsciiResource::dispose_count);
430 }
Steve Block44f0eee2011-05-26 01:26:41 +0100431 i::Isolate::Current()->compilation_cache()->Clear();
432 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000433 CHECK_EQ(1, TestAsciiResource::dispose_count);
434}
435
436
437THREADED_TEST(ScriptMakingExternalString) {
438 TestResource::dispose_count = 0;
439 uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
440 {
441 v8::HandleScope scope;
442 LocalContext env;
443 Local<String> source = String::New(two_byte_source);
Andrei Popescu402d9372010-02-26 13:31:12 +0000444 // Trigger GCs so that the newly allocated string moves to old gen.
Steve Block44f0eee2011-05-26 01:26:41 +0100445 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
446 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
Steve Blocka7e24c12009-10-30 11:49:00 +0000447 bool success = source->MakeExternal(new TestResource(two_byte_source));
448 CHECK(success);
449 Local<Script> script = Script::Compile(source);
450 Local<Value> value = script->Run();
451 CHECK(value->IsNumber());
452 CHECK_EQ(7, value->Int32Value());
Steve Block44f0eee2011-05-26 01:26:41 +0100453 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000454 CHECK_EQ(0, TestResource::dispose_count);
455 }
Steve Block44f0eee2011-05-26 01:26:41 +0100456 i::Isolate::Current()->compilation_cache()->Clear();
457 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000458 CHECK_EQ(1, TestResource::dispose_count);
459}
460
461
462THREADED_TEST(ScriptMakingExternalAsciiString) {
463 TestAsciiResource::dispose_count = 0;
464 const char* c_source = "1 + 2 * 3";
465 {
466 v8::HandleScope scope;
467 LocalContext env;
468 Local<String> source = v8_str(c_source);
Andrei Popescu402d9372010-02-26 13:31:12 +0000469 // Trigger GCs so that the newly allocated string moves to old gen.
Steve Block44f0eee2011-05-26 01:26:41 +0100470 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
471 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
Steve Blocka7e24c12009-10-30 11:49:00 +0000472 bool success = source->MakeExternal(
473 new TestAsciiResource(i::StrDup(c_source)));
474 CHECK(success);
475 Local<Script> script = Script::Compile(source);
476 Local<Value> value = script->Run();
477 CHECK(value->IsNumber());
478 CHECK_EQ(7, value->Int32Value());
Steve Block44f0eee2011-05-26 01:26:41 +0100479 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000480 CHECK_EQ(0, TestAsciiResource::dispose_count);
481 }
Steve Block44f0eee2011-05-26 01:26:41 +0100482 i::Isolate::Current()->compilation_cache()->Clear();
483 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000484 CHECK_EQ(1, TestAsciiResource::dispose_count);
485}
486
487
Andrei Popescu402d9372010-02-26 13:31:12 +0000488TEST(MakingExternalStringConditions) {
489 v8::HandleScope scope;
490 LocalContext env;
491
492 // Free some space in the new space so that we can check freshness.
Steve Block44f0eee2011-05-26 01:26:41 +0100493 HEAP->CollectGarbage(i::NEW_SPACE);
494 HEAP->CollectGarbage(i::NEW_SPACE);
Andrei Popescu402d9372010-02-26 13:31:12 +0000495
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100496 uint16_t* two_byte_string = AsciiToTwoByteString("small");
497 Local<String> small_string = String::New(two_byte_string);
498 i::DeleteArray(two_byte_string);
499
Andrei Popescu402d9372010-02-26 13:31:12 +0000500 // We should refuse to externalize newly created small string.
501 CHECK(!small_string->CanMakeExternal());
502 // Trigger GCs so that the newly allocated string moves to old gen.
Steve Block44f0eee2011-05-26 01:26:41 +0100503 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
504 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
Andrei Popescu402d9372010-02-26 13:31:12 +0000505 // Old space strings should be accepted.
506 CHECK(small_string->CanMakeExternal());
507
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100508 two_byte_string = AsciiToTwoByteString("small 2");
509 small_string = String::New(two_byte_string);
510 i::DeleteArray(two_byte_string);
511
Andrei Popescu402d9372010-02-26 13:31:12 +0000512 // We should refuse externalizing newly created small string.
513 CHECK(!small_string->CanMakeExternal());
514 for (int i = 0; i < 100; i++) {
515 String::Value value(small_string);
516 }
517 // Frequently used strings should be accepted.
518 CHECK(small_string->CanMakeExternal());
519
520 const int buf_size = 10 * 1024;
521 char* buf = i::NewArray<char>(buf_size);
522 memset(buf, 'a', buf_size);
523 buf[buf_size - 1] = '\0';
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100524
525 two_byte_string = AsciiToTwoByteString(buf);
526 Local<String> large_string = String::New(two_byte_string);
Andrei Popescu402d9372010-02-26 13:31:12 +0000527 i::DeleteArray(buf);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100528 i::DeleteArray(two_byte_string);
Andrei Popescu402d9372010-02-26 13:31:12 +0000529 // Large strings should be immediately accepted.
530 CHECK(large_string->CanMakeExternal());
531}
532
533
534TEST(MakingExternalAsciiStringConditions) {
535 v8::HandleScope scope;
536 LocalContext env;
537
538 // Free some space in the new space so that we can check freshness.
Steve Block44f0eee2011-05-26 01:26:41 +0100539 HEAP->CollectGarbage(i::NEW_SPACE);
540 HEAP->CollectGarbage(i::NEW_SPACE);
Andrei Popescu402d9372010-02-26 13:31:12 +0000541
542 Local<String> small_string = String::New("small");
543 // We should refuse to externalize newly created small string.
544 CHECK(!small_string->CanMakeExternal());
545 // Trigger GCs so that the newly allocated string moves to old gen.
Steve Block44f0eee2011-05-26 01:26:41 +0100546 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
547 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
Andrei Popescu402d9372010-02-26 13:31:12 +0000548 // Old space strings should be accepted.
549 CHECK(small_string->CanMakeExternal());
550
551 small_string = String::New("small 2");
552 // We should refuse externalizing newly created small string.
553 CHECK(!small_string->CanMakeExternal());
554 for (int i = 0; i < 100; i++) {
555 String::Value value(small_string);
556 }
557 // Frequently used strings should be accepted.
558 CHECK(small_string->CanMakeExternal());
559
560 const int buf_size = 10 * 1024;
561 char* buf = i::NewArray<char>(buf_size);
562 memset(buf, 'a', buf_size);
563 buf[buf_size - 1] = '\0';
564 Local<String> large_string = String::New(buf);
565 i::DeleteArray(buf);
566 // Large strings should be immediately accepted.
567 CHECK(large_string->CanMakeExternal());
568}
569
570
Steve Blocka7e24c12009-10-30 11:49:00 +0000571THREADED_TEST(UsingExternalString) {
572 {
573 v8::HandleScope scope;
574 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
575 Local<String> string =
576 String::NewExternal(new TestResource(two_byte_string));
577 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
578 // Trigger GCs so that the newly allocated string moves to old gen.
Steve Block44f0eee2011-05-26 01:26:41 +0100579 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
580 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
581 i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
Steve Blocka7e24c12009-10-30 11:49:00 +0000582 CHECK(isymbol->IsSymbol());
583 }
Steve Block44f0eee2011-05-26 01:26:41 +0100584 HEAP->CollectAllGarbage(false);
585 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000586}
587
588
589THREADED_TEST(UsingExternalAsciiString) {
590 {
591 v8::HandleScope scope;
592 const char* one_byte_string = "test string";
593 Local<String> string = String::NewExternal(
594 new TestAsciiResource(i::StrDup(one_byte_string)));
595 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
596 // Trigger GCs so that the newly allocated string moves to old gen.
Steve Block44f0eee2011-05-26 01:26:41 +0100597 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
598 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
599 i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
Steve Blocka7e24c12009-10-30 11:49:00 +0000600 CHECK(isymbol->IsSymbol());
601 }
Steve Block44f0eee2011-05-26 01:26:41 +0100602 HEAP->CollectAllGarbage(false);
603 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000604}
605
606
Leon Clarkee46be812010-01-19 14:06:41 +0000607THREADED_TEST(ScavengeExternalString) {
608 TestResource::dispose_count = 0;
Steve Block6ded16b2010-05-10 14:33:55 +0100609 bool in_new_space = false;
Leon Clarkee46be812010-01-19 14:06:41 +0000610 {
611 v8::HandleScope scope;
612 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
613 Local<String> string =
614 String::NewExternal(new TestResource(two_byte_string));
615 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
Steve Block44f0eee2011-05-26 01:26:41 +0100616 HEAP->CollectGarbage(i::NEW_SPACE);
617 in_new_space = HEAP->InNewSpace(*istring);
618 CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
Leon Clarkee46be812010-01-19 14:06:41 +0000619 CHECK_EQ(0, TestResource::dispose_count);
620 }
Steve Block44f0eee2011-05-26 01:26:41 +0100621 HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
Leon Clarkee46be812010-01-19 14:06:41 +0000622 CHECK_EQ(1, TestResource::dispose_count);
623}
624
625
626THREADED_TEST(ScavengeExternalAsciiString) {
627 TestAsciiResource::dispose_count = 0;
Steve Block6ded16b2010-05-10 14:33:55 +0100628 bool in_new_space = false;
Leon Clarkee46be812010-01-19 14:06:41 +0000629 {
630 v8::HandleScope scope;
631 const char* one_byte_string = "test string";
632 Local<String> string = String::NewExternal(
633 new TestAsciiResource(i::StrDup(one_byte_string)));
634 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
Steve Block44f0eee2011-05-26 01:26:41 +0100635 HEAP->CollectGarbage(i::NEW_SPACE);
636 in_new_space = HEAP->InNewSpace(*istring);
637 CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
Leon Clarkee46be812010-01-19 14:06:41 +0000638 CHECK_EQ(0, TestAsciiResource::dispose_count);
639 }
Steve Block44f0eee2011-05-26 01:26:41 +0100640 HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
Leon Clarkee46be812010-01-19 14:06:41 +0000641 CHECK_EQ(1, TestAsciiResource::dispose_count);
642}
643
644
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100645class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
646 public:
647 static int dispose_calls;
648
649 TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
650 : TestAsciiResource(data),
651 dispose_(dispose) { }
652
653 void Dispose() {
654 ++dispose_calls;
655 if (dispose_) delete this;
656 }
657 private:
658 bool dispose_;
659};
660
661
662int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
663
664
665TEST(ExternalStringWithDisposeHandling) {
666 const char* c_source = "1 + 2 * 3";
667
668 // Use a stack allocated external string resource allocated object.
669 TestAsciiResource::dispose_count = 0;
670 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
671 TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
672 {
673 v8::HandleScope scope;
674 LocalContext env;
675 Local<String> source = String::NewExternal(&res_stack);
676 Local<Script> script = Script::Compile(source);
677 Local<Value> value = script->Run();
678 CHECK(value->IsNumber());
679 CHECK_EQ(7, value->Int32Value());
Steve Block44f0eee2011-05-26 01:26:41 +0100680 HEAP->CollectAllGarbage(false);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100681 CHECK_EQ(0, TestAsciiResource::dispose_count);
682 }
Steve Block44f0eee2011-05-26 01:26:41 +0100683 i::Isolate::Current()->compilation_cache()->Clear();
684 HEAP->CollectAllGarbage(false);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100685 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
686 CHECK_EQ(0, TestAsciiResource::dispose_count);
687
688 // Use a heap allocated external string resource allocated object.
689 TestAsciiResource::dispose_count = 0;
690 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
691 TestAsciiResource* res_heap =
692 new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
693 {
694 v8::HandleScope scope;
695 LocalContext env;
696 Local<String> source = String::NewExternal(res_heap);
697 Local<Script> script = Script::Compile(source);
698 Local<Value> value = script->Run();
699 CHECK(value->IsNumber());
700 CHECK_EQ(7, value->Int32Value());
Steve Block44f0eee2011-05-26 01:26:41 +0100701 HEAP->CollectAllGarbage(false);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100702 CHECK_EQ(0, TestAsciiResource::dispose_count);
703 }
Steve Block44f0eee2011-05-26 01:26:41 +0100704 i::Isolate::Current()->compilation_cache()->Clear();
705 HEAP->CollectAllGarbage(false);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100706 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
707 CHECK_EQ(1, TestAsciiResource::dispose_count);
708}
709
710
Steve Block3ce2e202009-11-05 08:53:23 +0000711THREADED_TEST(StringConcat) {
712 {
713 v8::HandleScope scope;
714 LocalContext env;
715 const char* one_byte_string_1 = "function a_times_t";
716 const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
717 const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
718 const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
719 const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
720 const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
721 const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
722 Local<String> left = v8_str(one_byte_string_1);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100723
724 uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
725 Local<String> right = String::New(two_byte_source);
726 i::DeleteArray(two_byte_source);
727
Steve Block3ce2e202009-11-05 08:53:23 +0000728 Local<String> source = String::Concat(left, right);
729 right = String::NewExternal(
730 new TestAsciiResource(i::StrDup(one_byte_extern_1)));
731 source = String::Concat(source, right);
732 right = String::NewExternal(
733 new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
734 source = String::Concat(source, right);
735 right = v8_str(one_byte_string_2);
736 source = String::Concat(source, right);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100737
738 two_byte_source = AsciiToTwoByteString(two_byte_string_2);
739 right = String::New(two_byte_source);
740 i::DeleteArray(two_byte_source);
741
Steve Block3ce2e202009-11-05 08:53:23 +0000742 source = String::Concat(source, right);
743 right = String::NewExternal(
744 new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
745 source = String::Concat(source, right);
746 Local<Script> script = Script::Compile(source);
747 Local<Value> value = script->Run();
748 CHECK(value->IsNumber());
749 CHECK_EQ(68, value->Int32Value());
750 }
Steve Block44f0eee2011-05-26 01:26:41 +0100751 i::Isolate::Current()->compilation_cache()->Clear();
752 HEAP->CollectAllGarbage(false);
753 HEAP->CollectAllGarbage(false);
Steve Block3ce2e202009-11-05 08:53:23 +0000754}
755
756
Steve Blocka7e24c12009-10-30 11:49:00 +0000757THREADED_TEST(GlobalProperties) {
758 v8::HandleScope scope;
759 LocalContext env;
760 v8::Handle<v8::Object> global = env->Global();
761 global->Set(v8_str("pi"), v8_num(3.1415926));
762 Local<Value> pi = global->Get(v8_str("pi"));
763 CHECK_EQ(3.1415926, pi->NumberValue());
764}
765
766
767static v8::Handle<Value> handle_call(const v8::Arguments& args) {
768 ApiTestFuzzer::Fuzz();
769 return v8_num(102);
770}
771
772
773static v8::Handle<Value> construct_call(const v8::Arguments& args) {
774 ApiTestFuzzer::Fuzz();
775 args.This()->Set(v8_str("x"), v8_num(1));
776 args.This()->Set(v8_str("y"), v8_num(2));
777 return args.This();
778}
779
Ben Murdochf87a2032010-10-22 12:50:53 +0100780static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
781 ApiTestFuzzer::Fuzz();
782 return v8_num(239);
783}
784
785
Steve Blocka7e24c12009-10-30 11:49:00 +0000786THREADED_TEST(FunctionTemplate) {
787 v8::HandleScope scope;
788 LocalContext env;
789 {
790 Local<v8::FunctionTemplate> fun_templ =
791 v8::FunctionTemplate::New(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 // Use SetCallHandler to initialize a function template, should work like the
798 // previous one.
799 {
800 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
801 fun_templ->SetCallHandler(handle_call);
802 Local<Function> fun = fun_templ->GetFunction();
803 env->Global()->Set(v8_str("obj"), fun);
804 Local<Script> script = v8_compile("obj()");
805 CHECK_EQ(102, script->Run()->Int32Value());
806 }
807 // Test constructor calls.
808 {
809 Local<v8::FunctionTemplate> fun_templ =
810 v8::FunctionTemplate::New(construct_call);
811 fun_templ->SetClassName(v8_str("funky"));
Ben Murdochf87a2032010-10-22 12:50:53 +0100812 fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), Return239);
Steve Blocka7e24c12009-10-30 11:49:00 +0000813 Local<Function> fun = fun_templ->GetFunction();
814 env->Global()->Set(v8_str("obj"), fun);
815 Local<Script> script = v8_compile("var s = new obj(); s.x");
816 CHECK_EQ(1, script->Run()->Int32Value());
817
818 Local<Value> result = v8_compile("(new obj()).toString()")->Run();
819 CHECK_EQ(v8_str("[object funky]"), result);
Ben Murdochf87a2032010-10-22 12:50:53 +0100820
821 result = v8_compile("(new obj()).m")->Run();
822 CHECK_EQ(239, result->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +0000823 }
824}
825
826
Ben Murdochb8e0da22011-05-16 14:20:40 +0100827static void* expected_ptr;
828static v8::Handle<v8::Value> callback(const v8::Arguments& args) {
829 void* ptr = v8::External::Unwrap(args.Data());
830 CHECK_EQ(expected_ptr, ptr);
831 return v8::Boolean::New(true);
832}
833
834
835static void TestExternalPointerWrapping() {
836 v8::HandleScope scope;
837 LocalContext env;
838
839 v8::Handle<v8::Value> data = v8::External::Wrap(expected_ptr);
840
841 v8::Handle<v8::Object> obj = v8::Object::New();
842 obj->Set(v8_str("func"),
843 v8::FunctionTemplate::New(callback, data)->GetFunction());
844 env->Global()->Set(v8_str("obj"), obj);
845
846 CHECK(CompileRun(
847 "function foo() {\n"
848 " for (var i = 0; i < 13; i++) obj.func();\n"
849 "}\n"
850 "foo(), true")->BooleanValue());
851}
852
853
854THREADED_TEST(ExternalWrap) {
855 // Check heap allocated object.
856 int* ptr = new int;
857 expected_ptr = ptr;
858 TestExternalPointerWrapping();
859 delete ptr;
860
861 // Check stack allocated object.
862 int foo;
863 expected_ptr = &foo;
864 TestExternalPointerWrapping();
865
866 // Check not aligned addresses.
867 const int n = 100;
868 char* s = new char[n];
869 for (int i = 0; i < n; i++) {
870 expected_ptr = s + i;
871 TestExternalPointerWrapping();
872 }
873
874 delete[] s;
875
876 // Check several invalid addresses.
877 expected_ptr = reinterpret_cast<void*>(1);
878 TestExternalPointerWrapping();
879
880 expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
881 TestExternalPointerWrapping();
882
883 expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
884 TestExternalPointerWrapping();
885
886#if defined(V8_HOST_ARCH_X64)
Steve Block1e0659c2011-05-24 12:43:12 +0100887 // Check a value with a leading 1 bit in x64 Smi encoding.
888 expected_ptr = reinterpret_cast<void*>(0x400000000);
889 TestExternalPointerWrapping();
890
Ben Murdochb8e0da22011-05-16 14:20:40 +0100891 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
892 TestExternalPointerWrapping();
893
894 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
895 TestExternalPointerWrapping();
896#endif
897}
898
899
Steve Blocka7e24c12009-10-30 11:49:00 +0000900THREADED_TEST(FindInstanceInPrototypeChain) {
901 v8::HandleScope scope;
902 LocalContext env;
903
904 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
905 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
906 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
907 derived->Inherit(base);
908
909 Local<v8::Function> base_function = base->GetFunction();
910 Local<v8::Function> derived_function = derived->GetFunction();
911 Local<v8::Function> other_function = other->GetFunction();
912
913 Local<v8::Object> base_instance = base_function->NewInstance();
914 Local<v8::Object> derived_instance = derived_function->NewInstance();
915 Local<v8::Object> derived_instance2 = derived_function->NewInstance();
916 Local<v8::Object> other_instance = other_function->NewInstance();
917 derived_instance2->Set(v8_str("__proto__"), derived_instance);
918 other_instance->Set(v8_str("__proto__"), derived_instance2);
919
920 // base_instance is only an instance of base.
921 CHECK_EQ(base_instance,
922 base_instance->FindInstanceInPrototypeChain(base));
923 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
924 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
925
926 // derived_instance is an instance of base and derived.
927 CHECK_EQ(derived_instance,
928 derived_instance->FindInstanceInPrototypeChain(base));
929 CHECK_EQ(derived_instance,
930 derived_instance->FindInstanceInPrototypeChain(derived));
931 CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
932
933 // other_instance is an instance of other and its immediate
934 // prototype derived_instance2 is an instance of base and derived.
935 // Note, derived_instance is an instance of base and derived too,
936 // but it comes after derived_instance2 in the prototype chain of
937 // other_instance.
938 CHECK_EQ(derived_instance2,
939 other_instance->FindInstanceInPrototypeChain(base));
940 CHECK_EQ(derived_instance2,
941 other_instance->FindInstanceInPrototypeChain(derived));
942 CHECK_EQ(other_instance,
943 other_instance->FindInstanceInPrototypeChain(other));
944}
945
946
Steve Block3ce2e202009-11-05 08:53:23 +0000947THREADED_TEST(TinyInteger) {
948 v8::HandleScope scope;
949 LocalContext env;
950 int32_t value = 239;
951 Local<v8::Integer> value_obj = v8::Integer::New(value);
952 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
953}
954
955
956THREADED_TEST(BigSmiInteger) {
957 v8::HandleScope scope;
958 LocalContext env;
959 int32_t value = i::Smi::kMaxValue;
960 // We cannot add one to a Smi::kMaxValue without wrapping.
961 if (i::kSmiValueSize < 32) {
962 CHECK(i::Smi::IsValid(value));
963 CHECK(!i::Smi::IsValid(value + 1));
964 Local<v8::Integer> value_obj = v8::Integer::New(value);
965 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
966 }
967}
968
969
970THREADED_TEST(BigInteger) {
971 v8::HandleScope scope;
972 LocalContext env;
973 // We cannot add one to a Smi::kMaxValue without wrapping.
974 if (i::kSmiValueSize < 32) {
975 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
976 // The code will not be run in that case, due to the "if" guard.
977 int32_t value =
978 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
979 CHECK(value > i::Smi::kMaxValue);
980 CHECK(!i::Smi::IsValid(value));
981 Local<v8::Integer> value_obj = v8::Integer::New(value);
982 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
983 }
984}
985
986
987THREADED_TEST(TinyUnsignedInteger) {
988 v8::HandleScope scope;
989 LocalContext env;
990 uint32_t value = 239;
991 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
992 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
993}
994
995
996THREADED_TEST(BigUnsignedSmiInteger) {
997 v8::HandleScope scope;
998 LocalContext env;
999 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1000 CHECK(i::Smi::IsValid(value));
1001 CHECK(!i::Smi::IsValid(value + 1));
1002 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1003 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1004}
1005
1006
1007THREADED_TEST(BigUnsignedInteger) {
1008 v8::HandleScope scope;
1009 LocalContext env;
1010 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1011 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1012 CHECK(!i::Smi::IsValid(value));
1013 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1014 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1015}
1016
1017
1018THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1019 v8::HandleScope scope;
1020 LocalContext env;
1021 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1022 uint32_t value = INT32_MAX_AS_UINT + 1;
1023 CHECK(value > INT32_MAX_AS_UINT); // No overflow.
1024 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1025 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1026}
1027
1028
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001029THREADED_TEST(IsNativeError) {
1030 v8::HandleScope scope;
1031 LocalContext env;
1032 v8::Handle<Value> syntax_error = CompileRun(
1033 "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1034 CHECK(syntax_error->IsNativeError());
1035 v8::Handle<Value> not_error = CompileRun("{a:42}");
1036 CHECK(!not_error->IsNativeError());
1037 v8::Handle<Value> not_object = CompileRun("42");
1038 CHECK(!not_object->IsNativeError());
1039}
1040
1041
1042THREADED_TEST(StringObject) {
1043 v8::HandleScope scope;
1044 LocalContext env;
1045 v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1046 CHECK(boxed_string->IsStringObject());
1047 v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1048 CHECK(!unboxed_string->IsStringObject());
1049 v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1050 CHECK(!boxed_not_string->IsStringObject());
1051 v8::Handle<Value> not_object = CompileRun("0");
1052 CHECK(!not_object->IsStringObject());
1053 v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1054 CHECK(!as_boxed.IsEmpty());
1055 Local<v8::String> the_string = as_boxed->StringValue();
1056 CHECK(!the_string.IsEmpty());
1057 ExpectObject("\"test\"", the_string);
1058 v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1059 CHECK(new_boxed_string->IsStringObject());
1060 as_boxed = new_boxed_string.As<v8::StringObject>();
1061 the_string = as_boxed->StringValue();
1062 CHECK(!the_string.IsEmpty());
1063 ExpectObject("\"test\"", the_string);
1064}
1065
1066
1067THREADED_TEST(NumberObject) {
1068 v8::HandleScope scope;
1069 LocalContext env;
1070 v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1071 CHECK(boxed_number->IsNumberObject());
1072 v8::Handle<Value> unboxed_number = CompileRun("42");
1073 CHECK(!unboxed_number->IsNumberObject());
1074 v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1075 CHECK(!boxed_not_number->IsNumberObject());
1076 v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1077 CHECK(!as_boxed.IsEmpty());
1078 double the_number = as_boxed->NumberValue();
1079 CHECK_EQ(42.0, the_number);
1080 v8::Handle<v8::Value> new_boxed_number = v8::NumberObject::New(43);
1081 CHECK(new_boxed_number->IsNumberObject());
1082 as_boxed = new_boxed_number.As<v8::NumberObject>();
1083 the_number = as_boxed->NumberValue();
1084 CHECK_EQ(43.0, the_number);
1085}
1086
1087
1088THREADED_TEST(BooleanObject) {
1089 v8::HandleScope scope;
1090 LocalContext env;
1091 v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1092 CHECK(boxed_boolean->IsBooleanObject());
1093 v8::Handle<Value> unboxed_boolean = CompileRun("true");
1094 CHECK(!unboxed_boolean->IsBooleanObject());
1095 v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1096 CHECK(!boxed_not_boolean->IsBooleanObject());
1097 v8::Handle<v8::BooleanObject> as_boxed =
1098 boxed_boolean.As<v8::BooleanObject>();
1099 CHECK(!as_boxed.IsEmpty());
1100 bool the_boolean = as_boxed->BooleanValue();
1101 CHECK_EQ(true, the_boolean);
1102 v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1103 v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1104 CHECK(boxed_true->IsBooleanObject());
1105 CHECK(boxed_false->IsBooleanObject());
1106 as_boxed = boxed_true.As<v8::BooleanObject>();
1107 CHECK_EQ(true, as_boxed->BooleanValue());
1108 as_boxed = boxed_false.As<v8::BooleanObject>();
1109 CHECK_EQ(false, as_boxed->BooleanValue());
1110}
1111
1112
Steve Blocka7e24c12009-10-30 11:49:00 +00001113THREADED_TEST(Number) {
1114 v8::HandleScope scope;
1115 LocalContext env;
1116 double PI = 3.1415926;
1117 Local<v8::Number> pi_obj = v8::Number::New(PI);
1118 CHECK_EQ(PI, pi_obj->NumberValue());
1119}
1120
1121
1122THREADED_TEST(ToNumber) {
1123 v8::HandleScope scope;
1124 LocalContext env;
1125 Local<String> str = v8_str("3.1415926");
1126 CHECK_EQ(3.1415926, str->NumberValue());
1127 v8::Handle<v8::Boolean> t = v8::True();
1128 CHECK_EQ(1.0, t->NumberValue());
1129 v8::Handle<v8::Boolean> f = v8::False();
1130 CHECK_EQ(0.0, f->NumberValue());
1131}
1132
1133
1134THREADED_TEST(Date) {
1135 v8::HandleScope scope;
1136 LocalContext env;
1137 double PI = 3.1415926;
Ben Murdoch257744e2011-11-30 15:57:28 +00001138 Local<Value> date = v8::Date::New(PI);
1139 CHECK_EQ(3.0, date->NumberValue());
1140 date.As<v8::Date>()->Set(v8_str("property"), v8::Integer::New(42));
1141 CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00001142}
1143
1144
1145THREADED_TEST(Boolean) {
1146 v8::HandleScope scope;
1147 LocalContext env;
1148 v8::Handle<v8::Boolean> t = v8::True();
1149 CHECK(t->Value());
1150 v8::Handle<v8::Boolean> f = v8::False();
1151 CHECK(!f->Value());
1152 v8::Handle<v8::Primitive> u = v8::Undefined();
1153 CHECK(!u->BooleanValue());
1154 v8::Handle<v8::Primitive> n = v8::Null();
1155 CHECK(!n->BooleanValue());
1156 v8::Handle<String> str1 = v8_str("");
1157 CHECK(!str1->BooleanValue());
1158 v8::Handle<String> str2 = v8_str("x");
1159 CHECK(str2->BooleanValue());
1160 CHECK(!v8::Number::New(0)->BooleanValue());
1161 CHECK(v8::Number::New(-1)->BooleanValue());
1162 CHECK(v8::Number::New(1)->BooleanValue());
1163 CHECK(v8::Number::New(42)->BooleanValue());
1164 CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1165}
1166
1167
1168static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
1169 ApiTestFuzzer::Fuzz();
1170 return v8_num(13.4);
1171}
1172
1173
1174static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
1175 ApiTestFuzzer::Fuzz();
1176 return v8_num(876);
1177}
1178
1179
1180THREADED_TEST(GlobalPrototype) {
1181 v8::HandleScope scope;
1182 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
1183 func_templ->PrototypeTemplate()->Set(
1184 "dummy",
1185 v8::FunctionTemplate::New(DummyCallHandler));
1186 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1187 templ->Set("x", v8_num(200));
1188 templ->SetAccessor(v8_str("m"), GetM);
1189 LocalContext env(0, templ);
1190 v8::Handle<v8::Object> obj = env->Global();
1191 v8::Handle<Script> script = v8_compile("dummy()");
1192 v8::Handle<Value> result = script->Run();
1193 CHECK_EQ(13.4, result->NumberValue());
1194 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1195 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1196}
1197
1198
Steve Blocka7e24c12009-10-30 11:49:00 +00001199THREADED_TEST(ObjectTemplate) {
1200 v8::HandleScope scope;
1201 Local<ObjectTemplate> templ1 = ObjectTemplate::New();
1202 templ1->Set("x", v8_num(10));
1203 templ1->Set("y", v8_num(13));
1204 LocalContext env;
1205 Local<v8::Object> instance1 = templ1->NewInstance();
1206 env->Global()->Set(v8_str("p"), instance1);
1207 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1208 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1209 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
1210 fun->PrototypeTemplate()->Set("nirk", v8_num(123));
1211 Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1212 templ2->Set("a", v8_num(12));
1213 templ2->Set("b", templ1);
1214 Local<v8::Object> instance2 = templ2->NewInstance();
1215 env->Global()->Set(v8_str("q"), instance2);
1216 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1217 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1218 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1219 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1220}
1221
1222
1223static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
1224 ApiTestFuzzer::Fuzz();
1225 return v8_num(17.2);
1226}
1227
1228
1229static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
1230 ApiTestFuzzer::Fuzz();
1231 return v8_num(15.2);
1232}
1233
1234
1235THREADED_TEST(DescriptorInheritance) {
1236 v8::HandleScope scope;
1237 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
1238 super->PrototypeTemplate()->Set("flabby",
1239 v8::FunctionTemplate::New(GetFlabby));
1240 super->PrototypeTemplate()->Set("PI", v8_num(3.14));
1241
1242 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1243
1244 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
1245 base1->Inherit(super);
1246 base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
1247
1248 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
1249 base2->Inherit(super);
1250 base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
1251
1252 LocalContext env;
1253
1254 env->Global()->Set(v8_str("s"), super->GetFunction());
1255 env->Global()->Set(v8_str("base1"), base1->GetFunction());
1256 env->Global()->Set(v8_str("base2"), base2->GetFunction());
1257
1258 // Checks right __proto__ chain.
1259 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1260 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1261
1262 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1263
1264 // Instance accessor should not be visible on function object or its prototype
1265 CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1266 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1267 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1268
1269 env->Global()->Set(v8_str("obj"),
1270 base1->GetFunction()->NewInstance());
1271 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1272 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1273 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1274 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1275 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1276
1277 env->Global()->Set(v8_str("obj2"),
1278 base2->GetFunction()->NewInstance());
1279 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1280 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1281 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1282 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1283 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1284
1285 // base1 and base2 cannot cross reference to each's prototype
1286 CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1287 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1288}
1289
1290
1291int echo_named_call_count;
1292
1293
1294static v8::Handle<Value> EchoNamedProperty(Local<String> name,
1295 const AccessorInfo& info) {
1296 ApiTestFuzzer::Fuzz();
1297 CHECK_EQ(v8_str("data"), info.Data());
1298 echo_named_call_count++;
1299 return name;
1300}
1301
1302
1303THREADED_TEST(NamedPropertyHandlerGetter) {
1304 echo_named_call_count = 0;
1305 v8::HandleScope scope;
1306 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1307 templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
1308 0, 0, 0, 0,
1309 v8_str("data"));
1310 LocalContext env;
1311 env->Global()->Set(v8_str("obj"),
1312 templ->GetFunction()->NewInstance());
1313 CHECK_EQ(echo_named_call_count, 0);
1314 v8_compile("obj.x")->Run();
1315 CHECK_EQ(echo_named_call_count, 1);
1316 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
1317 v8::Handle<Value> str = CompileRun(code);
1318 String::AsciiValue value(str);
1319 CHECK_EQ(*value, "oddlepoddle");
1320 // Check default behavior
1321 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
1322 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
1323 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
1324}
1325
1326
1327int echo_indexed_call_count = 0;
1328
1329
1330static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
1331 const AccessorInfo& info) {
1332 ApiTestFuzzer::Fuzz();
1333 CHECK_EQ(v8_num(637), info.Data());
1334 echo_indexed_call_count++;
1335 return v8_num(index);
1336}
1337
1338
1339THREADED_TEST(IndexedPropertyHandlerGetter) {
1340 v8::HandleScope scope;
1341 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1342 templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
1343 0, 0, 0, 0,
1344 v8_num(637));
1345 LocalContext env;
1346 env->Global()->Set(v8_str("obj"),
1347 templ->GetFunction()->NewInstance());
1348 Local<Script> script = v8_compile("obj[900]");
1349 CHECK_EQ(script->Run()->Int32Value(), 900);
1350}
1351
1352
1353v8::Handle<v8::Object> bottom;
1354
1355static v8::Handle<Value> CheckThisIndexedPropertyHandler(
1356 uint32_t index,
1357 const AccessorInfo& info) {
1358 ApiTestFuzzer::Fuzz();
1359 CHECK(info.This()->Equals(bottom));
1360 return v8::Handle<Value>();
1361}
1362
1363static v8::Handle<Value> CheckThisNamedPropertyHandler(
1364 Local<String> name,
1365 const AccessorInfo& info) {
1366 ApiTestFuzzer::Fuzz();
1367 CHECK(info.This()->Equals(bottom));
1368 return v8::Handle<Value>();
1369}
1370
1371
1372v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
1373 Local<Value> value,
1374 const AccessorInfo& info) {
1375 ApiTestFuzzer::Fuzz();
1376 CHECK(info.This()->Equals(bottom));
1377 return v8::Handle<Value>();
1378}
1379
1380
1381v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
1382 Local<Value> value,
1383 const AccessorInfo& info) {
1384 ApiTestFuzzer::Fuzz();
1385 CHECK(info.This()->Equals(bottom));
1386 return v8::Handle<Value>();
1387}
1388
Iain Merrick75681382010-08-19 15:07:18 +01001389v8::Handle<v8::Integer> CheckThisIndexedPropertyQuery(
Steve Blocka7e24c12009-10-30 11:49:00 +00001390 uint32_t index,
1391 const AccessorInfo& info) {
1392 ApiTestFuzzer::Fuzz();
1393 CHECK(info.This()->Equals(bottom));
Iain Merrick75681382010-08-19 15:07:18 +01001394 return v8::Handle<v8::Integer>();
Steve Blocka7e24c12009-10-30 11:49:00 +00001395}
1396
1397
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001398v8::Handle<v8::Integer> CheckThisNamedPropertyQuery(Local<String> property,
Steve Blocka7e24c12009-10-30 11:49:00 +00001399 const AccessorInfo& info) {
1400 ApiTestFuzzer::Fuzz();
1401 CHECK(info.This()->Equals(bottom));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001402 return v8::Handle<v8::Integer>();
Steve Blocka7e24c12009-10-30 11:49:00 +00001403}
1404
1405
1406v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
1407 uint32_t index,
1408 const AccessorInfo& info) {
1409 ApiTestFuzzer::Fuzz();
1410 CHECK(info.This()->Equals(bottom));
1411 return v8::Handle<v8::Boolean>();
1412}
1413
1414
1415v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
1416 Local<String> property,
1417 const AccessorInfo& info) {
1418 ApiTestFuzzer::Fuzz();
1419 CHECK(info.This()->Equals(bottom));
1420 return v8::Handle<v8::Boolean>();
1421}
1422
1423
1424v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
1425 const AccessorInfo& info) {
1426 ApiTestFuzzer::Fuzz();
1427 CHECK(info.This()->Equals(bottom));
1428 return v8::Handle<v8::Array>();
1429}
1430
1431
1432v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
1433 const AccessorInfo& info) {
1434 ApiTestFuzzer::Fuzz();
1435 CHECK(info.This()->Equals(bottom));
1436 return v8::Handle<v8::Array>();
1437}
1438
1439
1440THREADED_TEST(PropertyHandlerInPrototype) {
1441 v8::HandleScope scope;
1442 LocalContext env;
1443
1444 // Set up a prototype chain with three interceptors.
1445 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1446 templ->InstanceTemplate()->SetIndexedPropertyHandler(
1447 CheckThisIndexedPropertyHandler,
1448 CheckThisIndexedPropertySetter,
1449 CheckThisIndexedPropertyQuery,
1450 CheckThisIndexedPropertyDeleter,
1451 CheckThisIndexedPropertyEnumerator);
1452
1453 templ->InstanceTemplate()->SetNamedPropertyHandler(
1454 CheckThisNamedPropertyHandler,
1455 CheckThisNamedPropertySetter,
1456 CheckThisNamedPropertyQuery,
1457 CheckThisNamedPropertyDeleter,
1458 CheckThisNamedPropertyEnumerator);
1459
1460 bottom = templ->GetFunction()->NewInstance();
1461 Local<v8::Object> top = templ->GetFunction()->NewInstance();
1462 Local<v8::Object> middle = templ->GetFunction()->NewInstance();
1463
1464 bottom->Set(v8_str("__proto__"), middle);
1465 middle->Set(v8_str("__proto__"), top);
1466 env->Global()->Set(v8_str("obj"), bottom);
1467
1468 // Indexed and named get.
1469 Script::Compile(v8_str("obj[0]"))->Run();
1470 Script::Compile(v8_str("obj.x"))->Run();
1471
1472 // Indexed and named set.
1473 Script::Compile(v8_str("obj[1] = 42"))->Run();
1474 Script::Compile(v8_str("obj.y = 42"))->Run();
1475
1476 // Indexed and named query.
1477 Script::Compile(v8_str("0 in obj"))->Run();
1478 Script::Compile(v8_str("'x' in obj"))->Run();
1479
1480 // Indexed and named deleter.
1481 Script::Compile(v8_str("delete obj[0]"))->Run();
1482 Script::Compile(v8_str("delete obj.x"))->Run();
1483
1484 // Enumerators.
1485 Script::Compile(v8_str("for (var p in obj) ;"))->Run();
1486}
1487
1488
1489static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
1490 const AccessorInfo& info) {
1491 ApiTestFuzzer::Fuzz();
1492 if (v8_str("pre")->Equals(key)) {
1493 return v8_str("PrePropertyHandler: pre");
1494 }
1495 return v8::Handle<String>();
1496}
1497
1498
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001499static v8::Handle<v8::Integer> PrePropertyHandlerQuery(Local<String> key,
1500 const AccessorInfo&) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001501 if (v8_str("pre")->Equals(key)) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001502 return v8::Integer::New(v8::None);
Steve Blocka7e24c12009-10-30 11:49:00 +00001503 }
1504
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001505 return v8::Handle<v8::Integer>(); // do not intercept the call
Steve Blocka7e24c12009-10-30 11:49:00 +00001506}
1507
1508
1509THREADED_TEST(PrePropertyHandler) {
1510 v8::HandleScope scope;
1511 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
1512 desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
1513 0,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001514 PrePropertyHandlerQuery);
Steve Blocka7e24c12009-10-30 11:49:00 +00001515 LocalContext env(NULL, desc->InstanceTemplate());
1516 Script::Compile(v8_str(
1517 "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
1518 v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
1519 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
1520 v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
1521 CHECK_EQ(v8_str("Object: on"), result_on);
1522 v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
1523 CHECK(result_post.IsEmpty());
1524}
1525
1526
1527THREADED_TEST(UndefinedIsNotEnumerable) {
1528 v8::HandleScope scope;
1529 LocalContext env;
1530 v8::Handle<Value> result = Script::Compile(v8_str(
1531 "this.propertyIsEnumerable(undefined)"))->Run();
1532 CHECK(result->IsFalse());
1533}
1534
1535
1536v8::Handle<Script> call_recursively_script;
Leon Clarke4515c472010-02-03 11:58:03 +00001537static const int kTargetRecursionDepth = 200; // near maximum
Steve Blocka7e24c12009-10-30 11:49:00 +00001538
1539
1540static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
1541 ApiTestFuzzer::Fuzz();
1542 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1543 if (depth == kTargetRecursionDepth) return v8::Undefined();
1544 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1545 return call_recursively_script->Run();
1546}
1547
1548
1549static v8::Handle<Value> CallFunctionRecursivelyCall(
1550 const v8::Arguments& args) {
1551 ApiTestFuzzer::Fuzz();
1552 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1553 if (depth == kTargetRecursionDepth) {
1554 printf("[depth = %d]\n", depth);
1555 return v8::Undefined();
1556 }
1557 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1558 v8::Handle<Value> function =
1559 args.This()->Get(v8_str("callFunctionRecursively"));
Steve Block6ded16b2010-05-10 14:33:55 +01001560 return function.As<Function>()->Call(args.This(), 0, NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001561}
1562
1563
1564THREADED_TEST(DeepCrossLanguageRecursion) {
1565 v8::HandleScope scope;
1566 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
1567 global->Set(v8_str("callScriptRecursively"),
1568 v8::FunctionTemplate::New(CallScriptRecursivelyCall));
1569 global->Set(v8_str("callFunctionRecursively"),
1570 v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
1571 LocalContext env(NULL, global);
1572
1573 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1574 call_recursively_script = v8_compile("callScriptRecursively()");
1575 v8::Handle<Value> result = call_recursively_script->Run();
1576 call_recursively_script = v8::Handle<Script>();
1577
1578 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1579 Script::Compile(v8_str("callFunctionRecursively()"))->Run();
1580}
1581
1582
1583static v8::Handle<Value>
1584 ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1585 ApiTestFuzzer::Fuzz();
1586 return v8::ThrowException(key);
1587}
1588
1589
1590static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
1591 Local<Value>,
1592 const AccessorInfo&) {
1593 v8::ThrowException(key);
1594 return v8::Undefined(); // not the same as v8::Handle<v8::Value>()
1595}
1596
1597
1598THREADED_TEST(CallbackExceptionRegression) {
1599 v8::HandleScope scope;
1600 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1601 obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
1602 ThrowingPropertyHandlerSet);
1603 LocalContext env;
1604 env->Global()->Set(v8_str("obj"), obj->NewInstance());
1605 v8::Handle<Value> otto = Script::Compile(v8_str(
1606 "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
1607 CHECK_EQ(v8_str("otto"), otto);
1608 v8::Handle<Value> netto = Script::Compile(v8_str(
1609 "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
1610 CHECK_EQ(v8_str("netto"), netto);
1611}
1612
1613
Steve Blocka7e24c12009-10-30 11:49:00 +00001614THREADED_TEST(FunctionPrototype) {
1615 v8::HandleScope scope;
1616 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
1617 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
1618 LocalContext env;
1619 env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
1620 Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
1621 CHECK_EQ(script->Run()->Int32Value(), 321);
1622}
1623
1624
1625THREADED_TEST(InternalFields) {
1626 v8::HandleScope scope;
1627 LocalContext env;
1628
1629 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1630 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1631 instance_templ->SetInternalFieldCount(1);
1632 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1633 CHECK_EQ(1, obj->InternalFieldCount());
1634 CHECK(obj->GetInternalField(0)->IsUndefined());
1635 obj->SetInternalField(0, v8_num(17));
1636 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
1637}
1638
1639
Steve Block6ded16b2010-05-10 14:33:55 +01001640THREADED_TEST(GlobalObjectInternalFields) {
1641 v8::HandleScope scope;
1642 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
1643 global_template->SetInternalFieldCount(1);
1644 LocalContext env(NULL, global_template);
1645 v8::Handle<v8::Object> global_proxy = env->Global();
1646 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
1647 CHECK_EQ(1, global->InternalFieldCount());
1648 CHECK(global->GetInternalField(0)->IsUndefined());
1649 global->SetInternalField(0, v8_num(17));
1650 CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
1651}
1652
1653
Steve Blocka7e24c12009-10-30 11:49:00 +00001654THREADED_TEST(InternalFieldsNativePointers) {
1655 v8::HandleScope scope;
1656 LocalContext env;
1657
1658 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1659 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1660 instance_templ->SetInternalFieldCount(1);
1661 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1662 CHECK_EQ(1, obj->InternalFieldCount());
1663 CHECK(obj->GetPointerFromInternalField(0) == NULL);
1664
1665 char* data = new char[100];
1666
1667 void* aligned = data;
Ben Murdochf87a2032010-10-22 12:50:53 +01001668 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
Steve Blocka7e24c12009-10-30 11:49:00 +00001669 void* unaligned = data + 1;
Ben Murdochf87a2032010-10-22 12:50:53 +01001670 CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
Steve Blocka7e24c12009-10-30 11:49:00 +00001671
1672 // Check reading and writing aligned pointers.
1673 obj->SetPointerInInternalField(0, aligned);
Steve Block44f0eee2011-05-26 01:26:41 +01001674 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +00001675 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1676
1677 // Check reading and writing unaligned pointers.
1678 obj->SetPointerInInternalField(0, unaligned);
Steve Block44f0eee2011-05-26 01:26:41 +01001679 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +00001680 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1681
1682 delete[] data;
1683}
1684
1685
Steve Block3ce2e202009-11-05 08:53:23 +00001686THREADED_TEST(InternalFieldsNativePointersAndExternal) {
1687 v8::HandleScope scope;
1688 LocalContext env;
1689
1690 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1691 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1692 instance_templ->SetInternalFieldCount(1);
1693 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1694 CHECK_EQ(1, obj->InternalFieldCount());
1695 CHECK(obj->GetPointerFromInternalField(0) == NULL);
1696
1697 char* data = new char[100];
1698
1699 void* aligned = data;
Ben Murdochf87a2032010-10-22 12:50:53 +01001700 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
Steve Block3ce2e202009-11-05 08:53:23 +00001701 void* unaligned = data + 1;
Ben Murdochf87a2032010-10-22 12:50:53 +01001702 CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
Steve Block3ce2e202009-11-05 08:53:23 +00001703
1704 obj->SetPointerInInternalField(0, aligned);
Steve Block44f0eee2011-05-26 01:26:41 +01001705 HEAP->CollectAllGarbage(false);
Steve Block3ce2e202009-11-05 08:53:23 +00001706 CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0)));
1707
1708 obj->SetPointerInInternalField(0, unaligned);
Steve Block44f0eee2011-05-26 01:26:41 +01001709 HEAP->CollectAllGarbage(false);
Steve Block3ce2e202009-11-05 08:53:23 +00001710 CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0)));
1711
1712 obj->SetInternalField(0, v8::External::Wrap(aligned));
Steve Block44f0eee2011-05-26 01:26:41 +01001713 HEAP->CollectAllGarbage(false);
Steve Block3ce2e202009-11-05 08:53:23 +00001714 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1715
1716 obj->SetInternalField(0, v8::External::Wrap(unaligned));
Steve Block44f0eee2011-05-26 01:26:41 +01001717 HEAP->CollectAllGarbage(false);
Steve Block3ce2e202009-11-05 08:53:23 +00001718 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1719
1720 delete[] data;
1721}
1722
1723
Steve Blocka7e24c12009-10-30 11:49:00 +00001724THREADED_TEST(IdentityHash) {
1725 v8::HandleScope scope;
1726 LocalContext env;
1727
1728 // Ensure that the test starts with an fresh heap to test whether the hash
1729 // code is based on the address.
Steve Block44f0eee2011-05-26 01:26:41 +01001730 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +00001731 Local<v8::Object> obj = v8::Object::New();
1732 int hash = obj->GetIdentityHash();
1733 int hash1 = obj->GetIdentityHash();
1734 CHECK_EQ(hash, hash1);
1735 int hash2 = v8::Object::New()->GetIdentityHash();
1736 // Since the identity hash is essentially a random number two consecutive
1737 // objects should not be assigned the same hash code. If the test below fails
1738 // the random number generator should be evaluated.
1739 CHECK_NE(hash, hash2);
Steve Block44f0eee2011-05-26 01:26:41 +01001740 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +00001741 int hash3 = v8::Object::New()->GetIdentityHash();
1742 // Make sure that the identity hash is not based on the initial address of
1743 // the object alone. If the test below fails the random number generator
1744 // should be evaluated.
1745 CHECK_NE(hash, hash3);
1746 int hash4 = obj->GetIdentityHash();
1747 CHECK_EQ(hash, hash4);
Steve Block1e0659c2011-05-24 12:43:12 +01001748
1749 // Check identity hashes behaviour in the presence of JS accessors.
1750 // Put a getter for 'v8::IdentityHash' on the Object's prototype:
1751 {
1752 CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
1753 Local<v8::Object> o1 = v8::Object::New();
1754 Local<v8::Object> o2 = v8::Object::New();
1755 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
1756 }
1757 {
1758 CompileRun(
1759 "function cnst() { return 42; };\n"
1760 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
1761 Local<v8::Object> o1 = v8::Object::New();
1762 Local<v8::Object> o2 = v8::Object::New();
1763 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
1764 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001765}
1766
1767
1768THREADED_TEST(HiddenProperties) {
1769 v8::HandleScope scope;
1770 LocalContext env;
1771
1772 v8::Local<v8::Object> obj = v8::Object::New();
1773 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1774 v8::Local<v8::String> empty = v8_str("");
1775 v8::Local<v8::String> prop_name = v8_str("prop_name");
1776
Steve Block44f0eee2011-05-26 01:26:41 +01001777 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +00001778
1779 // Make sure delete of a non-existent hidden value works
1780 CHECK(obj->DeleteHiddenValue(key));
1781
1782 CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
1783 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
1784 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
1785 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1786
Steve Block44f0eee2011-05-26 01:26:41 +01001787 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +00001788
1789 // Make sure we do not find the hidden property.
1790 CHECK(!obj->Has(empty));
1791 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1792 CHECK(obj->Get(empty)->IsUndefined());
1793 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1794 CHECK(obj->Set(empty, v8::Integer::New(2003)));
1795 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1796 CHECK_EQ(2003, obj->Get(empty)->Int32Value());
1797
Steve Block44f0eee2011-05-26 01:26:41 +01001798 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +00001799
1800 // Add another property and delete it afterwards to force the object in
1801 // slow case.
1802 CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
1803 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1804 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
1805 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1806 CHECK(obj->Delete(prop_name));
1807 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1808
Steve Block44f0eee2011-05-26 01:26:41 +01001809 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +00001810
1811 CHECK(obj->DeleteHiddenValue(key));
1812 CHECK(obj->GetHiddenValue(key).IsEmpty());
1813}
1814
1815
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001816THREADED_TEST(Regress97784) {
1817 // Regression test for crbug.com/97784
1818 // Messing with the Object.prototype should not have effect on
1819 // hidden properties.
1820 v8::HandleScope scope;
1821 LocalContext env;
1822
1823 v8::Local<v8::Object> obj = v8::Object::New();
1824 v8::Local<v8::String> key = v8_str("hidden");
1825
1826 CompileRun(
1827 "set_called = false;"
1828 "Object.defineProperty("
1829 " Object.prototype,"
1830 " 'hidden',"
1831 " {get: function() { return 45; },"
1832 " set: function() { set_called = true; }})");
1833
1834 CHECK(obj->GetHiddenValue(key).IsEmpty());
1835 // Make sure that the getter and setter from Object.prototype is not invoked.
1836 // If it did we would have full access to the hidden properties in
1837 // the accessor.
1838 CHECK(obj->SetHiddenValue(key, v8::Integer::New(42)));
1839 ExpectFalse("set_called");
1840 CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
1841}
1842
1843
Steve Blockd0582a62009-12-15 09:54:21 +00001844static bool interceptor_for_hidden_properties_called;
Steve Blocka7e24c12009-10-30 11:49:00 +00001845static v8::Handle<Value> InterceptorForHiddenProperties(
1846 Local<String> name, const AccessorInfo& info) {
Steve Blockd0582a62009-12-15 09:54:21 +00001847 interceptor_for_hidden_properties_called = true;
Steve Blocka7e24c12009-10-30 11:49:00 +00001848 return v8::Handle<Value>();
1849}
1850
1851
1852THREADED_TEST(HiddenPropertiesWithInterceptors) {
1853 v8::HandleScope scope;
1854 LocalContext context;
1855
Steve Blockd0582a62009-12-15 09:54:21 +00001856 interceptor_for_hidden_properties_called = false;
1857
Steve Blocka7e24c12009-10-30 11:49:00 +00001858 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1859
1860 // Associate an interceptor with an object and start setting hidden values.
1861 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
1862 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
1863 instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
1864 Local<v8::Function> function = fun_templ->GetFunction();
1865 Local<v8::Object> obj = function->NewInstance();
1866 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
1867 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
Steve Blockd0582a62009-12-15 09:54:21 +00001868 CHECK(!interceptor_for_hidden_properties_called);
Steve Blocka7e24c12009-10-30 11:49:00 +00001869}
1870
1871
1872THREADED_TEST(External) {
1873 v8::HandleScope scope;
1874 int x = 3;
1875 Local<v8::External> ext = v8::External::New(&x);
1876 LocalContext env;
1877 env->Global()->Set(v8_str("ext"), ext);
1878 Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
Steve Block6ded16b2010-05-10 14:33:55 +01001879 v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
Steve Blocka7e24c12009-10-30 11:49:00 +00001880 int* ptr = static_cast<int*>(reext->Value());
1881 CHECK_EQ(x, 3);
1882 *ptr = 10;
1883 CHECK_EQ(x, 10);
1884
1885 // Make sure unaligned pointers are wrapped properly.
1886 char* data = i::StrDup("0123456789");
1887 Local<v8::Value> zero = v8::External::Wrap(&data[0]);
1888 Local<v8::Value> one = v8::External::Wrap(&data[1]);
1889 Local<v8::Value> two = v8::External::Wrap(&data[2]);
1890 Local<v8::Value> three = v8::External::Wrap(&data[3]);
1891
1892 char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero));
1893 CHECK_EQ('0', *char_ptr);
1894 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one));
1895 CHECK_EQ('1', *char_ptr);
1896 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two));
1897 CHECK_EQ('2', *char_ptr);
1898 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three));
1899 CHECK_EQ('3', *char_ptr);
1900 i::DeleteArray(data);
1901}
1902
1903
1904THREADED_TEST(GlobalHandle) {
1905 v8::Persistent<String> global;
1906 {
1907 v8::HandleScope scope;
1908 Local<String> str = v8_str("str");
1909 global = v8::Persistent<String>::New(str);
1910 }
1911 CHECK_EQ(global->Length(), 3);
1912 global.Dispose();
1913}
1914
1915
Steve Block44f0eee2011-05-26 01:26:41 +01001916static int NumberOfWeakCalls = 0;
1917static void WeakPointerCallback(Persistent<Value> handle, void* id) {
1918 CHECK_EQ(reinterpret_cast<void*>(1234), id);
1919 NumberOfWeakCalls++;
1920 handle.Dispose();
1921}
1922
1923THREADED_TEST(ApiObjectGroups) {
1924 HandleScope scope;
1925 LocalContext env;
1926
1927 NumberOfWeakCalls = 0;
1928
1929 Persistent<Object> g1s1;
1930 Persistent<Object> g1s2;
1931 Persistent<Object> g1c1;
1932 Persistent<Object> g2s1;
1933 Persistent<Object> g2s2;
1934 Persistent<Object> g2c1;
1935
1936 {
1937 HandleScope scope;
1938 g1s1 = Persistent<Object>::New(Object::New());
1939 g1s2 = Persistent<Object>::New(Object::New());
1940 g1c1 = Persistent<Object>::New(Object::New());
1941 g1s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1942 g1s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1943 g1c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1944
1945 g2s1 = Persistent<Object>::New(Object::New());
1946 g2s2 = Persistent<Object>::New(Object::New());
1947 g2c1 = Persistent<Object>::New(Object::New());
1948 g2s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1949 g2s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1950 g2c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1951 }
1952
1953 Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
1954
1955 // Connect group 1 and 2, make a cycle.
1956 CHECK(g1s2->Set(0, g2s2));
1957 CHECK(g2s1->Set(0, g1s1));
1958
1959 {
1960 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
1961 Persistent<Value> g1_children[] = { g1c1 };
1962 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
1963 Persistent<Value> g2_children[] = { g2c1 };
1964 V8::AddObjectGroup(g1_objects, 2);
1965 V8::AddImplicitReferences(g1s1, g1_children, 1);
1966 V8::AddObjectGroup(g2_objects, 2);
1967 V8::AddImplicitReferences(g2s2, g2_children, 1);
1968 }
1969 // Do a full GC
1970 HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
1971
1972 // All object should be alive.
1973 CHECK_EQ(0, NumberOfWeakCalls);
1974
1975 // Weaken the root.
1976 root.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1977 // But make children strong roots---all the objects (except for children)
1978 // should be collectable now.
1979 g1c1.ClearWeak();
1980 g2c1.ClearWeak();
1981
1982 // Groups are deleted, rebuild groups.
1983 {
1984 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
1985 Persistent<Value> g1_children[] = { g1c1 };
1986 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
1987 Persistent<Value> g2_children[] = { g2c1 };
1988 V8::AddObjectGroup(g1_objects, 2);
1989 V8::AddImplicitReferences(g1s1, g1_children, 1);
1990 V8::AddObjectGroup(g2_objects, 2);
1991 V8::AddImplicitReferences(g2s2, g2_children, 1);
1992 }
1993
1994 HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
1995
1996 // All objects should be gone. 5 global handles in total.
1997 CHECK_EQ(5, NumberOfWeakCalls);
1998
1999 // And now make children weak again and collect them.
2000 g1c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
2001 g2c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
2002
2003 HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
2004 CHECK_EQ(7, NumberOfWeakCalls);
2005}
2006
2007
2008THREADED_TEST(ApiObjectGroupsCycle) {
2009 HandleScope scope;
2010 LocalContext env;
2011
2012 NumberOfWeakCalls = 0;
2013
2014 Persistent<Object> g1s1;
2015 Persistent<Object> g1s2;
2016 Persistent<Object> g2s1;
2017 Persistent<Object> g2s2;
2018 Persistent<Object> g3s1;
2019 Persistent<Object> g3s2;
2020
2021 {
2022 HandleScope scope;
2023 g1s1 = Persistent<Object>::New(Object::New());
2024 g1s2 = Persistent<Object>::New(Object::New());
2025 g1s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
2026 g1s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
2027
2028 g2s1 = Persistent<Object>::New(Object::New());
2029 g2s2 = Persistent<Object>::New(Object::New());
2030 g2s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
2031 g2s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
2032
2033 g3s1 = Persistent<Object>::New(Object::New());
2034 g3s2 = Persistent<Object>::New(Object::New());
2035 g3s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
2036 g3s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
2037 }
2038
2039 Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
2040
2041 // Connect groups. We're building the following cycle:
2042 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
2043 // groups.
2044 {
2045 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2046 Persistent<Value> g1_children[] = { g2s1 };
2047 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2048 Persistent<Value> g2_children[] = { g3s1 };
2049 Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2050 Persistent<Value> g3_children[] = { g1s1 };
2051 V8::AddObjectGroup(g1_objects, 2);
2052 V8::AddImplicitReferences(g1s1, g1_children, 1);
2053 V8::AddObjectGroup(g2_objects, 2);
2054 V8::AddImplicitReferences(g2s1, g2_children, 1);
2055 V8::AddObjectGroup(g3_objects, 2);
2056 V8::AddImplicitReferences(g3s1, g3_children, 1);
2057 }
2058 // Do a full GC
2059 HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
2060
2061 // All object should be alive.
2062 CHECK_EQ(0, NumberOfWeakCalls);
2063
2064 // Weaken the root.
2065 root.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
2066
2067 // Groups are deleted, rebuild groups.
2068 {
2069 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2070 Persistent<Value> g1_children[] = { g2s1 };
2071 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2072 Persistent<Value> g2_children[] = { g3s1 };
2073 Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2074 Persistent<Value> g3_children[] = { g1s1 };
2075 V8::AddObjectGroup(g1_objects, 2);
2076 V8::AddImplicitReferences(g1s1, g1_children, 1);
2077 V8::AddObjectGroup(g2_objects, 2);
2078 V8::AddImplicitReferences(g2s1, g2_children, 1);
2079 V8::AddObjectGroup(g3_objects, 2);
2080 V8::AddImplicitReferences(g3s1, g3_children, 1);
2081 }
2082
2083 HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
2084
2085 // All objects should be gone. 7 global handles in total.
2086 CHECK_EQ(7, NumberOfWeakCalls);
2087}
2088
2089
Steve Blocka7e24c12009-10-30 11:49:00 +00002090THREADED_TEST(ScriptException) {
2091 v8::HandleScope scope;
2092 LocalContext env;
2093 Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
2094 v8::TryCatch try_catch;
2095 Local<Value> result = script->Run();
2096 CHECK(result.IsEmpty());
2097 CHECK(try_catch.HasCaught());
2098 String::AsciiValue exception_value(try_catch.Exception());
2099 CHECK_EQ(*exception_value, "panama!");
2100}
2101
2102
2103bool message_received;
2104
2105
2106static void check_message(v8::Handle<v8::Message> message,
2107 v8::Handle<Value> data) {
2108 CHECK_EQ(5.76, data->NumberValue());
2109 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
2110 CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
2111 message_received = true;
2112}
2113
2114
2115THREADED_TEST(MessageHandlerData) {
2116 message_received = false;
2117 v8::HandleScope scope;
2118 CHECK(!message_received);
2119 v8::V8::AddMessageListener(check_message, v8_num(5.76));
2120 LocalContext context;
2121 v8::ScriptOrigin origin =
2122 v8::ScriptOrigin(v8_str("6.75"));
2123 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
2124 &origin);
2125 script->SetData(v8_str("7.56"));
2126 script->Run();
2127 CHECK(message_received);
2128 // clear out the message listener
2129 v8::V8::RemoveMessageListeners(check_message);
2130}
2131
2132
2133THREADED_TEST(GetSetProperty) {
2134 v8::HandleScope scope;
2135 LocalContext context;
2136 context->Global()->Set(v8_str("foo"), v8_num(14));
2137 context->Global()->Set(v8_str("12"), v8_num(92));
2138 context->Global()->Set(v8::Integer::New(16), v8_num(32));
2139 context->Global()->Set(v8_num(13), v8_num(56));
2140 Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
2141 CHECK_EQ(14, foo->Int32Value());
2142 Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
2143 CHECK_EQ(92, twelve->Int32Value());
2144 Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
2145 CHECK_EQ(32, sixteen->Int32Value());
2146 Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
2147 CHECK_EQ(56, thirteen->Int32Value());
2148 CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
2149 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
2150 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
2151 CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
2152 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
2153 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
2154 CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
2155 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
2156 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
2157}
2158
2159
2160THREADED_TEST(PropertyAttributes) {
2161 v8::HandleScope scope;
2162 LocalContext context;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002163 // none
2164 Local<String> prop = v8_str("none");
2165 context->Global()->Set(prop, v8_num(7));
2166 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
Steve Blocka7e24c12009-10-30 11:49:00 +00002167 // read-only
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002168 prop = v8_str("read_only");
Steve Blocka7e24c12009-10-30 11:49:00 +00002169 context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
2170 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002171 CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
Steve Blocka7e24c12009-10-30 11:49:00 +00002172 Script::Compile(v8_str("read_only = 9"))->Run();
2173 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2174 context->Global()->Set(prop, v8_num(10));
2175 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2176 // dont-delete
2177 prop = v8_str("dont_delete");
2178 context->Global()->Set(prop, v8_num(13), v8::DontDelete);
2179 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
2180 Script::Compile(v8_str("delete dont_delete"))->Run();
2181 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002182 CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
2183 // dont-enum
2184 prop = v8_str("dont_enum");
2185 context->Global()->Set(prop, v8_num(28), v8::DontEnum);
2186 CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
2187 // absent
2188 prop = v8_str("absent");
2189 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
2190 Local<Value> fake_prop = v8_num(1);
2191 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
2192 // exception
2193 TryCatch try_catch;
2194 Local<Value> exception =
2195 CompileRun("({ toString: function() { throw 'exception';} })");
2196 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
2197 CHECK(try_catch.HasCaught());
2198 String::AsciiValue exception_value(try_catch.Exception());
2199 CHECK_EQ("exception", *exception_value);
2200 try_catch.Reset();
Steve Blocka7e24c12009-10-30 11:49:00 +00002201}
2202
2203
2204THREADED_TEST(Array) {
2205 v8::HandleScope scope;
2206 LocalContext context;
2207 Local<v8::Array> array = v8::Array::New();
2208 CHECK_EQ(0, array->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01002209 CHECK(array->Get(0)->IsUndefined());
Steve Blocka7e24c12009-10-30 11:49:00 +00002210 CHECK(!array->Has(0));
Steve Block6ded16b2010-05-10 14:33:55 +01002211 CHECK(array->Get(100)->IsUndefined());
Steve Blocka7e24c12009-10-30 11:49:00 +00002212 CHECK(!array->Has(100));
Steve Block6ded16b2010-05-10 14:33:55 +01002213 array->Set(2, v8_num(7));
Steve Blocka7e24c12009-10-30 11:49:00 +00002214 CHECK_EQ(3, array->Length());
2215 CHECK(!array->Has(0));
2216 CHECK(!array->Has(1));
2217 CHECK(array->Has(2));
Steve Block6ded16b2010-05-10 14:33:55 +01002218 CHECK_EQ(7, array->Get(2)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00002219 Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
Steve Block6ded16b2010-05-10 14:33:55 +01002220 Local<v8::Array> arr = obj.As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00002221 CHECK_EQ(3, arr->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01002222 CHECK_EQ(1, arr->Get(0)->Int32Value());
2223 CHECK_EQ(2, arr->Get(1)->Int32Value());
2224 CHECK_EQ(3, arr->Get(2)->Int32Value());
Steve Block44f0eee2011-05-26 01:26:41 +01002225 array = v8::Array::New(27);
2226 CHECK_EQ(27, array->Length());
2227 array = v8::Array::New(-27);
2228 CHECK_EQ(0, array->Length());
Steve Blocka7e24c12009-10-30 11:49:00 +00002229}
2230
2231
2232v8::Handle<Value> HandleF(const v8::Arguments& args) {
2233 v8::HandleScope scope;
2234 ApiTestFuzzer::Fuzz();
2235 Local<v8::Array> result = v8::Array::New(args.Length());
2236 for (int i = 0; i < args.Length(); i++)
Steve Block6ded16b2010-05-10 14:33:55 +01002237 result->Set(i, args[i]);
Steve Blocka7e24c12009-10-30 11:49:00 +00002238 return scope.Close(result);
2239}
2240
2241
2242THREADED_TEST(Vector) {
2243 v8::HandleScope scope;
2244 Local<ObjectTemplate> global = ObjectTemplate::New();
2245 global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
2246 LocalContext context(0, global);
2247
2248 const char* fun = "f()";
Steve Block6ded16b2010-05-10 14:33:55 +01002249 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00002250 CHECK_EQ(0, a0->Length());
2251
2252 const char* fun2 = "f(11)";
Steve Block6ded16b2010-05-10 14:33:55 +01002253 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00002254 CHECK_EQ(1, a1->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01002255 CHECK_EQ(11, a1->Get(0)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00002256
2257 const char* fun3 = "f(12, 13)";
Steve Block6ded16b2010-05-10 14:33:55 +01002258 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00002259 CHECK_EQ(2, a2->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01002260 CHECK_EQ(12, a2->Get(0)->Int32Value());
2261 CHECK_EQ(13, a2->Get(1)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00002262
2263 const char* fun4 = "f(14, 15, 16)";
Steve Block6ded16b2010-05-10 14:33:55 +01002264 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00002265 CHECK_EQ(3, a3->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01002266 CHECK_EQ(14, a3->Get(0)->Int32Value());
2267 CHECK_EQ(15, a3->Get(1)->Int32Value());
2268 CHECK_EQ(16, a3->Get(2)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00002269
2270 const char* fun5 = "f(17, 18, 19, 20)";
Steve Block6ded16b2010-05-10 14:33:55 +01002271 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00002272 CHECK_EQ(4, a4->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01002273 CHECK_EQ(17, a4->Get(0)->Int32Value());
2274 CHECK_EQ(18, a4->Get(1)->Int32Value());
2275 CHECK_EQ(19, a4->Get(2)->Int32Value());
2276 CHECK_EQ(20, a4->Get(3)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00002277}
2278
2279
2280THREADED_TEST(FunctionCall) {
2281 v8::HandleScope scope;
2282 LocalContext context;
2283 CompileRun(
2284 "function Foo() {"
2285 " var result = [];"
2286 " for (var i = 0; i < arguments.length; i++) {"
2287 " result.push(arguments[i]);"
2288 " }"
2289 " return result;"
2290 "}");
2291 Local<Function> Foo =
2292 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2293
2294 v8::Handle<Value>* args0 = NULL;
2295 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
2296 CHECK_EQ(0, a0->Length());
2297
2298 v8::Handle<Value> args1[] = { v8_num(1.1) };
2299 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
2300 CHECK_EQ(1, a1->Length());
2301 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2302
2303 v8::Handle<Value> args2[] = { v8_num(2.2),
2304 v8_num(3.3) };
2305 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
2306 CHECK_EQ(2, a2->Length());
2307 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2308 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2309
2310 v8::Handle<Value> args3[] = { v8_num(4.4),
2311 v8_num(5.5),
2312 v8_num(6.6) };
2313 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
2314 CHECK_EQ(3, a3->Length());
2315 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2316 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2317 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2318
2319 v8::Handle<Value> args4[] = { v8_num(7.7),
2320 v8_num(8.8),
2321 v8_num(9.9),
2322 v8_num(10.11) };
2323 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
2324 CHECK_EQ(4, a4->Length());
2325 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2326 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2327 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2328 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2329}
2330
2331
2332static const char* js_code_causing_out_of_memory =
2333 "var a = new Array(); while(true) a.push(a);";
2334
2335
2336// These tests run for a long time and prevent us from running tests
2337// that come after them so they cannot run in parallel.
2338TEST(OutOfMemory) {
2339 // It's not possible to read a snapshot into a heap with different dimensions.
Steve Block8defd9f2010-07-08 12:39:36 +01002340 if (i::Snapshot::IsEnabled()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00002341 // Set heap limits.
2342 static const int K = 1024;
2343 v8::ResourceConstraints constraints;
2344 constraints.set_max_young_space_size(256 * K);
2345 constraints.set_max_old_space_size(4 * K * K);
2346 v8::SetResourceConstraints(&constraints);
2347
2348 // Execute a script that causes out of memory.
2349 v8::HandleScope scope;
2350 LocalContext context;
2351 v8::V8::IgnoreOutOfMemoryException();
2352 Local<Script> script =
2353 Script::Compile(String::New(js_code_causing_out_of_memory));
2354 Local<Value> result = script->Run();
2355
2356 // Check for out of memory state.
2357 CHECK(result.IsEmpty());
2358 CHECK(context->HasOutOfMemoryException());
2359}
2360
2361
2362v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
2363 ApiTestFuzzer::Fuzz();
2364
2365 v8::HandleScope scope;
2366 LocalContext context;
2367 Local<Script> script =
2368 Script::Compile(String::New(js_code_causing_out_of_memory));
2369 Local<Value> result = script->Run();
2370
2371 // Check for out of memory state.
2372 CHECK(result.IsEmpty());
2373 CHECK(context->HasOutOfMemoryException());
2374
2375 return result;
2376}
2377
2378
2379TEST(OutOfMemoryNested) {
2380 // It's not possible to read a snapshot into a heap with different dimensions.
Steve Block8defd9f2010-07-08 12:39:36 +01002381 if (i::Snapshot::IsEnabled()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00002382 // Set heap limits.
2383 static const int K = 1024;
2384 v8::ResourceConstraints constraints;
2385 constraints.set_max_young_space_size(256 * K);
2386 constraints.set_max_old_space_size(4 * K * K);
2387 v8::SetResourceConstraints(&constraints);
2388
2389 v8::HandleScope scope;
2390 Local<ObjectTemplate> templ = ObjectTemplate::New();
2391 templ->Set(v8_str("ProvokeOutOfMemory"),
2392 v8::FunctionTemplate::New(ProvokeOutOfMemory));
2393 LocalContext context(0, templ);
2394 v8::V8::IgnoreOutOfMemoryException();
2395 Local<Value> result = CompileRun(
2396 "var thrown = false;"
2397 "try {"
2398 " ProvokeOutOfMemory();"
2399 "} catch (e) {"
2400 " thrown = true;"
2401 "}");
2402 // Check for out of memory state.
2403 CHECK(result.IsEmpty());
2404 CHECK(context->HasOutOfMemoryException());
2405}
2406
2407
2408TEST(HugeConsStringOutOfMemory) {
2409 // It's not possible to read a snapshot into a heap with different dimensions.
Steve Block8defd9f2010-07-08 12:39:36 +01002410 if (i::Snapshot::IsEnabled()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00002411 // Set heap limits.
2412 static const int K = 1024;
2413 v8::ResourceConstraints constraints;
2414 constraints.set_max_young_space_size(256 * K);
2415 constraints.set_max_old_space_size(2 * K * K);
2416 v8::SetResourceConstraints(&constraints);
2417
2418 // Execute a script that causes out of memory.
2419 v8::V8::IgnoreOutOfMemoryException();
2420
Steve Block44f0eee2011-05-26 01:26:41 +01002421 v8::HandleScope scope;
2422 LocalContext context;
2423
Steve Blocka7e24c12009-10-30 11:49:00 +00002424 // Build huge string. This should fail with out of memory exception.
2425 Local<Value> result = CompileRun(
2426 "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
Steve Block3ce2e202009-11-05 08:53:23 +00002427 "for (var i = 0; i < 22; i++) { str = str + str; }");
Steve Blocka7e24c12009-10-30 11:49:00 +00002428
2429 // Check for out of memory state.
2430 CHECK(result.IsEmpty());
2431 CHECK(context->HasOutOfMemoryException());
2432}
2433
2434
2435THREADED_TEST(ConstructCall) {
2436 v8::HandleScope scope;
2437 LocalContext context;
2438 CompileRun(
2439 "function Foo() {"
2440 " var result = [];"
2441 " for (var i = 0; i < arguments.length; i++) {"
2442 " result.push(arguments[i]);"
2443 " }"
2444 " return result;"
2445 "}");
2446 Local<Function> Foo =
2447 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2448
2449 v8::Handle<Value>* args0 = NULL;
2450 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
2451 CHECK_EQ(0, a0->Length());
2452
2453 v8::Handle<Value> args1[] = { v8_num(1.1) };
2454 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
2455 CHECK_EQ(1, a1->Length());
2456 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2457
2458 v8::Handle<Value> args2[] = { v8_num(2.2),
2459 v8_num(3.3) };
2460 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
2461 CHECK_EQ(2, a2->Length());
2462 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2463 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2464
2465 v8::Handle<Value> args3[] = { v8_num(4.4),
2466 v8_num(5.5),
2467 v8_num(6.6) };
2468 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
2469 CHECK_EQ(3, a3->Length());
2470 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2471 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2472 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2473
2474 v8::Handle<Value> args4[] = { v8_num(7.7),
2475 v8_num(8.8),
2476 v8_num(9.9),
2477 v8_num(10.11) };
2478 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
2479 CHECK_EQ(4, a4->Length());
2480 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2481 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2482 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2483 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2484}
2485
2486
2487static void CheckUncle(v8::TryCatch* try_catch) {
2488 CHECK(try_catch->HasCaught());
2489 String::AsciiValue str_value(try_catch->Exception());
2490 CHECK_EQ(*str_value, "uncle?");
2491 try_catch->Reset();
2492}
2493
2494
Steve Block6ded16b2010-05-10 14:33:55 +01002495THREADED_TEST(ConversionNumber) {
2496 v8::HandleScope scope;
2497 LocalContext env;
2498 // Very large number.
2499 CompileRun("var obj = Math.pow(2,32) * 1237;");
2500 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2501 CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
2502 CHECK_EQ(0, obj->ToInt32()->Value());
2503 CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned.
2504 // Large number.
2505 CompileRun("var obj = -1234567890123;");
2506 obj = env->Global()->Get(v8_str("obj"));
2507 CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
2508 CHECK_EQ(-1912276171, obj->ToInt32()->Value());
2509 CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT
2510 // Small positive integer.
2511 CompileRun("var obj = 42;");
2512 obj = env->Global()->Get(v8_str("obj"));
2513 CHECK_EQ(42.0, obj->ToNumber()->Value());
2514 CHECK_EQ(42, obj->ToInt32()->Value());
2515 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
2516 // Negative integer.
2517 CompileRun("var obj = -37;");
2518 obj = env->Global()->Get(v8_str("obj"));
2519 CHECK_EQ(-37.0, obj->ToNumber()->Value());
2520 CHECK_EQ(-37, obj->ToInt32()->Value());
2521 CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT
2522 // Positive non-int32 integer.
2523 CompileRun("var obj = 0x81234567;");
2524 obj = env->Global()->Get(v8_str("obj"));
2525 CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
2526 CHECK_EQ(-2128394905, obj->ToInt32()->Value());
2527 CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT
2528 // Fraction.
2529 CompileRun("var obj = 42.3;");
2530 obj = env->Global()->Get(v8_str("obj"));
2531 CHECK_EQ(42.3, obj->ToNumber()->Value());
2532 CHECK_EQ(42, obj->ToInt32()->Value());
2533 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
2534 // Large negative fraction.
2535 CompileRun("var obj = -5726623061.75;");
2536 obj = env->Global()->Get(v8_str("obj"));
2537 CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
2538 CHECK_EQ(-1431655765, obj->ToInt32()->Value());
2539 CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT
2540}
2541
2542
2543THREADED_TEST(isNumberType) {
2544 v8::HandleScope scope;
2545 LocalContext env;
2546 // Very large number.
2547 CompileRun("var obj = Math.pow(2,32) * 1237;");
2548 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2549 CHECK(!obj->IsInt32());
2550 CHECK(!obj->IsUint32());
2551 // Large negative number.
2552 CompileRun("var obj = -1234567890123;");
2553 obj = env->Global()->Get(v8_str("obj"));
2554 CHECK(!obj->IsInt32());
2555 CHECK(!obj->IsUint32());
2556 // Small positive integer.
2557 CompileRun("var obj = 42;");
2558 obj = env->Global()->Get(v8_str("obj"));
2559 CHECK(obj->IsInt32());
2560 CHECK(obj->IsUint32());
2561 // Negative integer.
2562 CompileRun("var obj = -37;");
2563 obj = env->Global()->Get(v8_str("obj"));
2564 CHECK(obj->IsInt32());
2565 CHECK(!obj->IsUint32());
2566 // Positive non-int32 integer.
2567 CompileRun("var obj = 0x81234567;");
2568 obj = env->Global()->Get(v8_str("obj"));
2569 CHECK(!obj->IsInt32());
2570 CHECK(obj->IsUint32());
2571 // Fraction.
2572 CompileRun("var obj = 42.3;");
2573 obj = env->Global()->Get(v8_str("obj"));
2574 CHECK(!obj->IsInt32());
2575 CHECK(!obj->IsUint32());
2576 // Large negative fraction.
2577 CompileRun("var obj = -5726623061.75;");
2578 obj = env->Global()->Get(v8_str("obj"));
2579 CHECK(!obj->IsInt32());
2580 CHECK(!obj->IsUint32());
2581}
2582
2583
Steve Blocka7e24c12009-10-30 11:49:00 +00002584THREADED_TEST(ConversionException) {
2585 v8::HandleScope scope;
2586 LocalContext env;
2587 CompileRun(
2588 "function TestClass() { };"
2589 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
2590 "var obj = new TestClass();");
2591 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2592
2593 v8::TryCatch try_catch;
2594
2595 Local<Value> to_string_result = obj->ToString();
2596 CHECK(to_string_result.IsEmpty());
2597 CheckUncle(&try_catch);
2598
2599 Local<Value> to_number_result = obj->ToNumber();
2600 CHECK(to_number_result.IsEmpty());
2601 CheckUncle(&try_catch);
2602
2603 Local<Value> to_integer_result = obj->ToInteger();
2604 CHECK(to_integer_result.IsEmpty());
2605 CheckUncle(&try_catch);
2606
2607 Local<Value> to_uint32_result = obj->ToUint32();
2608 CHECK(to_uint32_result.IsEmpty());
2609 CheckUncle(&try_catch);
2610
2611 Local<Value> to_int32_result = obj->ToInt32();
2612 CHECK(to_int32_result.IsEmpty());
2613 CheckUncle(&try_catch);
2614
2615 Local<Value> to_object_result = v8::Undefined()->ToObject();
2616 CHECK(to_object_result.IsEmpty());
2617 CHECK(try_catch.HasCaught());
2618 try_catch.Reset();
2619
2620 int32_t int32_value = obj->Int32Value();
2621 CHECK_EQ(0, int32_value);
2622 CheckUncle(&try_catch);
2623
2624 uint32_t uint32_value = obj->Uint32Value();
2625 CHECK_EQ(0, uint32_value);
2626 CheckUncle(&try_catch);
2627
2628 double number_value = obj->NumberValue();
2629 CHECK_NE(0, IsNaN(number_value));
2630 CheckUncle(&try_catch);
2631
2632 int64_t integer_value = obj->IntegerValue();
2633 CHECK_EQ(0.0, static_cast<double>(integer_value));
2634 CheckUncle(&try_catch);
2635}
2636
2637
2638v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
2639 ApiTestFuzzer::Fuzz();
2640 return v8::ThrowException(v8_str("konto"));
2641}
2642
2643
2644v8::Handle<Value> CCatcher(const v8::Arguments& args) {
2645 if (args.Length() < 1) return v8::Boolean::New(false);
2646 v8::HandleScope scope;
2647 v8::TryCatch try_catch;
2648 Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
2649 CHECK(!try_catch.HasCaught() || result.IsEmpty());
2650 return v8::Boolean::New(try_catch.HasCaught());
2651}
2652
2653
2654THREADED_TEST(APICatch) {
2655 v8::HandleScope scope;
2656 Local<ObjectTemplate> templ = ObjectTemplate::New();
2657 templ->Set(v8_str("ThrowFromC"),
2658 v8::FunctionTemplate::New(ThrowFromC));
2659 LocalContext context(0, templ);
2660 CompileRun(
2661 "var thrown = false;"
2662 "try {"
2663 " ThrowFromC();"
2664 "} catch (e) {"
2665 " thrown = true;"
2666 "}");
2667 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
2668 CHECK(thrown->BooleanValue());
2669}
2670
2671
2672THREADED_TEST(APIThrowTryCatch) {
2673 v8::HandleScope scope;
2674 Local<ObjectTemplate> templ = ObjectTemplate::New();
2675 templ->Set(v8_str("ThrowFromC"),
2676 v8::FunctionTemplate::New(ThrowFromC));
2677 LocalContext context(0, templ);
2678 v8::TryCatch try_catch;
2679 CompileRun("ThrowFromC();");
2680 CHECK(try_catch.HasCaught());
2681}
2682
2683
2684// Test that a try-finally block doesn't shadow a try-catch block
2685// when setting up an external handler.
2686//
2687// BUG(271): Some of the exception propagation does not work on the
2688// ARM simulator because the simulator separates the C++ stack and the
2689// JS stack. This test therefore fails on the simulator. The test is
2690// not threaded to allow the threading tests to run on the simulator.
2691TEST(TryCatchInTryFinally) {
2692 v8::HandleScope scope;
2693 Local<ObjectTemplate> templ = ObjectTemplate::New();
2694 templ->Set(v8_str("CCatcher"),
2695 v8::FunctionTemplate::New(CCatcher));
2696 LocalContext context(0, templ);
2697 Local<Value> result = CompileRun("try {"
2698 " try {"
2699 " CCatcher('throw 7;');"
2700 " } finally {"
2701 " }"
2702 "} catch (e) {"
2703 "}");
2704 CHECK(result->IsTrue());
2705}
2706
2707
Ben Murdochb8e0da22011-05-16 14:20:40 +01002708static void check_reference_error_message(
2709 v8::Handle<v8::Message> message,
2710 v8::Handle<v8::Value> data) {
2711 const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
2712 CHECK(message->Get()->Equals(v8_str(reference_error)));
2713}
2714
2715
Steve Block1e0659c2011-05-24 12:43:12 +01002716static v8::Handle<Value> Fail(const v8::Arguments& args) {
2717 ApiTestFuzzer::Fuzz();
2718 CHECK(false);
2719 return v8::Undefined();
2720}
2721
2722
2723// Test that overwritten methods are not invoked on uncaught exception
2724// formatting. However, they are invoked when performing normal error
2725// string conversions.
Ben Murdochb8e0da22011-05-16 14:20:40 +01002726TEST(APIThrowMessageOverwrittenToString) {
2727 v8::HandleScope scope;
2728 v8::V8::AddMessageListener(check_reference_error_message);
Steve Block1e0659c2011-05-24 12:43:12 +01002729 Local<ObjectTemplate> templ = ObjectTemplate::New();
2730 templ->Set(v8_str("fail"), v8::FunctionTemplate::New(Fail));
2731 LocalContext context(NULL, templ);
2732 CompileRun("asdf;");
2733 CompileRun("var limit = {};"
2734 "limit.valueOf = fail;"
2735 "Error.stackTraceLimit = limit;");
2736 CompileRun("asdf");
2737 CompileRun("Array.prototype.pop = fail;");
2738 CompileRun("Object.prototype.hasOwnProperty = fail;");
2739 CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
2740 CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
2741 CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
Ben Murdochb8e0da22011-05-16 14:20:40 +01002742 CompileRun("ReferenceError.prototype.toString ="
2743 " function() { return 'Whoops' }");
2744 CompileRun("asdf;");
Steve Block1e0659c2011-05-24 12:43:12 +01002745 CompileRun("ReferenceError.prototype.constructor.name = void 0;");
2746 CompileRun("asdf;");
2747 CompileRun("ReferenceError.prototype.constructor = void 0;");
2748 CompileRun("asdf;");
2749 CompileRun("ReferenceError.prototype.__proto__ = new Object();");
2750 CompileRun("asdf;");
2751 CompileRun("ReferenceError.prototype = new Object();");
2752 CompileRun("asdf;");
Ben Murdochb8e0da22011-05-16 14:20:40 +01002753 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
2754 CHECK(string->Equals(v8_str("Whoops")));
Steve Block1e0659c2011-05-24 12:43:12 +01002755 CompileRun("ReferenceError.prototype.constructor = new Object();"
2756 "ReferenceError.prototype.constructor.name = 1;"
2757 "Number.prototype.toString = function() { return 'Whoops'; };"
2758 "ReferenceError.prototype.toString = Object.prototype.toString;");
2759 CompileRun("asdf;");
Ben Murdochb8e0da22011-05-16 14:20:40 +01002760 v8::V8::RemoveMessageListeners(check_message);
2761}
2762
2763
Steve Blocka7e24c12009-10-30 11:49:00 +00002764static void receive_message(v8::Handle<v8::Message> message,
2765 v8::Handle<v8::Value> data) {
2766 message->Get();
2767 message_received = true;
2768}
2769
2770
2771TEST(APIThrowMessage) {
2772 message_received = false;
2773 v8::HandleScope scope;
2774 v8::V8::AddMessageListener(receive_message);
2775 Local<ObjectTemplate> templ = ObjectTemplate::New();
2776 templ->Set(v8_str("ThrowFromC"),
2777 v8::FunctionTemplate::New(ThrowFromC));
2778 LocalContext context(0, templ);
2779 CompileRun("ThrowFromC();");
2780 CHECK(message_received);
2781 v8::V8::RemoveMessageListeners(check_message);
2782}
2783
2784
2785TEST(APIThrowMessageAndVerboseTryCatch) {
2786 message_received = false;
2787 v8::HandleScope scope;
2788 v8::V8::AddMessageListener(receive_message);
2789 Local<ObjectTemplate> templ = ObjectTemplate::New();
2790 templ->Set(v8_str("ThrowFromC"),
2791 v8::FunctionTemplate::New(ThrowFromC));
2792 LocalContext context(0, templ);
2793 v8::TryCatch try_catch;
2794 try_catch.SetVerbose(true);
2795 Local<Value> result = CompileRun("ThrowFromC();");
2796 CHECK(try_catch.HasCaught());
2797 CHECK(result.IsEmpty());
2798 CHECK(message_received);
2799 v8::V8::RemoveMessageListeners(check_message);
2800}
2801
2802
Ben Murdoch8b112d22011-06-08 16:22:53 +01002803TEST(APIStackOverflowAndVerboseTryCatch) {
2804 message_received = false;
2805 v8::HandleScope scope;
2806 v8::V8::AddMessageListener(receive_message);
2807 LocalContext context;
2808 v8::TryCatch try_catch;
2809 try_catch.SetVerbose(true);
2810 Local<Value> result = CompileRun("function foo() { foo(); } foo();");
2811 CHECK(try_catch.HasCaught());
2812 CHECK(result.IsEmpty());
2813 CHECK(message_received);
2814 v8::V8::RemoveMessageListeners(receive_message);
2815}
2816
2817
Steve Blocka7e24c12009-10-30 11:49:00 +00002818THREADED_TEST(ExternalScriptException) {
2819 v8::HandleScope scope;
2820 Local<ObjectTemplate> templ = ObjectTemplate::New();
2821 templ->Set(v8_str("ThrowFromC"),
2822 v8::FunctionTemplate::New(ThrowFromC));
2823 LocalContext context(0, templ);
2824
2825 v8::TryCatch try_catch;
2826 Local<Script> script
2827 = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
2828 Local<Value> result = script->Run();
2829 CHECK(result.IsEmpty());
2830 CHECK(try_catch.HasCaught());
2831 String::AsciiValue exception_value(try_catch.Exception());
2832 CHECK_EQ("konto", *exception_value);
2833}
2834
2835
2836
2837v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
2838 ApiTestFuzzer::Fuzz();
2839 CHECK_EQ(4, args.Length());
2840 int count = args[0]->Int32Value();
2841 int cInterval = args[2]->Int32Value();
2842 if (count == 0) {
2843 return v8::ThrowException(v8_str("FromC"));
2844 } else {
2845 Local<v8::Object> global = Context::GetCurrent()->Global();
2846 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
2847 v8::Handle<Value> argv[] = { v8_num(count - 1),
2848 args[1],
2849 args[2],
2850 args[3] };
2851 if (count % cInterval == 0) {
2852 v8::TryCatch try_catch;
Steve Block6ded16b2010-05-10 14:33:55 +01002853 Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
Steve Blocka7e24c12009-10-30 11:49:00 +00002854 int expected = args[3]->Int32Value();
2855 if (try_catch.HasCaught()) {
2856 CHECK_EQ(expected, count);
2857 CHECK(result.IsEmpty());
Steve Block44f0eee2011-05-26 01:26:41 +01002858 CHECK(!i::Isolate::Current()->has_scheduled_exception());
Steve Blocka7e24c12009-10-30 11:49:00 +00002859 } else {
2860 CHECK_NE(expected, count);
2861 }
2862 return result;
2863 } else {
Steve Block6ded16b2010-05-10 14:33:55 +01002864 return fun.As<Function>()->Call(global, 4, argv);
Steve Blocka7e24c12009-10-30 11:49:00 +00002865 }
2866 }
2867}
2868
2869
2870v8::Handle<Value> JSCheck(const v8::Arguments& args) {
2871 ApiTestFuzzer::Fuzz();
2872 CHECK_EQ(3, args.Length());
2873 bool equality = args[0]->BooleanValue();
2874 int count = args[1]->Int32Value();
2875 int expected = args[2]->Int32Value();
2876 if (equality) {
2877 CHECK_EQ(count, expected);
2878 } else {
2879 CHECK_NE(count, expected);
2880 }
2881 return v8::Undefined();
2882}
2883
2884
2885THREADED_TEST(EvalInTryFinally) {
2886 v8::HandleScope scope;
2887 LocalContext context;
2888 v8::TryCatch try_catch;
2889 CompileRun("(function() {"
2890 " try {"
2891 " eval('asldkf (*&^&*^');"
2892 " } finally {"
2893 " return;"
2894 " }"
2895 "})()");
2896 CHECK(!try_catch.HasCaught());
2897}
2898
2899
2900// This test works by making a stack of alternating JavaScript and C
2901// activations. These activations set up exception handlers with regular
2902// intervals, one interval for C activations and another for JavaScript
2903// activations. When enough activations have been created an exception is
2904// thrown and we check that the right activation catches the exception and that
2905// no other activations do. The right activation is always the topmost one with
2906// a handler, regardless of whether it is in JavaScript or C.
2907//
2908// The notation used to describe a test case looks like this:
2909//
2910// *JS[4] *C[3] @JS[2] C[1] JS[0]
2911//
2912// Each entry is an activation, either JS or C. The index is the count at that
2913// level. Stars identify activations with exception handlers, the @ identifies
2914// the exception handler that should catch the exception.
2915//
2916// BUG(271): Some of the exception propagation does not work on the
2917// ARM simulator because the simulator separates the C++ stack and the
2918// JS stack. This test therefore fails on the simulator. The test is
2919// not threaded to allow the threading tests to run on the simulator.
2920TEST(ExceptionOrder) {
2921 v8::HandleScope scope;
2922 Local<ObjectTemplate> templ = ObjectTemplate::New();
2923 templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
2924 templ->Set(v8_str("CThrowCountDown"),
2925 v8::FunctionTemplate::New(CThrowCountDown));
2926 LocalContext context(0, templ);
2927 CompileRun(
2928 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
2929 " if (count == 0) throw 'FromJS';"
2930 " if (count % jsInterval == 0) {"
2931 " try {"
2932 " var value = CThrowCountDown(count - 1,"
2933 " jsInterval,"
2934 " cInterval,"
2935 " expected);"
2936 " check(false, count, expected);"
2937 " return value;"
2938 " } catch (e) {"
2939 " check(true, count, expected);"
2940 " }"
2941 " } else {"
2942 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
2943 " }"
2944 "}");
2945 Local<Function> fun =
2946 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
2947
2948 const int argc = 4;
2949 // count jsInterval cInterval expected
2950
2951 // *JS[4] *C[3] @JS[2] C[1] JS[0]
2952 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
2953 fun->Call(fun, argc, a0);
2954
2955 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
2956 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
2957 fun->Call(fun, argc, a1);
2958
2959 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
2960 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
2961 fun->Call(fun, argc, a2);
2962
2963 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
2964 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
2965 fun->Call(fun, argc, a3);
2966
2967 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
2968 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
2969 fun->Call(fun, argc, a4);
2970
2971 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
2972 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
2973 fun->Call(fun, argc, a5);
2974}
2975
2976
2977v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
2978 ApiTestFuzzer::Fuzz();
2979 CHECK_EQ(1, args.Length());
2980 return v8::ThrowException(args[0]);
2981}
2982
2983
2984THREADED_TEST(ThrowValues) {
2985 v8::HandleScope scope;
2986 Local<ObjectTemplate> templ = ObjectTemplate::New();
2987 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
2988 LocalContext context(0, templ);
2989 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
2990 "function Run(obj) {"
2991 " try {"
2992 " Throw(obj);"
2993 " } catch (e) {"
2994 " return e;"
2995 " }"
2996 " return 'no exception';"
2997 "}"
2998 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
2999 CHECK_EQ(5, result->Length());
3000 CHECK(result->Get(v8::Integer::New(0))->IsString());
3001 CHECK(result->Get(v8::Integer::New(1))->IsNumber());
3002 CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
3003 CHECK(result->Get(v8::Integer::New(2))->IsNumber());
3004 CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
3005 CHECK(result->Get(v8::Integer::New(3))->IsNull());
3006 CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
3007}
3008
3009
3010THREADED_TEST(CatchZero) {
3011 v8::HandleScope scope;
3012 LocalContext context;
3013 v8::TryCatch try_catch;
3014 CHECK(!try_catch.HasCaught());
3015 Script::Compile(v8_str("throw 10"))->Run();
3016 CHECK(try_catch.HasCaught());
3017 CHECK_EQ(10, try_catch.Exception()->Int32Value());
3018 try_catch.Reset();
3019 CHECK(!try_catch.HasCaught());
3020 Script::Compile(v8_str("throw 0"))->Run();
3021 CHECK(try_catch.HasCaught());
3022 CHECK_EQ(0, try_catch.Exception()->Int32Value());
3023}
3024
3025
3026THREADED_TEST(CatchExceptionFromWith) {
3027 v8::HandleScope scope;
3028 LocalContext context;
3029 v8::TryCatch try_catch;
3030 CHECK(!try_catch.HasCaught());
3031 Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
3032 CHECK(try_catch.HasCaught());
3033}
3034
3035
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003036THREADED_TEST(TryCatchAndFinallyHidingException) {
3037 v8::HandleScope scope;
3038 LocalContext context;
3039 v8::TryCatch try_catch;
3040 CHECK(!try_catch.HasCaught());
3041 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
3042 CompileRun("f({toString: function() { throw 42; }});");
3043 CHECK(!try_catch.HasCaught());
3044}
3045
3046
3047v8::Handle<v8::Value> WithTryCatch(const v8::Arguments& args) {
3048 v8::TryCatch try_catch;
3049 return v8::Undefined();
3050}
3051
3052
3053THREADED_TEST(TryCatchAndFinally) {
3054 v8::HandleScope scope;
3055 LocalContext context;
3056 context->Global()->Set(
3057 v8_str("native_with_try_catch"),
3058 v8::FunctionTemplate::New(WithTryCatch)->GetFunction());
3059 v8::TryCatch try_catch;
3060 CHECK(!try_catch.HasCaught());
3061 CompileRun(
3062 "try {\n"
3063 " throw new Error('a');\n"
3064 "} finally {\n"
3065 " native_with_try_catch();\n"
3066 "}\n");
3067 CHECK(try_catch.HasCaught());
3068}
3069
3070
Steve Blocka7e24c12009-10-30 11:49:00 +00003071THREADED_TEST(Equality) {
3072 v8::HandleScope scope;
3073 LocalContext context;
3074 // Check that equality works at all before relying on CHECK_EQ
3075 CHECK(v8_str("a")->Equals(v8_str("a")));
3076 CHECK(!v8_str("a")->Equals(v8_str("b")));
3077
3078 CHECK_EQ(v8_str("a"), v8_str("a"));
3079 CHECK_NE(v8_str("a"), v8_str("b"));
3080 CHECK_EQ(v8_num(1), v8_num(1));
3081 CHECK_EQ(v8_num(1.00), v8_num(1));
3082 CHECK_NE(v8_num(1), v8_num(2));
3083
3084 // Assume String is not symbol.
3085 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
3086 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
3087 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
3088 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
3089 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
3090 CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
3091 Local<Value> not_a_number = v8_num(i::OS::nan_value());
3092 CHECK(!not_a_number->StrictEquals(not_a_number));
3093 CHECK(v8::False()->StrictEquals(v8::False()));
3094 CHECK(!v8::False()->StrictEquals(v8::Undefined()));
3095
3096 v8::Handle<v8::Object> obj = v8::Object::New();
3097 v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
3098 CHECK(alias->StrictEquals(obj));
3099 alias.Dispose();
3100}
3101
3102
3103THREADED_TEST(MultiRun) {
3104 v8::HandleScope scope;
3105 LocalContext context;
3106 Local<Script> script = Script::Compile(v8_str("x"));
3107 for (int i = 0; i < 10; i++)
3108 script->Run();
3109}
3110
3111
3112static v8::Handle<Value> GetXValue(Local<String> name,
3113 const AccessorInfo& info) {
3114 ApiTestFuzzer::Fuzz();
3115 CHECK_EQ(info.Data(), v8_str("donut"));
3116 CHECK_EQ(name, v8_str("x"));
3117 return name;
3118}
3119
3120
3121THREADED_TEST(SimplePropertyRead) {
3122 v8::HandleScope scope;
3123 Local<ObjectTemplate> templ = ObjectTemplate::New();
3124 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3125 LocalContext context;
3126 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3127 Local<Script> script = Script::Compile(v8_str("obj.x"));
3128 for (int i = 0; i < 10; i++) {
3129 Local<Value> result = script->Run();
3130 CHECK_EQ(result, v8_str("x"));
3131 }
3132}
3133
Andrei Popescu31002712010-02-23 13:46:05 +00003134THREADED_TEST(DefinePropertyOnAPIAccessor) {
3135 v8::HandleScope scope;
3136 Local<ObjectTemplate> templ = ObjectTemplate::New();
3137 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3138 LocalContext context;
3139 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3140
3141 // Uses getOwnPropertyDescriptor to check the configurable status
3142 Local<Script> script_desc
Leon Clarkef7060e22010-06-03 12:02:55 +01003143 = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
Andrei Popescu31002712010-02-23 13:46:05 +00003144 "obj, 'x');"
3145 "prop.configurable;"));
3146 Local<Value> result = script_desc->Run();
3147 CHECK_EQ(result->BooleanValue(), true);
3148
3149 // Redefine get - but still configurable
3150 Local<Script> script_define
3151 = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
3152 " configurable: true };"
3153 "Object.defineProperty(obj, 'x', desc);"
3154 "obj.x"));
3155 result = script_define->Run();
3156 CHECK_EQ(result, v8_num(42));
3157
3158 // Check that the accessor is still configurable
3159 result = script_desc->Run();
3160 CHECK_EQ(result->BooleanValue(), true);
3161
3162 // Redefine to a non-configurable
3163 script_define
3164 = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
3165 " configurable: false };"
3166 "Object.defineProperty(obj, 'x', desc);"
3167 "obj.x"));
3168 result = script_define->Run();
3169 CHECK_EQ(result, v8_num(43));
3170 result = script_desc->Run();
3171 CHECK_EQ(result->BooleanValue(), false);
3172
3173 // Make sure that it is not possible to redefine again
3174 v8::TryCatch try_catch;
3175 result = script_define->Run();
3176 CHECK(try_catch.HasCaught());
3177 String::AsciiValue exception_value(try_catch.Exception());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003178 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
Andrei Popescu31002712010-02-23 13:46:05 +00003179}
3180
3181THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
3182 v8::HandleScope scope;
3183 Local<ObjectTemplate> templ = ObjectTemplate::New();
3184 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3185 LocalContext context;
3186 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3187
3188 Local<Script> script_desc = Script::Compile(v8_str("var prop ="
3189 "Object.getOwnPropertyDescriptor( "
3190 "obj, 'x');"
3191 "prop.configurable;"));
3192 Local<Value> result = script_desc->Run();
3193 CHECK_EQ(result->BooleanValue(), true);
3194
3195 Local<Script> script_define =
3196 Script::Compile(v8_str("var desc = {get: function(){return 42; },"
3197 " configurable: true };"
3198 "Object.defineProperty(obj, 'x', desc);"
3199 "obj.x"));
3200 result = script_define->Run();
3201 CHECK_EQ(result, v8_num(42));
3202
3203
3204 result = script_desc->Run();
3205 CHECK_EQ(result->BooleanValue(), true);
3206
3207
3208 script_define =
3209 Script::Compile(v8_str("var desc = {get: function(){return 43; },"
3210 " configurable: false };"
3211 "Object.defineProperty(obj, 'x', desc);"
3212 "obj.x"));
3213 result = script_define->Run();
3214 CHECK_EQ(result, v8_num(43));
3215 result = script_desc->Run();
3216
3217 CHECK_EQ(result->BooleanValue(), false);
3218
3219 v8::TryCatch try_catch;
3220 result = script_define->Run();
3221 CHECK(try_catch.HasCaught());
3222 String::AsciiValue exception_value(try_catch.Exception());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003223 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
Andrei Popescu31002712010-02-23 13:46:05 +00003224}
3225
3226
Leon Clarkef7060e22010-06-03 12:02:55 +01003227static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
3228 char const* name) {
3229 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
3230}
Andrei Popescu31002712010-02-23 13:46:05 +00003231
3232
Leon Clarkef7060e22010-06-03 12:02:55 +01003233THREADED_TEST(DefineAPIAccessorOnObject) {
3234 v8::HandleScope scope;
3235 Local<ObjectTemplate> templ = ObjectTemplate::New();
3236 LocalContext context;
3237
3238 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3239 CompileRun("var obj2 = {};");
3240
3241 CHECK(CompileRun("obj1.x")->IsUndefined());
3242 CHECK(CompileRun("obj2.x")->IsUndefined());
3243
3244 CHECK(GetGlobalProperty(&context, "obj1")->
3245 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3246
3247 ExpectString("obj1.x", "x");
3248 CHECK(CompileRun("obj2.x")->IsUndefined());
3249
3250 CHECK(GetGlobalProperty(&context, "obj2")->
3251 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3252
3253 ExpectString("obj1.x", "x");
3254 ExpectString("obj2.x", "x");
3255
3256 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3257 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3258
3259 CompileRun("Object.defineProperty(obj1, 'x',"
3260 "{ get: function() { return 'y'; }, configurable: true })");
3261
3262 ExpectString("obj1.x", "y");
3263 ExpectString("obj2.x", "x");
3264
3265 CompileRun("Object.defineProperty(obj2, 'x',"
3266 "{ get: function() { return 'y'; }, configurable: true })");
3267
3268 ExpectString("obj1.x", "y");
3269 ExpectString("obj2.x", "y");
3270
3271 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3272 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3273
3274 CHECK(GetGlobalProperty(&context, "obj1")->
3275 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3276 CHECK(GetGlobalProperty(&context, "obj2")->
3277 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3278
3279 ExpectString("obj1.x", "x");
3280 ExpectString("obj2.x", "x");
3281
3282 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3283 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3284
3285 // Define getters/setters, but now make them not configurable.
3286 CompileRun("Object.defineProperty(obj1, 'x',"
3287 "{ get: function() { return 'z'; }, configurable: false })");
3288 CompileRun("Object.defineProperty(obj2, 'x',"
3289 "{ get: function() { return 'z'; }, configurable: false })");
3290
3291 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3292 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3293
3294 ExpectString("obj1.x", "z");
3295 ExpectString("obj2.x", "z");
3296
3297 CHECK(!GetGlobalProperty(&context, "obj1")->
3298 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3299 CHECK(!GetGlobalProperty(&context, "obj2")->
3300 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3301
3302 ExpectString("obj1.x", "z");
3303 ExpectString("obj2.x", "z");
3304}
3305
3306
3307THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
3308 v8::HandleScope scope;
3309 Local<ObjectTemplate> templ = ObjectTemplate::New();
3310 LocalContext context;
3311
3312 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3313 CompileRun("var obj2 = {};");
3314
3315 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3316 v8_str("x"),
3317 GetXValue, NULL,
3318 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3319 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3320 v8_str("x"),
3321 GetXValue, NULL,
3322 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3323
3324 ExpectString("obj1.x", "x");
3325 ExpectString("obj2.x", "x");
3326
3327 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3328 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3329
3330 CHECK(!GetGlobalProperty(&context, "obj1")->
3331 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3332 CHECK(!GetGlobalProperty(&context, "obj2")->
3333 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3334
3335 {
3336 v8::TryCatch try_catch;
3337 CompileRun("Object.defineProperty(obj1, 'x',"
3338 "{get: function() { return 'func'; }})");
3339 CHECK(try_catch.HasCaught());
3340 String::AsciiValue exception_value(try_catch.Exception());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003341 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
Leon Clarkef7060e22010-06-03 12:02:55 +01003342 }
3343 {
3344 v8::TryCatch try_catch;
3345 CompileRun("Object.defineProperty(obj2, 'x',"
3346 "{get: function() { return 'func'; }})");
3347 CHECK(try_catch.HasCaught());
3348 String::AsciiValue exception_value(try_catch.Exception());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003349 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
Leon Clarkef7060e22010-06-03 12:02:55 +01003350 }
3351}
3352
3353
3354static v8::Handle<Value> Get239Value(Local<String> name,
3355 const AccessorInfo& info) {
3356 ApiTestFuzzer::Fuzz();
3357 CHECK_EQ(info.Data(), v8_str("donut"));
3358 CHECK_EQ(name, v8_str("239"));
3359 return name;
3360}
3361
3362
3363THREADED_TEST(ElementAPIAccessor) {
3364 v8::HandleScope scope;
3365 Local<ObjectTemplate> templ = ObjectTemplate::New();
3366 LocalContext context;
3367
3368 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3369 CompileRun("var obj2 = {};");
3370
3371 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3372 v8_str("239"),
3373 Get239Value, NULL,
3374 v8_str("donut")));
3375 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3376 v8_str("239"),
3377 Get239Value, NULL,
3378 v8_str("donut")));
3379
3380 ExpectString("obj1[239]", "239");
3381 ExpectString("obj2[239]", "239");
3382 ExpectString("obj1['239']", "239");
3383 ExpectString("obj2['239']", "239");
3384}
3385
Steve Blocka7e24c12009-10-30 11:49:00 +00003386
3387v8::Persistent<Value> xValue;
3388
3389
3390static void SetXValue(Local<String> name,
3391 Local<Value> value,
3392 const AccessorInfo& info) {
3393 CHECK_EQ(value, v8_num(4));
3394 CHECK_EQ(info.Data(), v8_str("donut"));
3395 CHECK_EQ(name, v8_str("x"));
3396 CHECK(xValue.IsEmpty());
3397 xValue = v8::Persistent<Value>::New(value);
3398}
3399
3400
3401THREADED_TEST(SimplePropertyWrite) {
3402 v8::HandleScope scope;
3403 Local<ObjectTemplate> templ = ObjectTemplate::New();
3404 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
3405 LocalContext context;
3406 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3407 Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
3408 for (int i = 0; i < 10; i++) {
3409 CHECK(xValue.IsEmpty());
3410 script->Run();
3411 CHECK_EQ(v8_num(4), xValue);
3412 xValue.Dispose();
3413 xValue = v8::Persistent<Value>();
3414 }
3415}
3416
3417
3418static v8::Handle<Value> XPropertyGetter(Local<String> property,
3419 const AccessorInfo& info) {
3420 ApiTestFuzzer::Fuzz();
3421 CHECK(info.Data()->IsUndefined());
3422 return property;
3423}
3424
3425
3426THREADED_TEST(NamedInterceptorPropertyRead) {
3427 v8::HandleScope scope;
3428 Local<ObjectTemplate> templ = ObjectTemplate::New();
3429 templ->SetNamedPropertyHandler(XPropertyGetter);
3430 LocalContext context;
3431 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3432 Local<Script> script = Script::Compile(v8_str("obj.x"));
3433 for (int i = 0; i < 10; i++) {
3434 Local<Value> result = script->Run();
3435 CHECK_EQ(result, v8_str("x"));
3436 }
3437}
3438
3439
Steve Block6ded16b2010-05-10 14:33:55 +01003440THREADED_TEST(NamedInterceptorDictionaryIC) {
3441 v8::HandleScope scope;
3442 Local<ObjectTemplate> templ = ObjectTemplate::New();
3443 templ->SetNamedPropertyHandler(XPropertyGetter);
3444 LocalContext context;
3445 // Create an object with a named interceptor.
3446 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
3447 Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
3448 for (int i = 0; i < 10; i++) {
3449 Local<Value> result = script->Run();
3450 CHECK_EQ(result, v8_str("x"));
3451 }
3452 // Create a slow case object and a function accessing a property in
3453 // that slow case object (with dictionary probing in generated
3454 // code). Then force object with a named interceptor into slow-case,
3455 // pass it to the function, and check that the interceptor is called
3456 // instead of accessing the local property.
3457 Local<Value> result =
3458 CompileRun("function get_x(o) { return o.x; };"
3459 "var obj = { x : 42, y : 0 };"
3460 "delete obj.y;"
3461 "for (var i = 0; i < 10; i++) get_x(obj);"
3462 "interceptor_obj.x = 42;"
3463 "interceptor_obj.y = 10;"
3464 "delete interceptor_obj.y;"
3465 "get_x(interceptor_obj)");
3466 CHECK_EQ(result, v8_str("x"));
3467}
3468
3469
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003470THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
3471 v8::HandleScope scope;
3472
3473 v8::Persistent<Context> context1 = Context::New();
3474
3475 context1->Enter();
3476 Local<ObjectTemplate> templ = ObjectTemplate::New();
3477 templ->SetNamedPropertyHandler(XPropertyGetter);
3478 // Create an object with a named interceptor.
3479 v8::Local<v8::Object> object = templ->NewInstance();
3480 context1->Global()->Set(v8_str("interceptor_obj"), object);
3481
3482 // Force the object into the slow case.
3483 CompileRun("interceptor_obj.y = 0;"
3484 "delete interceptor_obj.y;");
3485 context1->Exit();
3486
3487 {
3488 // Introduce the object into a different context.
3489 // Repeat named loads to exercise ICs.
3490 LocalContext context2;
3491 context2->Global()->Set(v8_str("interceptor_obj"), object);
3492 Local<Value> result =
3493 CompileRun("function get_x(o) { return o.x; }"
3494 "interceptor_obj.x = 42;"
3495 "for (var i=0; i != 10; i++) {"
3496 " get_x(interceptor_obj);"
3497 "}"
3498 "get_x(interceptor_obj)");
3499 // Check that the interceptor was actually invoked.
3500 CHECK_EQ(result, v8_str("x"));
3501 }
3502
3503 // Return to the original context and force some object to the slow case
3504 // to cause the NormalizedMapCache to verify.
3505 context1->Enter();
3506 CompileRun("var obj = { x : 0 }; delete obj.x;");
3507 context1->Exit();
3508
3509 context1.Dispose();
3510}
3511
3512
Andrei Popescu402d9372010-02-26 13:31:12 +00003513static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
3514 const AccessorInfo& info) {
3515 // Set x on the prototype object and do not handle the get request.
3516 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
Steve Block6ded16b2010-05-10 14:33:55 +01003517 proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
Andrei Popescu402d9372010-02-26 13:31:12 +00003518 return v8::Handle<Value>();
3519}
3520
3521
3522// This is a regression test for http://crbug.com/20104. Map
3523// transitions should not interfere with post interceptor lookup.
3524THREADED_TEST(NamedInterceptorMapTransitionRead) {
3525 v8::HandleScope scope;
3526 Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
3527 Local<v8::ObjectTemplate> instance_template
3528 = function_template->InstanceTemplate();
3529 instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
3530 LocalContext context;
3531 context->Global()->Set(v8_str("F"), function_template->GetFunction());
3532 // Create an instance of F and introduce a map transition for x.
3533 CompileRun("var o = new F(); o.x = 23;");
3534 // Create an instance of F and invoke the getter. The result should be 23.
3535 Local<Value> result = CompileRun("o = new F(); o.x");
3536 CHECK_EQ(result->Int32Value(), 23);
3537}
3538
3539
Steve Blocka7e24c12009-10-30 11:49:00 +00003540static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
3541 const AccessorInfo& info) {
3542 ApiTestFuzzer::Fuzz();
3543 if (index == 37) {
3544 return v8::Handle<Value>(v8_num(625));
3545 }
3546 return v8::Handle<Value>();
3547}
3548
3549
3550static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
3551 Local<Value> value,
3552 const AccessorInfo& info) {
3553 ApiTestFuzzer::Fuzz();
3554 if (index == 39) {
3555 return value;
3556 }
3557 return v8::Handle<Value>();
3558}
3559
3560
3561THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
3562 v8::HandleScope scope;
3563 Local<ObjectTemplate> templ = ObjectTemplate::New();
3564 templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
3565 IndexedPropertySetter);
3566 LocalContext context;
3567 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3568 Local<Script> getter_script = Script::Compile(v8_str(
3569 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
3570 Local<Script> setter_script = Script::Compile(v8_str(
3571 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
3572 "obj[17] = 23;"
3573 "obj.foo;"));
3574 Local<Script> interceptor_setter_script = Script::Compile(v8_str(
3575 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
3576 "obj[39] = 47;"
3577 "obj.foo;")); // This setter should not run, due to the interceptor.
3578 Local<Script> interceptor_getter_script = Script::Compile(v8_str(
3579 "obj[37];"));
3580 Local<Value> result = getter_script->Run();
3581 CHECK_EQ(v8_num(5), result);
3582 result = setter_script->Run();
3583 CHECK_EQ(v8_num(23), result);
3584 result = interceptor_setter_script->Run();
3585 CHECK_EQ(v8_num(23), result);
3586 result = interceptor_getter_script->Run();
3587 CHECK_EQ(v8_num(625), result);
3588}
3589
3590
Leon Clarked91b9f72010-01-27 17:25:45 +00003591static v8::Handle<Value> IdentityIndexedPropertyGetter(
3592 uint32_t index,
3593 const AccessorInfo& info) {
Ben Murdochf87a2032010-10-22 12:50:53 +01003594 return v8::Integer::NewFromUnsigned(index);
Leon Clarked91b9f72010-01-27 17:25:45 +00003595}
3596
3597
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003598THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
3599 v8::HandleScope scope;
3600 Local<ObjectTemplate> templ = ObjectTemplate::New();
3601 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3602
3603 LocalContext context;
3604 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3605
3606 // Check fast object case.
3607 const char* fast_case_code =
3608 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
3609 ExpectString(fast_case_code, "0");
3610
3611 // Check slow case.
3612 const char* slow_case_code =
3613 "obj.x = 1; delete obj.x;"
3614 "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
3615 ExpectString(slow_case_code, "1");
3616}
3617
3618
Leon Clarked91b9f72010-01-27 17:25:45 +00003619THREADED_TEST(IndexedInterceptorWithNoSetter) {
3620 v8::HandleScope scope;
3621 Local<ObjectTemplate> templ = ObjectTemplate::New();
3622 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3623
3624 LocalContext context;
3625 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3626
3627 const char* code =
3628 "try {"
3629 " obj[0] = 239;"
3630 " for (var i = 0; i < 100; i++) {"
3631 " var v = obj[0];"
3632 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
3633 " }"
3634 " 'PASSED'"
3635 "} catch(e) {"
3636 " e"
3637 "}";
3638 ExpectString(code, "PASSED");
3639}
3640
3641
Andrei Popescu402d9372010-02-26 13:31:12 +00003642THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
3643 v8::HandleScope scope;
3644 Local<ObjectTemplate> templ = ObjectTemplate::New();
3645 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3646
3647 LocalContext context;
3648 Local<v8::Object> obj = templ->NewInstance();
3649 obj->TurnOnAccessCheck();
3650 context->Global()->Set(v8_str("obj"), obj);
3651
3652 const char* code =
3653 "try {"
3654 " for (var i = 0; i < 100; i++) {"
3655 " var v = obj[0];"
3656 " if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
3657 " }"
3658 " 'PASSED'"
3659 "} catch(e) {"
3660 " e"
3661 "}";
3662 ExpectString(code, "PASSED");
3663}
3664
3665
3666THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
3667 i::FLAG_allow_natives_syntax = true;
3668 v8::HandleScope scope;
3669 Local<ObjectTemplate> templ = ObjectTemplate::New();
3670 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3671
3672 LocalContext context;
3673 Local<v8::Object> obj = templ->NewInstance();
3674 context->Global()->Set(v8_str("obj"), obj);
3675
3676 const char* code =
3677 "try {"
3678 " for (var i = 0; i < 100; i++) {"
3679 " var expected = i;"
3680 " if (i == 5) {"
3681 " %EnableAccessChecks(obj);"
3682 " expected = undefined;"
3683 " }"
3684 " var v = obj[i];"
3685 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3686 " if (i == 5) %DisableAccessChecks(obj);"
3687 " }"
3688 " 'PASSED'"
3689 "} catch(e) {"
3690 " e"
3691 "}";
3692 ExpectString(code, "PASSED");
3693}
3694
3695
3696THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
3697 v8::HandleScope scope;
3698 Local<ObjectTemplate> templ = ObjectTemplate::New();
3699 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3700
3701 LocalContext context;
3702 Local<v8::Object> obj = templ->NewInstance();
3703 context->Global()->Set(v8_str("obj"), obj);
3704
3705 const char* code =
3706 "try {"
3707 " for (var i = 0; i < 100; i++) {"
3708 " var v = obj[i];"
3709 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
3710 " }"
3711 " 'PASSED'"
3712 "} catch(e) {"
3713 " e"
3714 "}";
3715 ExpectString(code, "PASSED");
3716}
3717
3718
Ben Murdochf87a2032010-10-22 12:50:53 +01003719THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
3720 v8::HandleScope scope;
3721 Local<ObjectTemplate> templ = ObjectTemplate::New();
3722 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3723
3724 LocalContext context;
3725 Local<v8::Object> obj = templ->NewInstance();
3726 context->Global()->Set(v8_str("obj"), obj);
3727
3728 const char* code =
3729 "try {"
3730 " for (var i = 0; i < 100; i++) {"
3731 " var expected = i;"
3732 " var key = i;"
3733 " if (i == 25) {"
3734 " key = -1;"
3735 " expected = undefined;"
3736 " }"
3737 " if (i == 50) {"
3738 " /* probe minimal Smi number on 32-bit platforms */"
3739 " key = -(1 << 30);"
3740 " expected = undefined;"
3741 " }"
3742 " if (i == 75) {"
3743 " /* probe minimal Smi number on 64-bit platforms */"
3744 " key = 1 << 31;"
3745 " expected = undefined;"
3746 " }"
3747 " var v = obj[key];"
3748 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3749 " }"
3750 " 'PASSED'"
3751 "} catch(e) {"
3752 " e"
3753 "}";
3754 ExpectString(code, "PASSED");
3755}
3756
3757
Andrei Popescu402d9372010-02-26 13:31:12 +00003758THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
3759 v8::HandleScope scope;
3760 Local<ObjectTemplate> templ = ObjectTemplate::New();
3761 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3762
3763 LocalContext context;
3764 Local<v8::Object> obj = templ->NewInstance();
3765 context->Global()->Set(v8_str("obj"), obj);
3766
3767 const char* code =
3768 "try {"
3769 " for (var i = 0; i < 100; i++) {"
3770 " var expected = i;"
Ben Murdochf87a2032010-10-22 12:50:53 +01003771 " var key = i;"
Andrei Popescu402d9372010-02-26 13:31:12 +00003772 " if (i == 50) {"
Ben Murdochf87a2032010-10-22 12:50:53 +01003773 " key = 'foobar';"
Andrei Popescu402d9372010-02-26 13:31:12 +00003774 " expected = undefined;"
3775 " }"
Ben Murdochf87a2032010-10-22 12:50:53 +01003776 " var v = obj[key];"
Andrei Popescu402d9372010-02-26 13:31:12 +00003777 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3778 " }"
3779 " 'PASSED'"
3780 "} catch(e) {"
3781 " e"
3782 "}";
3783 ExpectString(code, "PASSED");
3784}
3785
3786
3787THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
3788 v8::HandleScope scope;
3789 Local<ObjectTemplate> templ = ObjectTemplate::New();
3790 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3791
3792 LocalContext context;
3793 Local<v8::Object> obj = templ->NewInstance();
3794 context->Global()->Set(v8_str("obj"), obj);
3795
3796 const char* code =
3797 "var original = obj;"
3798 "try {"
3799 " for (var i = 0; i < 100; i++) {"
3800 " var expected = i;"
3801 " if (i == 50) {"
3802 " obj = {50: 'foobar'};"
3803 " expected = 'foobar';"
3804 " }"
3805 " var v = obj[i];"
3806 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3807 " if (i == 50) obj = original;"
3808 " }"
3809 " 'PASSED'"
3810 "} catch(e) {"
3811 " e"
3812 "}";
3813 ExpectString(code, "PASSED");
3814}
3815
3816
3817THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
3818 v8::HandleScope scope;
3819 Local<ObjectTemplate> templ = ObjectTemplate::New();
3820 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3821
3822 LocalContext context;
3823 Local<v8::Object> obj = templ->NewInstance();
3824 context->Global()->Set(v8_str("obj"), obj);
3825
3826 const char* code =
3827 "var original = obj;"
3828 "try {"
3829 " for (var i = 0; i < 100; i++) {"
3830 " var expected = i;"
3831 " if (i == 5) {"
3832 " obj = 239;"
3833 " expected = undefined;"
3834 " }"
3835 " var v = obj[i];"
3836 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3837 " if (i == 5) obj = original;"
3838 " }"
3839 " 'PASSED'"
3840 "} catch(e) {"
3841 " e"
3842 "}";
3843 ExpectString(code, "PASSED");
3844}
3845
3846
3847THREADED_TEST(IndexedInterceptorOnProto) {
3848 v8::HandleScope scope;
3849 Local<ObjectTemplate> templ = ObjectTemplate::New();
3850 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3851
3852 LocalContext context;
3853 Local<v8::Object> obj = templ->NewInstance();
3854 context->Global()->Set(v8_str("obj"), obj);
3855
3856 const char* code =
3857 "var o = {__proto__: obj};"
3858 "try {"
3859 " for (var i = 0; i < 100; i++) {"
3860 " var v = o[i];"
3861 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
3862 " }"
3863 " 'PASSED'"
3864 "} catch(e) {"
3865 " e"
3866 "}";
3867 ExpectString(code, "PASSED");
3868}
3869
3870
Steve Blocka7e24c12009-10-30 11:49:00 +00003871THREADED_TEST(MultiContexts) {
3872 v8::HandleScope scope;
3873 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
3874 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
3875
3876 Local<String> password = v8_str("Password");
3877
3878 // Create an environment
3879 LocalContext context0(0, templ);
3880 context0->SetSecurityToken(password);
3881 v8::Handle<v8::Object> global0 = context0->Global();
3882 global0->Set(v8_str("custom"), v8_num(1234));
3883 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
3884
3885 // Create an independent environment
3886 LocalContext context1(0, templ);
3887 context1->SetSecurityToken(password);
3888 v8::Handle<v8::Object> global1 = context1->Global();
3889 global1->Set(v8_str("custom"), v8_num(1234));
3890 CHECK_NE(global0, global1);
3891 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
3892 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
3893
3894 // Now create a new context with the old global
3895 LocalContext context2(0, templ, global1);
3896 context2->SetSecurityToken(password);
3897 v8::Handle<v8::Object> global2 = context2->Global();
3898 CHECK_EQ(global1, global2);
3899 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
3900 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
3901}
3902
3903
3904THREADED_TEST(FunctionPrototypeAcrossContexts) {
3905 // Make sure that functions created by cloning boilerplates cannot
3906 // communicate through their __proto__ field.
3907
3908 v8::HandleScope scope;
3909
3910 LocalContext env0;
3911 v8::Handle<v8::Object> global0 =
3912 env0->Global();
3913 v8::Handle<v8::Object> object0 =
Steve Block6ded16b2010-05-10 14:33:55 +01003914 global0->Get(v8_str("Object")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00003915 v8::Handle<v8::Object> tostring0 =
Steve Block6ded16b2010-05-10 14:33:55 +01003916 object0->Get(v8_str("toString")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00003917 v8::Handle<v8::Object> proto0 =
Steve Block6ded16b2010-05-10 14:33:55 +01003918 tostring0->Get(v8_str("__proto__")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00003919 proto0->Set(v8_str("custom"), v8_num(1234));
3920
3921 LocalContext env1;
3922 v8::Handle<v8::Object> global1 =
3923 env1->Global();
3924 v8::Handle<v8::Object> object1 =
Steve Block6ded16b2010-05-10 14:33:55 +01003925 global1->Get(v8_str("Object")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00003926 v8::Handle<v8::Object> tostring1 =
Steve Block6ded16b2010-05-10 14:33:55 +01003927 object1->Get(v8_str("toString")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00003928 v8::Handle<v8::Object> proto1 =
Steve Block6ded16b2010-05-10 14:33:55 +01003929 tostring1->Get(v8_str("__proto__")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00003930 CHECK(!proto1->Has(v8_str("custom")));
3931}
3932
3933
3934THREADED_TEST(Regress892105) {
3935 // Make sure that object and array literals created by cloning
3936 // boilerplates cannot communicate through their __proto__
3937 // field. This is rather difficult to check, but we try to add stuff
3938 // to Object.prototype and Array.prototype and create a new
3939 // environment. This should succeed.
3940
3941 v8::HandleScope scope;
3942
3943 Local<String> source = v8_str("Object.prototype.obj = 1234;"
3944 "Array.prototype.arr = 4567;"
3945 "8901");
3946
3947 LocalContext env0;
3948 Local<Script> script0 = Script::Compile(source);
3949 CHECK_EQ(8901.0, script0->Run()->NumberValue());
3950
3951 LocalContext env1;
3952 Local<Script> script1 = Script::Compile(source);
3953 CHECK_EQ(8901.0, script1->Run()->NumberValue());
3954}
3955
3956
Steve Blocka7e24c12009-10-30 11:49:00 +00003957THREADED_TEST(UndetectableObject) {
3958 v8::HandleScope scope;
3959 LocalContext env;
3960
3961 Local<v8::FunctionTemplate> desc =
3962 v8::FunctionTemplate::New(0, v8::Handle<Value>());
3963 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
3964
3965 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
3966 env->Global()->Set(v8_str("undetectable"), obj);
3967
3968 ExpectString("undetectable.toString()", "[object Object]");
3969 ExpectString("typeof undetectable", "undefined");
3970 ExpectString("typeof(undetectable)", "undefined");
3971 ExpectBoolean("typeof undetectable == 'undefined'", true);
3972 ExpectBoolean("typeof undetectable == 'object'", false);
3973 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
3974 ExpectBoolean("!undetectable", true);
3975
3976 ExpectObject("true&&undetectable", obj);
3977 ExpectBoolean("false&&undetectable", false);
3978 ExpectBoolean("true||undetectable", true);
3979 ExpectObject("false||undetectable", obj);
3980
3981 ExpectObject("undetectable&&true", obj);
3982 ExpectObject("undetectable&&false", obj);
3983 ExpectBoolean("undetectable||true", true);
3984 ExpectBoolean("undetectable||false", false);
3985
3986 ExpectBoolean("undetectable==null", true);
3987 ExpectBoolean("null==undetectable", true);
3988 ExpectBoolean("undetectable==undefined", true);
3989 ExpectBoolean("undefined==undetectable", true);
3990 ExpectBoolean("undetectable==undetectable", true);
3991
3992
3993 ExpectBoolean("undetectable===null", false);
3994 ExpectBoolean("null===undetectable", false);
3995 ExpectBoolean("undetectable===undefined", false);
3996 ExpectBoolean("undefined===undetectable", false);
3997 ExpectBoolean("undetectable===undetectable", true);
3998}
3999
4000
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004001THREADED_TEST(VoidLiteral) {
4002 v8::HandleScope scope;
4003 LocalContext env;
4004
4005 Local<v8::FunctionTemplate> desc =
4006 v8::FunctionTemplate::New(0, v8::Handle<Value>());
4007 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4008
4009 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4010 env->Global()->Set(v8_str("undetectable"), obj);
4011
4012 ExpectBoolean("undefined == void 0", true);
4013 ExpectBoolean("undetectable == void 0", true);
4014 ExpectBoolean("null == void 0", true);
4015 ExpectBoolean("undefined === void 0", true);
4016 ExpectBoolean("undetectable === void 0", false);
4017 ExpectBoolean("null === void 0", false);
4018
4019 ExpectBoolean("void 0 == undefined", true);
4020 ExpectBoolean("void 0 == undetectable", true);
4021 ExpectBoolean("void 0 == null", true);
4022 ExpectBoolean("void 0 === undefined", true);
4023 ExpectBoolean("void 0 === undetectable", false);
4024 ExpectBoolean("void 0 === null", false);
4025
4026 ExpectString("(function() {"
4027 " try {"
4028 " return x === void 0;"
4029 " } catch(e) {"
4030 " return e.toString();"
4031 " }"
4032 "})()",
4033 "ReferenceError: x is not defined");
4034 ExpectString("(function() {"
4035 " try {"
4036 " return void 0 === x;"
4037 " } catch(e) {"
4038 " return e.toString();"
4039 " }"
4040 "})()",
4041 "ReferenceError: x is not defined");
4042}
4043
Steve Block8defd9f2010-07-08 12:39:36 +01004044
4045THREADED_TEST(ExtensibleOnUndetectable) {
4046 v8::HandleScope scope;
4047 LocalContext env;
4048
4049 Local<v8::FunctionTemplate> desc =
4050 v8::FunctionTemplate::New(0, v8::Handle<Value>());
4051 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4052
4053 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4054 env->Global()->Set(v8_str("undetectable"), obj);
4055
4056 Local<String> source = v8_str("undetectable.x = 42;"
4057 "undetectable.x");
4058
4059 Local<Script> script = Script::Compile(source);
4060
4061 CHECK_EQ(v8::Integer::New(42), script->Run());
4062
4063 ExpectBoolean("Object.isExtensible(undetectable)", true);
4064
4065 source = v8_str("Object.preventExtensions(undetectable);");
4066 script = Script::Compile(source);
4067 script->Run();
4068 ExpectBoolean("Object.isExtensible(undetectable)", false);
4069
4070 source = v8_str("undetectable.y = 2000;");
4071 script = Script::Compile(source);
Steve Block8defd9f2010-07-08 12:39:36 +01004072 Local<Value> result = script->Run();
Steve Block44f0eee2011-05-26 01:26:41 +01004073 ExpectBoolean("undetectable.y == undefined", true);
Steve Block8defd9f2010-07-08 12:39:36 +01004074}
4075
4076
4077
Steve Blocka7e24c12009-10-30 11:49:00 +00004078THREADED_TEST(UndetectableString) {
4079 v8::HandleScope scope;
4080 LocalContext env;
4081
4082 Local<String> obj = String::NewUndetectable("foo");
4083 env->Global()->Set(v8_str("undetectable"), obj);
4084
4085 ExpectString("undetectable", "foo");
4086 ExpectString("typeof undetectable", "undefined");
4087 ExpectString("typeof(undetectable)", "undefined");
4088 ExpectBoolean("typeof undetectable == 'undefined'", true);
4089 ExpectBoolean("typeof undetectable == 'string'", false);
4090 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
4091 ExpectBoolean("!undetectable", true);
4092
4093 ExpectObject("true&&undetectable", obj);
4094 ExpectBoolean("false&&undetectable", false);
4095 ExpectBoolean("true||undetectable", true);
4096 ExpectObject("false||undetectable", obj);
4097
4098 ExpectObject("undetectable&&true", obj);
4099 ExpectObject("undetectable&&false", obj);
4100 ExpectBoolean("undetectable||true", true);
4101 ExpectBoolean("undetectable||false", false);
4102
4103 ExpectBoolean("undetectable==null", true);
4104 ExpectBoolean("null==undetectable", true);
4105 ExpectBoolean("undetectable==undefined", true);
4106 ExpectBoolean("undefined==undetectable", true);
4107 ExpectBoolean("undetectable==undetectable", true);
4108
4109
4110 ExpectBoolean("undetectable===null", false);
4111 ExpectBoolean("null===undetectable", false);
4112 ExpectBoolean("undetectable===undefined", false);
4113 ExpectBoolean("undefined===undetectable", false);
4114 ExpectBoolean("undetectable===undetectable", true);
4115}
4116
4117
Ben Murdoch257744e2011-11-30 15:57:28 +00004118TEST(UndetectableOptimized) {
4119 i::FLAG_allow_natives_syntax = true;
4120 v8::HandleScope scope;
4121 LocalContext env;
4122
4123 Local<String> obj = String::NewUndetectable("foo");
4124 env->Global()->Set(v8_str("undetectable"), obj);
4125 env->Global()->Set(v8_str("detectable"), v8_str("bar"));
4126
4127 ExpectString(
4128 "function testBranch() {"
4129 " if (!%_IsUndetectableObject(undetectable)) throw 1;"
4130 " if (%_IsUndetectableObject(detectable)) throw 2;"
4131 "}\n"
4132 "function testBool() {"
4133 " var b1 = !%_IsUndetectableObject(undetectable);"
4134 " var b2 = %_IsUndetectableObject(detectable);"
4135 " if (b1) throw 3;"
4136 " if (b2) throw 4;"
4137 " return b1 == b2;"
4138 "}\n"
4139 "%OptimizeFunctionOnNextCall(testBranch);"
4140 "%OptimizeFunctionOnNextCall(testBool);"
4141 "for (var i = 0; i < 10; i++) {"
4142 " testBranch();"
4143 " testBool();"
4144 "}\n"
4145 "\"PASS\"",
4146 "PASS");
4147}
4148
4149
Steve Blocka7e24c12009-10-30 11:49:00 +00004150template <typename T> static void USE(T) { }
4151
4152
4153// This test is not intended to be run, just type checked.
4154static void PersistentHandles() {
4155 USE(PersistentHandles);
4156 Local<String> str = v8_str("foo");
4157 v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
4158 USE(p_str);
4159 Local<Script> scr = Script::Compile(v8_str(""));
4160 v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
4161 USE(p_scr);
4162 Local<ObjectTemplate> templ = ObjectTemplate::New();
4163 v8::Persistent<ObjectTemplate> p_templ =
4164 v8::Persistent<ObjectTemplate>::New(templ);
4165 USE(p_templ);
4166}
4167
4168
4169static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
4170 ApiTestFuzzer::Fuzz();
4171 return v8::Undefined();
4172}
4173
4174
4175THREADED_TEST(GlobalObjectTemplate) {
4176 v8::HandleScope handle_scope;
4177 Local<ObjectTemplate> global_template = ObjectTemplate::New();
4178 global_template->Set(v8_str("JSNI_Log"),
4179 v8::FunctionTemplate::New(HandleLogDelegator));
4180 v8::Persistent<Context> context = Context::New(0, global_template);
4181 Context::Scope context_scope(context);
4182 Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
4183 context.Dispose();
4184}
4185
4186
4187static const char* kSimpleExtensionSource =
4188 "function Foo() {"
4189 " return 4;"
4190 "}";
4191
4192
4193THREADED_TEST(SimpleExtensions) {
4194 v8::HandleScope handle_scope;
4195 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
4196 const char* extension_names[] = { "simpletest" };
4197 v8::ExtensionConfiguration extensions(1, extension_names);
4198 v8::Handle<Context> context = Context::New(&extensions);
4199 Context::Scope lock(context);
4200 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
4201 CHECK_EQ(result, v8::Integer::New(4));
4202}
4203
4204
4205static const char* kEvalExtensionSource1 =
4206 "function UseEval1() {"
4207 " var x = 42;"
4208 " return eval('x');"
4209 "}";
4210
4211
4212static const char* kEvalExtensionSource2 =
4213 "(function() {"
4214 " var x = 42;"
4215 " function e() {"
4216 " return eval('x');"
4217 " }"
4218 " this.UseEval2 = e;"
4219 "})()";
4220
4221
4222THREADED_TEST(UseEvalFromExtension) {
4223 v8::HandleScope handle_scope;
4224 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
4225 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
4226 const char* extension_names[] = { "evaltest1", "evaltest2" };
4227 v8::ExtensionConfiguration extensions(2, extension_names);
4228 v8::Handle<Context> context = Context::New(&extensions);
4229 Context::Scope lock(context);
4230 v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
4231 CHECK_EQ(result, v8::Integer::New(42));
4232 result = Script::Compile(v8_str("UseEval2()"))->Run();
4233 CHECK_EQ(result, v8::Integer::New(42));
4234}
4235
4236
4237static const char* kWithExtensionSource1 =
4238 "function UseWith1() {"
4239 " var x = 42;"
4240 " with({x:87}) { return x; }"
4241 "}";
4242
4243
4244
4245static const char* kWithExtensionSource2 =
4246 "(function() {"
4247 " var x = 42;"
4248 " function e() {"
4249 " with ({x:87}) { return x; }"
4250 " }"
4251 " this.UseWith2 = e;"
4252 "})()";
4253
4254
4255THREADED_TEST(UseWithFromExtension) {
4256 v8::HandleScope handle_scope;
4257 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
4258 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
4259 const char* extension_names[] = { "withtest1", "withtest2" };
4260 v8::ExtensionConfiguration extensions(2, extension_names);
4261 v8::Handle<Context> context = Context::New(&extensions);
4262 Context::Scope lock(context);
4263 v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
4264 CHECK_EQ(result, v8::Integer::New(87));
4265 result = Script::Compile(v8_str("UseWith2()"))->Run();
4266 CHECK_EQ(result, v8::Integer::New(87));
4267}
4268
4269
4270THREADED_TEST(AutoExtensions) {
4271 v8::HandleScope handle_scope;
4272 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
4273 extension->set_auto_enable(true);
4274 v8::RegisterExtension(extension);
4275 v8::Handle<Context> context = Context::New();
4276 Context::Scope lock(context);
4277 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
4278 CHECK_EQ(result, v8::Integer::New(4));
4279}
4280
4281
Steve Blockd0582a62009-12-15 09:54:21 +00004282static const char* kSyntaxErrorInExtensionSource =
4283 "[";
4284
4285
4286// Test that a syntax error in an extension does not cause a fatal
4287// error but results in an empty context.
4288THREADED_TEST(SyntaxErrorExtensions) {
4289 v8::HandleScope handle_scope;
4290 v8::RegisterExtension(new Extension("syntaxerror",
4291 kSyntaxErrorInExtensionSource));
4292 const char* extension_names[] = { "syntaxerror" };
4293 v8::ExtensionConfiguration extensions(1, extension_names);
4294 v8::Handle<Context> context = Context::New(&extensions);
4295 CHECK(context.IsEmpty());
4296}
4297
4298
4299static const char* kExceptionInExtensionSource =
4300 "throw 42";
4301
4302
4303// Test that an exception when installing an extension does not cause
4304// a fatal error but results in an empty context.
4305THREADED_TEST(ExceptionExtensions) {
4306 v8::HandleScope handle_scope;
4307 v8::RegisterExtension(new Extension("exception",
4308 kExceptionInExtensionSource));
4309 const char* extension_names[] = { "exception" };
4310 v8::ExtensionConfiguration extensions(1, extension_names);
4311 v8::Handle<Context> context = Context::New(&extensions);
4312 CHECK(context.IsEmpty());
4313}
4314
4315
Iain Merrick9ac36c92010-09-13 15:29:50 +01004316static const char* kNativeCallInExtensionSource =
4317 "function call_runtime_last_index_of(x) {"
4318 " return %StringLastIndexOf(x, 'bob', 10);"
4319 "}";
4320
4321
4322static const char* kNativeCallTest =
4323 "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
4324
4325// Test that a native runtime calls are supported in extensions.
4326THREADED_TEST(NativeCallInExtensions) {
4327 v8::HandleScope handle_scope;
4328 v8::RegisterExtension(new Extension("nativecall",
4329 kNativeCallInExtensionSource));
4330 const char* extension_names[] = { "nativecall" };
4331 v8::ExtensionConfiguration extensions(1, extension_names);
4332 v8::Handle<Context> context = Context::New(&extensions);
4333 Context::Scope lock(context);
4334 v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run();
4335 CHECK_EQ(result, v8::Integer::New(3));
4336}
4337
4338
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004339class NativeFunctionExtension : public Extension {
4340 public:
4341 NativeFunctionExtension(const char* name,
4342 const char* source,
4343 v8::InvocationCallback fun = &Echo)
4344 : Extension(name, source),
4345 function_(fun) { }
4346
4347 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
4348 v8::Handle<v8::String> name) {
4349 return v8::FunctionTemplate::New(function_);
4350 }
4351
4352 static v8::Handle<v8::Value> Echo(const v8::Arguments& args) {
4353 if (args.Length() >= 1) return (args[0]);
4354 return v8::Undefined();
4355 }
4356 private:
4357 v8::InvocationCallback function_;
4358};
4359
4360
4361THREADED_TEST(NativeFunctionDeclaration) {
4362 v8::HandleScope handle_scope;
4363 const char* name = "nativedecl";
4364 v8::RegisterExtension(new NativeFunctionExtension(name,
4365 "native function foo();"));
4366 const char* extension_names[] = { name };
4367 v8::ExtensionConfiguration extensions(1, extension_names);
4368 v8::Handle<Context> context = Context::New(&extensions);
4369 Context::Scope lock(context);
4370 v8::Handle<Value> result = Script::Compile(v8_str("foo(42);"))->Run();
4371 CHECK_EQ(result, v8::Integer::New(42));
4372}
4373
4374
4375THREADED_TEST(NativeFunctionDeclarationError) {
4376 v8::HandleScope handle_scope;
4377 const char* name = "nativedeclerr";
4378 // Syntax error in extension code.
4379 v8::RegisterExtension(new NativeFunctionExtension(name,
4380 "native\nfunction foo();"));
4381 const char* extension_names[] = { name };
4382 v8::ExtensionConfiguration extensions(1, extension_names);
4383 v8::Handle<Context> context = Context::New(&extensions);
4384 ASSERT(context.IsEmpty());
4385}
4386
4387THREADED_TEST(NativeFunctionDeclarationErrorEscape) {
4388 v8::HandleScope handle_scope;
4389 const char* name = "nativedeclerresc";
4390 // Syntax error in extension code - escape code in "native" means that
4391 // it's not treated as a keyword.
4392 v8::RegisterExtension(new NativeFunctionExtension(
4393 name,
4394 "nativ\\u0065 function foo();"));
4395 const char* extension_names[] = { name };
4396 v8::ExtensionConfiguration extensions(1, extension_names);
4397 v8::Handle<Context> context = Context::New(&extensions);
4398 ASSERT(context.IsEmpty());
4399}
4400
4401
Steve Blocka7e24c12009-10-30 11:49:00 +00004402static void CheckDependencies(const char* name, const char* expected) {
4403 v8::HandleScope handle_scope;
4404 v8::ExtensionConfiguration config(1, &name);
4405 LocalContext context(&config);
4406 CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
4407}
4408
4409
4410/*
4411 * Configuration:
4412 *
4413 * /-- B <--\
4414 * A <- -- D <-- E
4415 * \-- C <--/
4416 */
4417THREADED_TEST(ExtensionDependency) {
4418 static const char* kEDeps[] = { "D" };
4419 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
4420 static const char* kDDeps[] = { "B", "C" };
4421 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
4422 static const char* kBCDeps[] = { "A" };
4423 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
4424 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
4425 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
4426 CheckDependencies("A", "undefinedA");
4427 CheckDependencies("B", "undefinedAB");
4428 CheckDependencies("C", "undefinedAC");
4429 CheckDependencies("D", "undefinedABCD");
4430 CheckDependencies("E", "undefinedABCDE");
4431 v8::HandleScope handle_scope;
4432 static const char* exts[2] = { "C", "E" };
4433 v8::ExtensionConfiguration config(2, exts);
4434 LocalContext context(&config);
4435 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
4436}
4437
4438
4439static const char* kExtensionTestScript =
4440 "native function A();"
4441 "native function B();"
4442 "native function C();"
4443 "function Foo(i) {"
4444 " if (i == 0) return A();"
4445 " if (i == 1) return B();"
4446 " if (i == 2) return C();"
4447 "}";
4448
4449
4450static v8::Handle<Value> CallFun(const v8::Arguments& args) {
4451 ApiTestFuzzer::Fuzz();
Leon Clarkee46be812010-01-19 14:06:41 +00004452 if (args.IsConstructCall()) {
4453 args.This()->Set(v8_str("data"), args.Data());
4454 return v8::Null();
4455 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004456 return args.Data();
4457}
4458
4459
4460class FunctionExtension : public Extension {
4461 public:
4462 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
4463 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
4464 v8::Handle<String> name);
4465};
4466
4467
4468static int lookup_count = 0;
4469v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
4470 v8::Handle<String> name) {
4471 lookup_count++;
4472 if (name->Equals(v8_str("A"))) {
4473 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
4474 } else if (name->Equals(v8_str("B"))) {
4475 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
4476 } else if (name->Equals(v8_str("C"))) {
4477 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
4478 } else {
4479 return v8::Handle<v8::FunctionTemplate>();
4480 }
4481}
4482
4483
4484THREADED_TEST(FunctionLookup) {
4485 v8::RegisterExtension(new FunctionExtension());
4486 v8::HandleScope handle_scope;
4487 static const char* exts[1] = { "functiontest" };
4488 v8::ExtensionConfiguration config(1, exts);
4489 LocalContext context(&config);
4490 CHECK_EQ(3, lookup_count);
4491 CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
4492 CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
4493 CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
4494}
4495
4496
Leon Clarkee46be812010-01-19 14:06:41 +00004497THREADED_TEST(NativeFunctionConstructCall) {
4498 v8::RegisterExtension(new FunctionExtension());
4499 v8::HandleScope handle_scope;
4500 static const char* exts[1] = { "functiontest" };
4501 v8::ExtensionConfiguration config(1, exts);
4502 LocalContext context(&config);
Leon Clarked91b9f72010-01-27 17:25:45 +00004503 for (int i = 0; i < 10; i++) {
4504 // Run a few times to ensure that allocation of objects doesn't
4505 // change behavior of a constructor function.
4506 CHECK_EQ(v8::Integer::New(8),
4507 Script::Compile(v8_str("(new A()).data"))->Run());
4508 CHECK_EQ(v8::Integer::New(7),
4509 Script::Compile(v8_str("(new B()).data"))->Run());
4510 CHECK_EQ(v8::Integer::New(6),
4511 Script::Compile(v8_str("(new C()).data"))->Run());
4512 }
Leon Clarkee46be812010-01-19 14:06:41 +00004513}
4514
4515
Steve Blocka7e24c12009-10-30 11:49:00 +00004516static const char* last_location;
4517static const char* last_message;
4518void StoringErrorCallback(const char* location, const char* message) {
4519 if (last_location == NULL) {
4520 last_location = location;
4521 last_message = message;
4522 }
4523}
4524
4525
4526// ErrorReporting creates a circular extensions configuration and
4527// tests that the fatal error handler gets called. This renders V8
4528// unusable and therefore this test cannot be run in parallel.
4529TEST(ErrorReporting) {
4530 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
4531 static const char* aDeps[] = { "B" };
4532 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
4533 static const char* bDeps[] = { "A" };
4534 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
4535 last_location = NULL;
4536 v8::ExtensionConfiguration config(1, bDeps);
4537 v8::Handle<Context> context = Context::New(&config);
4538 CHECK(context.IsEmpty());
4539 CHECK_NE(last_location, NULL);
4540}
4541
4542
4543static const char* js_code_causing_huge_string_flattening =
4544 "var str = 'X';"
4545 "for (var i = 0; i < 30; i++) {"
4546 " str = str + str;"
4547 "}"
4548 "str.match(/X/);";
4549
4550
4551void OOMCallback(const char* location, const char* message) {
4552 exit(0);
4553}
4554
4555
4556TEST(RegexpOutOfMemory) {
4557 // Execute a script that causes out of memory when flattening a string.
4558 v8::HandleScope scope;
4559 v8::V8::SetFatalErrorHandler(OOMCallback);
4560 LocalContext context;
4561 Local<Script> script =
4562 Script::Compile(String::New(js_code_causing_huge_string_flattening));
4563 last_location = NULL;
4564 Local<Value> result = script->Run();
4565
4566 CHECK(false); // Should not return.
4567}
4568
4569
4570static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
4571 v8::Handle<Value> data) {
4572 CHECK_EQ(v8::Undefined(), data);
4573 CHECK(message->GetScriptResourceName()->IsUndefined());
4574 CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
4575 message->GetLineNumber();
4576 message->GetSourceLine();
4577}
4578
4579
4580THREADED_TEST(ErrorWithMissingScriptInfo) {
4581 v8::HandleScope scope;
4582 LocalContext context;
4583 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
4584 Script::Compile(v8_str("throw Error()"))->Run();
4585 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
4586}
4587
4588
4589int global_index = 0;
4590
4591class Snorkel {
4592 public:
4593 Snorkel() { index_ = global_index++; }
4594 int index_;
4595};
4596
4597class Whammy {
4598 public:
4599 Whammy() {
4600 cursor_ = 0;
4601 }
4602 ~Whammy() {
4603 script_.Dispose();
4604 }
4605 v8::Handle<Script> getScript() {
4606 if (script_.IsEmpty())
4607 script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
4608 return Local<Script>(*script_);
4609 }
4610
4611 public:
4612 static const int kObjectCount = 256;
4613 int cursor_;
4614 v8::Persistent<v8::Object> objects_[kObjectCount];
4615 v8::Persistent<Script> script_;
4616};
4617
4618static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
4619 Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
4620 delete snorkel;
4621 obj.ClearWeak();
4622}
4623
4624v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
4625 const AccessorInfo& info) {
4626 Whammy* whammy =
4627 static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
4628
4629 v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
4630
4631 v8::Handle<v8::Object> obj = v8::Object::New();
4632 v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
4633 if (!prev.IsEmpty()) {
4634 prev->Set(v8_str("next"), obj);
4635 prev.MakeWeak(new Snorkel(), &HandleWeakReference);
4636 whammy->objects_[whammy->cursor_].Clear();
4637 }
4638 whammy->objects_[whammy->cursor_] = global;
4639 whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
4640 return whammy->getScript()->Run();
4641}
4642
4643THREADED_TEST(WeakReference) {
4644 v8::HandleScope handle_scope;
4645 v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
Ben Murdoch3bec4d22010-07-22 14:51:16 +01004646 Whammy* whammy = new Whammy();
Steve Blocka7e24c12009-10-30 11:49:00 +00004647 templ->SetNamedPropertyHandler(WhammyPropertyGetter,
4648 0, 0, 0, 0,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01004649 v8::External::New(whammy));
Steve Blocka7e24c12009-10-30 11:49:00 +00004650 const char* extension_list[] = { "v8/gc" };
4651 v8::ExtensionConfiguration extensions(1, extension_list);
4652 v8::Persistent<Context> context = Context::New(&extensions);
4653 Context::Scope context_scope(context);
4654
4655 v8::Handle<v8::Object> interceptor = templ->NewInstance();
4656 context->Global()->Set(v8_str("whammy"), interceptor);
4657 const char* code =
4658 "var last;"
4659 "for (var i = 0; i < 10000; i++) {"
4660 " var obj = whammy.length;"
4661 " if (last) last.next = obj;"
4662 " last = obj;"
4663 "}"
4664 "gc();"
4665 "4";
4666 v8::Handle<Value> result = CompileRun(code);
4667 CHECK_EQ(4.0, result->NumberValue());
Ben Murdoch3bec4d22010-07-22 14:51:16 +01004668 delete whammy;
Steve Blocka7e24c12009-10-30 11:49:00 +00004669 context.Dispose();
4670}
4671
4672
Ben Murdoch257744e2011-11-30 15:57:28 +00004673static void DisposeAndSetFlag(v8::Persistent<v8::Value> obj, void* data) {
Steve Blockd0582a62009-12-15 09:54:21 +00004674 obj.Dispose();
4675 obj.Clear();
Steve Blockd0582a62009-12-15 09:54:21 +00004676 *(reinterpret_cast<bool*>(data)) = true;
4677}
4678
Steve Blockd0582a62009-12-15 09:54:21 +00004679
Ben Murdoch257744e2011-11-30 15:57:28 +00004680THREADED_TEST(IndependentWeakHandle) {
Steve Blockd0582a62009-12-15 09:54:21 +00004681 v8::Persistent<Context> context = Context::New();
4682 Context::Scope context_scope(context);
4683
4684 v8::Persistent<v8::Object> object_a;
Steve Blockd0582a62009-12-15 09:54:21 +00004685
4686 {
4687 v8::HandleScope handle_scope;
Steve Blockd0582a62009-12-15 09:54:21 +00004688 object_a = v8::Persistent<v8::Object>::New(v8::Object::New());
4689 }
4690
4691 bool object_a_disposed = false;
Ben Murdoch257744e2011-11-30 15:57:28 +00004692 object_a.MakeWeak(&object_a_disposed, &DisposeAndSetFlag);
4693 object_a.MarkIndependent();
4694 HEAP->PerformScavenge();
4695 CHECK(object_a_disposed);
4696}
Steve Blockd0582a62009-12-15 09:54:21 +00004697
Ben Murdoch257744e2011-11-30 15:57:28 +00004698
4699static void InvokeScavenge() {
4700 HEAP->PerformScavenge();
4701}
4702
4703
4704static void InvokeMarkSweep() {
4705 HEAP->CollectAllGarbage(false);
4706}
4707
4708
4709static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
4710 obj.Dispose();
4711 obj.Clear();
4712 *(reinterpret_cast<bool*>(data)) = true;
4713 InvokeScavenge();
4714}
4715
4716
4717static void ForceMarkSweep(v8::Persistent<v8::Value> obj, void* data) {
4718 obj.Dispose();
4719 obj.Clear();
4720 *(reinterpret_cast<bool*>(data)) = true;
4721 InvokeMarkSweep();
4722}
4723
4724
4725THREADED_TEST(GCFromWeakCallbacks) {
4726 v8::Persistent<Context> context = Context::New();
4727 Context::Scope context_scope(context);
4728
4729 static const int kNumberOfGCTypes = 2;
4730 v8::WeakReferenceCallback gc_forcing_callback[kNumberOfGCTypes] =
4731 {&ForceScavenge, &ForceMarkSweep};
4732
4733 typedef void (*GCInvoker)();
4734 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
4735
4736 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
4737 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
4738 v8::Persistent<v8::Object> object;
4739 {
4740 v8::HandleScope handle_scope;
4741 object = v8::Persistent<v8::Object>::New(v8::Object::New());
4742 }
4743 bool disposed = false;
4744 object.MakeWeak(&disposed, gc_forcing_callback[inner_gc]);
4745 object.MarkIndependent();
4746 invoke_gc[outer_gc]();
4747 CHECK(disposed);
4748 }
Steve Blockd0582a62009-12-15 09:54:21 +00004749 }
Ben Murdoch257744e2011-11-30 15:57:28 +00004750}
4751
4752
4753static void RevivingCallback(v8::Persistent<v8::Value> obj, void* data) {
4754 obj.ClearWeak();
4755 *(reinterpret_cast<bool*>(data)) = true;
4756}
4757
4758
4759THREADED_TEST(IndependentHandleRevival) {
4760 v8::Persistent<Context> context = Context::New();
4761 Context::Scope context_scope(context);
4762
4763 v8::Persistent<v8::Object> object;
4764 {
4765 v8::HandleScope handle_scope;
4766 object = v8::Persistent<v8::Object>::New(v8::Object::New());
4767 object->Set(v8_str("x"), v8::Integer::New(1));
4768 v8::Local<String> y_str = v8_str("y");
4769 object->Set(y_str, y_str);
4770 }
4771 bool revived = false;
4772 object.MakeWeak(&revived, &RevivingCallback);
4773 object.MarkIndependent();
4774 HEAP->PerformScavenge();
4775 CHECK(revived);
4776 HEAP->CollectAllGarbage(true);
4777 {
4778 v8::HandleScope handle_scope;
4779 v8::Local<String> y_str = v8_str("y");
4780 CHECK_EQ(v8::Integer::New(1), object->Get(v8_str("x")));
4781 CHECK(object->Get(y_str)->Equals(y_str));
4782 }
Steve Blockd0582a62009-12-15 09:54:21 +00004783}
4784
4785
Steve Blocka7e24c12009-10-30 11:49:00 +00004786v8::Handle<Function> args_fun;
4787
4788
4789static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
4790 ApiTestFuzzer::Fuzz();
4791 CHECK_EQ(args_fun, args.Callee());
4792 CHECK_EQ(3, args.Length());
4793 CHECK_EQ(v8::Integer::New(1), args[0]);
4794 CHECK_EQ(v8::Integer::New(2), args[1]);
4795 CHECK_EQ(v8::Integer::New(3), args[2]);
4796 CHECK_EQ(v8::Undefined(), args[3]);
4797 v8::HandleScope scope;
Steve Block44f0eee2011-05-26 01:26:41 +01004798 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +00004799 return v8::Undefined();
4800}
4801
4802
4803THREADED_TEST(Arguments) {
4804 v8::HandleScope scope;
4805 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
4806 global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
4807 LocalContext context(NULL, global);
Steve Block6ded16b2010-05-10 14:33:55 +01004808 args_fun = context->Global()->Get(v8_str("f")).As<Function>();
Steve Blocka7e24c12009-10-30 11:49:00 +00004809 v8_compile("f(1, 2, 3)")->Run();
4810}
4811
4812
Steve Blocka7e24c12009-10-30 11:49:00 +00004813static v8::Handle<Value> NoBlockGetterX(Local<String> name,
4814 const AccessorInfo&) {
4815 return v8::Handle<Value>();
4816}
4817
4818
4819static v8::Handle<Value> NoBlockGetterI(uint32_t index,
4820 const AccessorInfo&) {
4821 return v8::Handle<Value>();
4822}
4823
4824
4825static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
4826 const AccessorInfo&) {
4827 if (!name->Equals(v8_str("foo"))) {
4828 return v8::Handle<v8::Boolean>(); // not intercepted
4829 }
4830
4831 return v8::False(); // intercepted, and don't delete the property
4832}
4833
4834
4835static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
4836 if (index != 2) {
4837 return v8::Handle<v8::Boolean>(); // not intercepted
4838 }
4839
4840 return v8::False(); // intercepted, and don't delete the property
4841}
4842
4843
4844THREADED_TEST(Deleter) {
4845 v8::HandleScope scope;
4846 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4847 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
4848 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
4849 LocalContext context;
4850 context->Global()->Set(v8_str("k"), obj->NewInstance());
4851 CompileRun(
4852 "k.foo = 'foo';"
4853 "k.bar = 'bar';"
4854 "k[2] = 2;"
4855 "k[4] = 4;");
4856 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
4857 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
4858
4859 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
4860 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
4861
4862 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
4863 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
4864
4865 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
4866 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
4867}
4868
4869
4870static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
4871 ApiTestFuzzer::Fuzz();
4872 if (name->Equals(v8_str("foo")) ||
4873 name->Equals(v8_str("bar")) ||
4874 name->Equals(v8_str("baz"))) {
4875 return v8::Undefined();
4876 }
4877 return v8::Handle<Value>();
4878}
4879
4880
4881static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
4882 ApiTestFuzzer::Fuzz();
4883 if (index == 0 || index == 1) return v8::Undefined();
4884 return v8::Handle<Value>();
4885}
4886
4887
4888static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
4889 ApiTestFuzzer::Fuzz();
4890 v8::Handle<v8::Array> result = v8::Array::New(3);
4891 result->Set(v8::Integer::New(0), v8_str("foo"));
4892 result->Set(v8::Integer::New(1), v8_str("bar"));
4893 result->Set(v8::Integer::New(2), v8_str("baz"));
4894 return result;
4895}
4896
4897
4898static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
4899 ApiTestFuzzer::Fuzz();
4900 v8::Handle<v8::Array> result = v8::Array::New(2);
4901 result->Set(v8::Integer::New(0), v8_str("0"));
4902 result->Set(v8::Integer::New(1), v8_str("1"));
4903 return result;
4904}
4905
4906
4907THREADED_TEST(Enumerators) {
4908 v8::HandleScope scope;
4909 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4910 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
4911 obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
4912 LocalContext context;
4913 context->Global()->Set(v8_str("k"), obj->NewInstance());
4914 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
4915 "k[10] = 0;"
4916 "k.a = 0;"
4917 "k[5] = 0;"
4918 "k.b = 0;"
4919 "k[4294967295] = 0;"
4920 "k.c = 0;"
4921 "k[4294967296] = 0;"
4922 "k.d = 0;"
4923 "k[140000] = 0;"
4924 "k.e = 0;"
4925 "k[30000000000] = 0;"
4926 "k.f = 0;"
4927 "var result = [];"
4928 "for (var prop in k) {"
4929 " result.push(prop);"
4930 "}"
4931 "result"));
4932 // Check that we get all the property names returned including the
4933 // ones from the enumerators in the right order: indexed properties
4934 // in numerical order, indexed interceptor properties, named
4935 // properties in insertion order, named interceptor properties.
4936 // This order is not mandated by the spec, so this test is just
4937 // documenting our behavior.
4938 CHECK_EQ(17, result->Length());
4939 // Indexed properties in numerical order.
4940 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
4941 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
4942 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
4943 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
4944 // Indexed interceptor properties in the order they are returned
4945 // from the enumerator interceptor.
4946 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
4947 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
4948 // Named properties in insertion order.
4949 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
4950 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
4951 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
4952 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
4953 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
4954 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
4955 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
4956 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
4957 // Named interceptor properties.
4958 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
4959 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
4960 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
4961}
4962
4963
4964int p_getter_count;
4965int p_getter_count2;
4966
4967
4968static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
4969 ApiTestFuzzer::Fuzz();
4970 p_getter_count++;
4971 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
4972 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
4973 if (name->Equals(v8_str("p1"))) {
4974 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
4975 } else if (name->Equals(v8_str("p2"))) {
4976 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
4977 } else if (name->Equals(v8_str("p3"))) {
4978 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
4979 } else if (name->Equals(v8_str("p4"))) {
4980 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
4981 }
4982 return v8::Undefined();
4983}
4984
4985
4986static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
4987 ApiTestFuzzer::Fuzz();
4988 LocalContext context;
4989 context->Global()->Set(v8_str("o1"), obj->NewInstance());
4990 CompileRun(
4991 "o1.__proto__ = { };"
4992 "var o2 = { __proto__: o1 };"
4993 "var o3 = { __proto__: o2 };"
4994 "var o4 = { __proto__: o3 };"
4995 "for (var i = 0; i < 10; i++) o4.p4;"
4996 "for (var i = 0; i < 10; i++) o3.p3;"
4997 "for (var i = 0; i < 10; i++) o2.p2;"
4998 "for (var i = 0; i < 10; i++) o1.p1;");
4999}
5000
5001
5002static v8::Handle<Value> PGetter2(Local<String> name,
5003 const AccessorInfo& info) {
5004 ApiTestFuzzer::Fuzz();
5005 p_getter_count2++;
5006 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5007 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
5008 if (name->Equals(v8_str("p1"))) {
5009 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
5010 } else if (name->Equals(v8_str("p2"))) {
5011 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
5012 } else if (name->Equals(v8_str("p3"))) {
5013 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
5014 } else if (name->Equals(v8_str("p4"))) {
5015 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
5016 }
5017 return v8::Undefined();
5018}
5019
5020
5021THREADED_TEST(GetterHolders) {
5022 v8::HandleScope scope;
5023 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5024 obj->SetAccessor(v8_str("p1"), PGetter);
5025 obj->SetAccessor(v8_str("p2"), PGetter);
5026 obj->SetAccessor(v8_str("p3"), PGetter);
5027 obj->SetAccessor(v8_str("p4"), PGetter);
5028 p_getter_count = 0;
5029 RunHolderTest(obj);
5030 CHECK_EQ(40, p_getter_count);
5031}
5032
5033
5034THREADED_TEST(PreInterceptorHolders) {
5035 v8::HandleScope scope;
5036 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5037 obj->SetNamedPropertyHandler(PGetter2);
5038 p_getter_count2 = 0;
5039 RunHolderTest(obj);
5040 CHECK_EQ(40, p_getter_count2);
5041}
5042
5043
5044THREADED_TEST(ObjectInstantiation) {
5045 v8::HandleScope scope;
5046 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5047 templ->SetAccessor(v8_str("t"), PGetter2);
5048 LocalContext context;
5049 context->Global()->Set(v8_str("o"), templ->NewInstance());
5050 for (int i = 0; i < 100; i++) {
5051 v8::HandleScope inner_scope;
5052 v8::Handle<v8::Object> obj = templ->NewInstance();
5053 CHECK_NE(obj, context->Global()->Get(v8_str("o")));
5054 context->Global()->Set(v8_str("o2"), obj);
5055 v8::Handle<Value> value =
5056 Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
5057 CHECK_EQ(v8::True(), value);
5058 context->Global()->Set(v8_str("o"), obj);
5059 }
5060}
5061
5062
Ben Murdochb0fe1622011-05-05 13:52:32 +01005063static int StrCmp16(uint16_t* a, uint16_t* b) {
5064 while (true) {
5065 if (*a == 0 && *b == 0) return 0;
5066 if (*a != *b) return 0 + *a - *b;
5067 a++;
5068 b++;
5069 }
5070}
5071
5072
5073static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
5074 while (true) {
5075 if (n-- == 0) return 0;
5076 if (*a == 0 && *b == 0) return 0;
5077 if (*a != *b) return 0 + *a - *b;
5078 a++;
5079 b++;
5080 }
5081}
5082
5083
Steve Blocka7e24c12009-10-30 11:49:00 +00005084THREADED_TEST(StringWrite) {
5085 v8::HandleScope scope;
5086 v8::Handle<String> str = v8_str("abcde");
Ben Murdochb0fe1622011-05-05 13:52:32 +01005087 // abc<Icelandic eth><Unicode snowman>.
5088 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
5089
5090 CHECK_EQ(5, str2->Length());
Steve Blocka7e24c12009-10-30 11:49:00 +00005091
5092 char buf[100];
Ben Murdochb0fe1622011-05-05 13:52:32 +01005093 char utf8buf[100];
5094 uint16_t wbuf[100];
Steve Blocka7e24c12009-10-30 11:49:00 +00005095 int len;
Ben Murdochb0fe1622011-05-05 13:52:32 +01005096 int charlen;
5097
5098 memset(utf8buf, 0x1, sizeof(utf8buf));
5099 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01005100 CHECK_EQ(9, len);
5101 CHECK_EQ(5, charlen);
5102 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005103
5104 memset(utf8buf, 0x1, sizeof(utf8buf));
5105 len = str2->WriteUtf8(utf8buf, 8, &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01005106 CHECK_EQ(8, len);
5107 CHECK_EQ(5, charlen);
5108 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005109
5110 memset(utf8buf, 0x1, sizeof(utf8buf));
5111 len = str2->WriteUtf8(utf8buf, 7, &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01005112 CHECK_EQ(5, len);
5113 CHECK_EQ(4, charlen);
5114 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005115
5116 memset(utf8buf, 0x1, sizeof(utf8buf));
5117 len = str2->WriteUtf8(utf8buf, 6, &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01005118 CHECK_EQ(5, len);
5119 CHECK_EQ(4, charlen);
5120 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005121
5122 memset(utf8buf, 0x1, sizeof(utf8buf));
5123 len = str2->WriteUtf8(utf8buf, 5, &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01005124 CHECK_EQ(5, len);
5125 CHECK_EQ(4, charlen);
5126 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005127
5128 memset(utf8buf, 0x1, sizeof(utf8buf));
5129 len = str2->WriteUtf8(utf8buf, 4, &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01005130 CHECK_EQ(3, len);
5131 CHECK_EQ(3, charlen);
5132 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005133
5134 memset(utf8buf, 0x1, sizeof(utf8buf));
5135 len = str2->WriteUtf8(utf8buf, 3, &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01005136 CHECK_EQ(3, len);
5137 CHECK_EQ(3, charlen);
5138 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005139
5140 memset(utf8buf, 0x1, sizeof(utf8buf));
5141 len = str2->WriteUtf8(utf8buf, 2, &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01005142 CHECK_EQ(2, len);
5143 CHECK_EQ(2, charlen);
5144 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
Steve Blocka7e24c12009-10-30 11:49:00 +00005145
5146 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005147 memset(wbuf, 0x1, sizeof(wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00005148 len = str->WriteAscii(buf);
Steve Block44f0eee2011-05-26 01:26:41 +01005149 CHECK_EQ(5, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005150 len = str->Write(wbuf);
Steve Block44f0eee2011-05-26 01:26:41 +01005151 CHECK_EQ(5, len);
5152 CHECK_EQ(0, strcmp("abcde", buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005153 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
Steve Block44f0eee2011-05-26 01:26:41 +01005154 CHECK_EQ(0, StrCmp16(answer1, wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00005155
5156 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005157 memset(wbuf, 0x1, sizeof(wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00005158 len = str->WriteAscii(buf, 0, 4);
Steve Block44f0eee2011-05-26 01:26:41 +01005159 CHECK_EQ(4, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005160 len = str->Write(wbuf, 0, 4);
Steve Block44f0eee2011-05-26 01:26:41 +01005161 CHECK_EQ(4, len);
5162 CHECK_EQ(0, strncmp("abcd\1", buf, 5));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005163 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
Steve Block44f0eee2011-05-26 01:26:41 +01005164 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
Steve Blocka7e24c12009-10-30 11:49:00 +00005165
5166 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005167 memset(wbuf, 0x1, sizeof(wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00005168 len = str->WriteAscii(buf, 0, 5);
Steve Block44f0eee2011-05-26 01:26:41 +01005169 CHECK_EQ(5, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005170 len = str->Write(wbuf, 0, 5);
Steve Block44f0eee2011-05-26 01:26:41 +01005171 CHECK_EQ(5, len);
5172 CHECK_EQ(0, strncmp("abcde\1", buf, 6));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005173 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
Steve Block44f0eee2011-05-26 01:26:41 +01005174 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
Steve Blocka7e24c12009-10-30 11:49:00 +00005175
5176 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005177 memset(wbuf, 0x1, sizeof(wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00005178 len = str->WriteAscii(buf, 0, 6);
Steve Block44f0eee2011-05-26 01:26:41 +01005179 CHECK_EQ(5, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005180 len = str->Write(wbuf, 0, 6);
Steve Block44f0eee2011-05-26 01:26:41 +01005181 CHECK_EQ(5, len);
5182 CHECK_EQ(0, strcmp("abcde", buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005183 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
Steve Block44f0eee2011-05-26 01:26:41 +01005184 CHECK_EQ(0, StrCmp16(answer4, wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00005185
5186 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005187 memset(wbuf, 0x1, sizeof(wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00005188 len = str->WriteAscii(buf, 4, -1);
Steve Block44f0eee2011-05-26 01:26:41 +01005189 CHECK_EQ(1, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005190 len = str->Write(wbuf, 4, -1);
Steve Block44f0eee2011-05-26 01:26:41 +01005191 CHECK_EQ(1, len);
5192 CHECK_EQ(0, strcmp("e", buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005193 uint16_t answer5[] = {'e', '\0'};
Steve Block44f0eee2011-05-26 01:26:41 +01005194 CHECK_EQ(0, StrCmp16(answer5, wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00005195
5196 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005197 memset(wbuf, 0x1, sizeof(wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00005198 len = str->WriteAscii(buf, 4, 6);
Steve Block44f0eee2011-05-26 01:26:41 +01005199 CHECK_EQ(1, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005200 len = str->Write(wbuf, 4, 6);
Steve Block44f0eee2011-05-26 01:26:41 +01005201 CHECK_EQ(1, len);
5202 CHECK_EQ(0, strcmp("e", buf));
5203 CHECK_EQ(0, StrCmp16(answer5, wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00005204
5205 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005206 memset(wbuf, 0x1, sizeof(wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00005207 len = str->WriteAscii(buf, 4, 1);
Steve Block44f0eee2011-05-26 01:26:41 +01005208 CHECK_EQ(1, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005209 len = str->Write(wbuf, 4, 1);
Steve Block44f0eee2011-05-26 01:26:41 +01005210 CHECK_EQ(1, len);
5211 CHECK_EQ(0, strncmp("e\1", buf, 2));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005212 uint16_t answer6[] = {'e', 0x101};
Steve Block44f0eee2011-05-26 01:26:41 +01005213 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005214
5215 memset(buf, 0x1, sizeof(buf));
5216 memset(wbuf, 0x1, sizeof(wbuf));
5217 len = str->WriteAscii(buf, 3, 1);
Steve Block44f0eee2011-05-26 01:26:41 +01005218 CHECK_EQ(1, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005219 len = str->Write(wbuf, 3, 1);
Steve Block44f0eee2011-05-26 01:26:41 +01005220 CHECK_EQ(1, len);
5221 CHECK_EQ(0, strncmp("d\1", buf, 2));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005222 uint16_t answer7[] = {'d', 0x101};
Steve Block44f0eee2011-05-26 01:26:41 +01005223 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
Steve Blocka7e24c12009-10-30 11:49:00 +00005224}
5225
5226
5227THREADED_TEST(ToArrayIndex) {
5228 v8::HandleScope scope;
5229 LocalContext context;
5230
5231 v8::Handle<String> str = v8_str("42");
5232 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
5233 CHECK(!index.IsEmpty());
5234 CHECK_EQ(42.0, index->Uint32Value());
5235 str = v8_str("42asdf");
5236 index = str->ToArrayIndex();
5237 CHECK(index.IsEmpty());
5238 str = v8_str("-42");
5239 index = str->ToArrayIndex();
5240 CHECK(index.IsEmpty());
5241 str = v8_str("4294967295");
5242 index = str->ToArrayIndex();
5243 CHECK(!index.IsEmpty());
5244 CHECK_EQ(4294967295.0, index->Uint32Value());
5245 v8::Handle<v8::Number> num = v8::Number::New(1);
5246 index = num->ToArrayIndex();
5247 CHECK(!index.IsEmpty());
5248 CHECK_EQ(1.0, index->Uint32Value());
5249 num = v8::Number::New(-1);
5250 index = num->ToArrayIndex();
5251 CHECK(index.IsEmpty());
5252 v8::Handle<v8::Object> obj = v8::Object::New();
5253 index = obj->ToArrayIndex();
5254 CHECK(index.IsEmpty());
5255}
5256
5257
5258THREADED_TEST(ErrorConstruction) {
5259 v8::HandleScope scope;
5260 LocalContext context;
5261
5262 v8::Handle<String> foo = v8_str("foo");
5263 v8::Handle<String> message = v8_str("message");
5264 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
5265 CHECK(range_error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01005266 v8::Handle<v8::Object> range_obj = range_error.As<v8::Object>();
5267 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00005268 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
5269 CHECK(reference_error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01005270 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00005271 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
5272 CHECK(syntax_error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01005273 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00005274 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
5275 CHECK(type_error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01005276 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00005277 v8::Handle<Value> error = v8::Exception::Error(foo);
5278 CHECK(error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01005279 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00005280}
5281
5282
5283static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
5284 ApiTestFuzzer::Fuzz();
5285 return v8_num(10);
5286}
5287
5288
5289static void YSetter(Local<String> name,
5290 Local<Value> value,
5291 const AccessorInfo& info) {
5292 if (info.This()->Has(name)) {
5293 info.This()->Delete(name);
5294 }
5295 info.This()->Set(name, value);
5296}
5297
5298
5299THREADED_TEST(DeleteAccessor) {
5300 v8::HandleScope scope;
5301 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5302 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
5303 LocalContext context;
5304 v8::Handle<v8::Object> holder = obj->NewInstance();
5305 context->Global()->Set(v8_str("holder"), holder);
5306 v8::Handle<Value> result = CompileRun(
5307 "holder.y = 11; holder.y = 12; holder.y");
5308 CHECK_EQ(12, result->Uint32Value());
5309}
5310
5311
5312THREADED_TEST(TypeSwitch) {
5313 v8::HandleScope scope;
5314 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
5315 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
5316 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
5317 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
5318 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
5319 LocalContext context;
5320 v8::Handle<v8::Object> obj0 = v8::Object::New();
5321 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
5322 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
5323 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
5324 for (int i = 0; i < 10; i++) {
5325 CHECK_EQ(0, type_switch->match(obj0));
5326 CHECK_EQ(1, type_switch->match(obj1));
5327 CHECK_EQ(2, type_switch->match(obj2));
5328 CHECK_EQ(3, type_switch->match(obj3));
5329 CHECK_EQ(3, type_switch->match(obj3));
5330 CHECK_EQ(2, type_switch->match(obj2));
5331 CHECK_EQ(1, type_switch->match(obj1));
5332 CHECK_EQ(0, type_switch->match(obj0));
5333 }
5334}
5335
5336
5337// For use within the TestSecurityHandler() test.
5338static bool g_security_callback_result = false;
5339static bool NamedSecurityTestCallback(Local<v8::Object> global,
5340 Local<Value> name,
5341 v8::AccessType type,
5342 Local<Value> data) {
5343 // Always allow read access.
5344 if (type == v8::ACCESS_GET)
5345 return true;
5346
5347 // Sometimes allow other access.
5348 return g_security_callback_result;
5349}
5350
5351
5352static bool IndexedSecurityTestCallback(Local<v8::Object> global,
5353 uint32_t key,
5354 v8::AccessType type,
5355 Local<Value> data) {
5356 // Always allow read access.
5357 if (type == v8::ACCESS_GET)
5358 return true;
5359
5360 // Sometimes allow other access.
5361 return g_security_callback_result;
5362}
5363
5364
5365static int trouble_nesting = 0;
5366static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
5367 ApiTestFuzzer::Fuzz();
5368 trouble_nesting++;
5369
5370 // Call a JS function that throws an uncaught exception.
5371 Local<v8::Object> arg_this = Context::GetCurrent()->Global();
5372 Local<Value> trouble_callee = (trouble_nesting == 3) ?
5373 arg_this->Get(v8_str("trouble_callee")) :
5374 arg_this->Get(v8_str("trouble_caller"));
5375 CHECK(trouble_callee->IsFunction());
5376 return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
5377}
5378
5379
5380static int report_count = 0;
5381static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
5382 v8::Handle<Value>) {
5383 report_count++;
5384}
5385
5386
5387// Counts uncaught exceptions, but other tests running in parallel
5388// also have uncaught exceptions.
5389TEST(ApiUncaughtException) {
5390 report_count = 0;
5391 v8::HandleScope scope;
5392 LocalContext env;
5393 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
5394
5395 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
5396 v8::Local<v8::Object> global = env->Global();
5397 global->Set(v8_str("trouble"), fun->GetFunction());
5398
5399 Script::Compile(v8_str("function trouble_callee() {"
5400 " var x = null;"
5401 " return x.foo;"
5402 "};"
5403 "function trouble_caller() {"
5404 " trouble();"
5405 "};"))->Run();
5406 Local<Value> trouble = global->Get(v8_str("trouble"));
5407 CHECK(trouble->IsFunction());
5408 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
5409 CHECK(trouble_callee->IsFunction());
5410 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
5411 CHECK(trouble_caller->IsFunction());
5412 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
5413 CHECK_EQ(1, report_count);
5414 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
5415}
5416
Leon Clarke4515c472010-02-03 11:58:03 +00005417static const char* script_resource_name = "ExceptionInNativeScript.js";
5418static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
5419 v8::Handle<Value>) {
5420 v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
5421 CHECK(!name_val.IsEmpty() && name_val->IsString());
5422 v8::String::AsciiValue name(message->GetScriptResourceName());
5423 CHECK_EQ(script_resource_name, *name);
5424 CHECK_EQ(3, message->GetLineNumber());
5425 v8::String::AsciiValue source_line(message->GetSourceLine());
5426 CHECK_EQ(" new o.foo();", *source_line);
5427}
5428
5429TEST(ExceptionInNativeScript) {
5430 v8::HandleScope scope;
5431 LocalContext env;
5432 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
5433
5434 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
5435 v8::Local<v8::Object> global = env->Global();
5436 global->Set(v8_str("trouble"), fun->GetFunction());
5437
5438 Script::Compile(v8_str("function trouble() {\n"
5439 " var o = {};\n"
5440 " new o.foo();\n"
5441 "};"), v8::String::New(script_resource_name))->Run();
5442 Local<Value> trouble = global->Get(v8_str("trouble"));
5443 CHECK(trouble->IsFunction());
5444 Function::Cast(*trouble)->Call(global, 0, NULL);
5445 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
5446}
5447
Steve Blocka7e24c12009-10-30 11:49:00 +00005448
5449TEST(CompilationErrorUsingTryCatchHandler) {
5450 v8::HandleScope scope;
5451 LocalContext env;
5452 v8::TryCatch try_catch;
5453 Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
5454 CHECK_NE(NULL, *try_catch.Exception());
5455 CHECK(try_catch.HasCaught());
5456}
5457
5458
5459TEST(TryCatchFinallyUsingTryCatchHandler) {
5460 v8::HandleScope scope;
5461 LocalContext env;
5462 v8::TryCatch try_catch;
5463 Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
5464 CHECK(!try_catch.HasCaught());
5465 Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
5466 CHECK(try_catch.HasCaught());
5467 try_catch.Reset();
5468 Script::Compile(v8_str("(function() {"
5469 "try { throw ''; } finally { return; }"
5470 "})()"))->Run();
5471 CHECK(!try_catch.HasCaught());
5472 Script::Compile(v8_str("(function()"
5473 " { try { throw ''; } finally { throw 0; }"
5474 "})()"))->Run();
5475 CHECK(try_catch.HasCaught());
5476}
5477
5478
5479// SecurityHandler can't be run twice
5480TEST(SecurityHandler) {
5481 v8::HandleScope scope0;
5482 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
5483 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
5484 IndexedSecurityTestCallback);
5485 // Create an environment
5486 v8::Persistent<Context> context0 =
5487 Context::New(NULL, global_template);
5488 context0->Enter();
5489
5490 v8::Handle<v8::Object> global0 = context0->Global();
5491 v8::Handle<Script> script0 = v8_compile("foo = 111");
5492 script0->Run();
5493 global0->Set(v8_str("0"), v8_num(999));
5494 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
5495 CHECK_EQ(111, foo0->Int32Value());
5496 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
5497 CHECK_EQ(999, z0->Int32Value());
5498
5499 // Create another environment, should fail security checks.
5500 v8::HandleScope scope1;
5501
5502 v8::Persistent<Context> context1 =
5503 Context::New(NULL, global_template);
5504 context1->Enter();
5505
5506 v8::Handle<v8::Object> global1 = context1->Global();
5507 global1->Set(v8_str("othercontext"), global0);
5508 // This set will fail the security check.
5509 v8::Handle<Script> script1 =
5510 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
5511 script1->Run();
5512 // This read will pass the security check.
5513 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
5514 CHECK_EQ(111, foo1->Int32Value());
5515 // This read will pass the security check.
5516 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
5517 CHECK_EQ(999, z1->Int32Value());
5518
5519 // Create another environment, should pass security checks.
5520 { g_security_callback_result = true; // allow security handler to pass.
5521 v8::HandleScope scope2;
5522 LocalContext context2;
5523 v8::Handle<v8::Object> global2 = context2->Global();
5524 global2->Set(v8_str("othercontext"), global0);
5525 v8::Handle<Script> script2 =
5526 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
5527 script2->Run();
5528 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
5529 CHECK_EQ(333, foo2->Int32Value());
5530 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
5531 CHECK_EQ(888, z2->Int32Value());
5532 }
5533
5534 context1->Exit();
5535 context1.Dispose();
5536
5537 context0->Exit();
5538 context0.Dispose();
5539}
5540
5541
5542THREADED_TEST(SecurityChecks) {
5543 v8::HandleScope handle_scope;
5544 LocalContext env1;
5545 v8::Persistent<Context> env2 = Context::New();
5546
5547 Local<Value> foo = v8_str("foo");
5548 Local<Value> bar = v8_str("bar");
5549
5550 // Set to the same domain.
5551 env1->SetSecurityToken(foo);
5552
5553 // Create a function in env1.
5554 Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
5555 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
5556 CHECK(spy->IsFunction());
5557
5558 // Create another function accessing global objects.
5559 Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
5560 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
5561 CHECK(spy2->IsFunction());
5562
5563 // Switch to env2 in the same domain and invoke spy on env2.
5564 {
5565 env2->SetSecurityToken(foo);
5566 // Enter env2
5567 Context::Scope scope_env2(env2);
5568 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
5569 CHECK(result->IsFunction());
5570 }
5571
5572 {
5573 env2->SetSecurityToken(bar);
5574 Context::Scope scope_env2(env2);
5575
5576 // Call cross_domain_call, it should throw an exception
5577 v8::TryCatch try_catch;
5578 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
5579 CHECK(try_catch.HasCaught());
5580 }
5581
5582 env2.Dispose();
5583}
5584
5585
5586// Regression test case for issue 1183439.
5587THREADED_TEST(SecurityChecksForPrototypeChain) {
5588 v8::HandleScope scope;
5589 LocalContext current;
5590 v8::Persistent<Context> other = Context::New();
5591
5592 // Change context to be able to get to the Object function in the
5593 // other context without hitting the security checks.
5594 v8::Local<Value> other_object;
5595 { Context::Scope scope(other);
5596 other_object = other->Global()->Get(v8_str("Object"));
5597 other->Global()->Set(v8_num(42), v8_num(87));
5598 }
5599
5600 current->Global()->Set(v8_str("other"), other->Global());
5601 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
5602
5603 // Make sure the security check fails here and we get an undefined
5604 // result instead of getting the Object function. Repeat in a loop
5605 // to make sure to exercise the IC code.
5606 v8::Local<Script> access_other0 = v8_compile("other.Object");
5607 v8::Local<Script> access_other1 = v8_compile("other[42]");
5608 for (int i = 0; i < 5; i++) {
5609 CHECK(!access_other0->Run()->Equals(other_object));
5610 CHECK(access_other0->Run()->IsUndefined());
5611 CHECK(!access_other1->Run()->Equals(v8_num(87)));
5612 CHECK(access_other1->Run()->IsUndefined());
5613 }
5614
5615 // Create an object that has 'other' in its prototype chain and make
5616 // sure we cannot access the Object function indirectly through
5617 // that. Repeat in a loop to make sure to exercise the IC code.
5618 v8_compile("function F() { };"
5619 "F.prototype = other;"
5620 "var f = new F();")->Run();
5621 v8::Local<Script> access_f0 = v8_compile("f.Object");
5622 v8::Local<Script> access_f1 = v8_compile("f[42]");
5623 for (int j = 0; j < 5; j++) {
5624 CHECK(!access_f0->Run()->Equals(other_object));
5625 CHECK(access_f0->Run()->IsUndefined());
5626 CHECK(!access_f1->Run()->Equals(v8_num(87)));
5627 CHECK(access_f1->Run()->IsUndefined());
5628 }
5629
5630 // Now it gets hairy: Set the prototype for the other global object
5631 // to be the current global object. The prototype chain for 'f' now
5632 // goes through 'other' but ends up in the current global object.
5633 { Context::Scope scope(other);
5634 other->Global()->Set(v8_str("__proto__"), current->Global());
5635 }
5636 // Set a named and an index property on the current global
5637 // object. To force the lookup to go through the other global object,
5638 // the properties must not exist in the other global object.
5639 current->Global()->Set(v8_str("foo"), v8_num(100));
5640 current->Global()->Set(v8_num(99), v8_num(101));
5641 // Try to read the properties from f and make sure that the access
5642 // gets stopped by the security checks on the other global object.
5643 Local<Script> access_f2 = v8_compile("f.foo");
5644 Local<Script> access_f3 = v8_compile("f[99]");
5645 for (int k = 0; k < 5; k++) {
5646 CHECK(!access_f2->Run()->Equals(v8_num(100)));
5647 CHECK(access_f2->Run()->IsUndefined());
5648 CHECK(!access_f3->Run()->Equals(v8_num(101)));
5649 CHECK(access_f3->Run()->IsUndefined());
5650 }
5651 other.Dispose();
5652}
5653
5654
5655THREADED_TEST(CrossDomainDelete) {
5656 v8::HandleScope handle_scope;
5657 LocalContext env1;
5658 v8::Persistent<Context> env2 = Context::New();
5659
5660 Local<Value> foo = v8_str("foo");
5661 Local<Value> bar = v8_str("bar");
5662
5663 // Set to the same domain.
5664 env1->SetSecurityToken(foo);
5665 env2->SetSecurityToken(foo);
5666
5667 env1->Global()->Set(v8_str("prop"), v8_num(3));
5668 env2->Global()->Set(v8_str("env1"), env1->Global());
5669
5670 // Change env2 to a different domain and delete env1.prop.
5671 env2->SetSecurityToken(bar);
5672 {
5673 Context::Scope scope_env2(env2);
5674 Local<Value> result =
5675 Script::Compile(v8_str("delete env1.prop"))->Run();
5676 CHECK(result->IsFalse());
5677 }
5678
5679 // Check that env1.prop still exists.
5680 Local<Value> v = env1->Global()->Get(v8_str("prop"));
5681 CHECK(v->IsNumber());
5682 CHECK_EQ(3, v->Int32Value());
5683
5684 env2.Dispose();
5685}
5686
5687
5688THREADED_TEST(CrossDomainIsPropertyEnumerable) {
5689 v8::HandleScope handle_scope;
5690 LocalContext env1;
5691 v8::Persistent<Context> env2 = Context::New();
5692
5693 Local<Value> foo = v8_str("foo");
5694 Local<Value> bar = v8_str("bar");
5695
5696 // Set to the same domain.
5697 env1->SetSecurityToken(foo);
5698 env2->SetSecurityToken(foo);
5699
5700 env1->Global()->Set(v8_str("prop"), v8_num(3));
5701 env2->Global()->Set(v8_str("env1"), env1->Global());
5702
5703 // env1.prop is enumerable in env2.
5704 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
5705 {
5706 Context::Scope scope_env2(env2);
5707 Local<Value> result = Script::Compile(test)->Run();
5708 CHECK(result->IsTrue());
5709 }
5710
5711 // Change env2 to a different domain and test again.
5712 env2->SetSecurityToken(bar);
5713 {
5714 Context::Scope scope_env2(env2);
5715 Local<Value> result = Script::Compile(test)->Run();
5716 CHECK(result->IsFalse());
5717 }
5718
5719 env2.Dispose();
5720}
5721
5722
5723THREADED_TEST(CrossDomainForIn) {
5724 v8::HandleScope handle_scope;
5725 LocalContext env1;
5726 v8::Persistent<Context> env2 = Context::New();
5727
5728 Local<Value> foo = v8_str("foo");
5729 Local<Value> bar = v8_str("bar");
5730
5731 // Set to the same domain.
5732 env1->SetSecurityToken(foo);
5733 env2->SetSecurityToken(foo);
5734
5735 env1->Global()->Set(v8_str("prop"), v8_num(3));
5736 env2->Global()->Set(v8_str("env1"), env1->Global());
5737
5738 // Change env2 to a different domain and set env1's global object
5739 // as the __proto__ of an object in env2 and enumerate properties
5740 // in for-in. It shouldn't enumerate properties on env1's global
5741 // object.
5742 env2->SetSecurityToken(bar);
5743 {
5744 Context::Scope scope_env2(env2);
5745 Local<Value> result =
5746 CompileRun("(function(){var obj = {'__proto__':env1};"
5747 "for (var p in obj)"
5748 " if (p == 'prop') return false;"
5749 "return true;})()");
5750 CHECK(result->IsTrue());
5751 }
5752 env2.Dispose();
5753}
5754
5755
5756TEST(ContextDetachGlobal) {
5757 v8::HandleScope handle_scope;
5758 LocalContext env1;
5759 v8::Persistent<Context> env2 = Context::New();
5760
5761 Local<v8::Object> global1 = env1->Global();
5762
5763 Local<Value> foo = v8_str("foo");
5764
5765 // Set to the same domain.
5766 env1->SetSecurityToken(foo);
5767 env2->SetSecurityToken(foo);
5768
5769 // Enter env2
5770 env2->Enter();
5771
Andrei Popescu74b3c142010-03-29 12:03:09 +01005772 // Create a function in env2 and add a reference to it in env1.
Steve Blocka7e24c12009-10-30 11:49:00 +00005773 Local<v8::Object> global2 = env2->Global();
5774 global2->Set(v8_str("prop"), v8::Integer::New(1));
5775 CompileRun("function getProp() {return prop;}");
5776
5777 env1->Global()->Set(v8_str("getProp"),
5778 global2->Get(v8_str("getProp")));
5779
Andrei Popescu74b3c142010-03-29 12:03:09 +01005780 // Detach env2's global, and reuse the global object of env2
Steve Blocka7e24c12009-10-30 11:49:00 +00005781 env2->Exit();
5782 env2->DetachGlobal();
5783 // env2 has a new global object.
5784 CHECK(!env2->Global()->Equals(global2));
5785
5786 v8::Persistent<Context> env3 =
5787 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
5788 env3->SetSecurityToken(v8_str("bar"));
5789 env3->Enter();
5790
5791 Local<v8::Object> global3 = env3->Global();
5792 CHECK_EQ(global2, global3);
5793 CHECK(global3->Get(v8_str("prop"))->IsUndefined());
5794 CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
5795 global3->Set(v8_str("prop"), v8::Integer::New(-1));
5796 global3->Set(v8_str("prop2"), v8::Integer::New(2));
5797 env3->Exit();
5798
5799 // Call getProp in env1, and it should return the value 1
5800 {
5801 Local<Value> get_prop = global1->Get(v8_str("getProp"));
5802 CHECK(get_prop->IsFunction());
5803 v8::TryCatch try_catch;
5804 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
5805 CHECK(!try_catch.HasCaught());
5806 CHECK_EQ(1, r->Int32Value());
5807 }
5808
5809 // Check that env3 is not accessible from env1
5810 {
5811 Local<Value> r = global3->Get(v8_str("prop2"));
5812 CHECK(r->IsUndefined());
5813 }
5814
5815 env2.Dispose();
5816 env3.Dispose();
5817}
5818
5819
Andrei Popescu74b3c142010-03-29 12:03:09 +01005820TEST(DetachAndReattachGlobal) {
5821 v8::HandleScope scope;
5822 LocalContext env1;
5823
5824 // Create second environment.
5825 v8::Persistent<Context> env2 = Context::New();
5826
5827 Local<Value> foo = v8_str("foo");
5828
5829 // Set same security token for env1 and env2.
5830 env1->SetSecurityToken(foo);
5831 env2->SetSecurityToken(foo);
5832
5833 // Create a property on the global object in env2.
5834 {
5835 v8::Context::Scope scope(env2);
5836 env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
5837 }
5838
5839 // Create a reference to env2 global from env1 global.
5840 env1->Global()->Set(v8_str("other"), env2->Global());
5841
5842 // Check that we have access to other.p in env2 from env1.
5843 Local<Value> result = CompileRun("other.p");
5844 CHECK(result->IsInt32());
5845 CHECK_EQ(42, result->Int32Value());
5846
5847 // Hold on to global from env2 and detach global from env2.
5848 Local<v8::Object> global2 = env2->Global();
5849 env2->DetachGlobal();
5850
5851 // Check that the global has been detached. No other.p property can
5852 // be found.
5853 result = CompileRun("other.p");
5854 CHECK(result->IsUndefined());
5855
5856 // Reuse global2 for env3.
5857 v8::Persistent<Context> env3 =
5858 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
5859 CHECK_EQ(global2, env3->Global());
5860
5861 // Start by using the same security token for env3 as for env1 and env2.
5862 env3->SetSecurityToken(foo);
5863
5864 // Create a property on the global object in env3.
5865 {
5866 v8::Context::Scope scope(env3);
5867 env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
5868 }
5869
5870 // Check that other.p is now the property in env3 and that we have access.
5871 result = CompileRun("other.p");
5872 CHECK(result->IsInt32());
5873 CHECK_EQ(24, result->Int32Value());
5874
5875 // Change security token for env3 to something different from env1 and env2.
5876 env3->SetSecurityToken(v8_str("bar"));
5877
5878 // Check that we do not have access to other.p in env1. |other| is now
5879 // the global object for env3 which has a different security token,
5880 // so access should be blocked.
5881 result = CompileRun("other.p");
5882 CHECK(result->IsUndefined());
5883
5884 // Detach the global for env3 and reattach it to env2.
5885 env3->DetachGlobal();
5886 env2->ReattachGlobal(global2);
5887
5888 // Check that we have access to other.p again in env1. |other| is now
5889 // the global object for env2 which has the same security token as env1.
5890 result = CompileRun("other.p");
5891 CHECK(result->IsInt32());
5892 CHECK_EQ(42, result->Int32Value());
5893
5894 env2.Dispose();
5895 env3.Dispose();
5896}
5897
5898
Steve Block1e0659c2011-05-24 12:43:12 +01005899static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
Steve Blocka7e24c12009-10-30 11:49:00 +00005900static bool NamedAccessBlocker(Local<v8::Object> global,
5901 Local<Value> name,
5902 v8::AccessType type,
5903 Local<Value> data) {
Steve Block1e0659c2011-05-24 12:43:12 +01005904 return Context::GetCurrent()->Global()->Equals(global) ||
5905 allowed_access_type[type];
Steve Blocka7e24c12009-10-30 11:49:00 +00005906}
5907
5908
5909static bool IndexedAccessBlocker(Local<v8::Object> global,
5910 uint32_t key,
5911 v8::AccessType type,
5912 Local<Value> data) {
Steve Block1e0659c2011-05-24 12:43:12 +01005913 return Context::GetCurrent()->Global()->Equals(global) ||
5914 allowed_access_type[type];
Steve Blocka7e24c12009-10-30 11:49:00 +00005915}
5916
5917
5918static int g_echo_value = -1;
5919static v8::Handle<Value> EchoGetter(Local<String> name,
5920 const AccessorInfo& info) {
5921 return v8_num(g_echo_value);
5922}
5923
5924
5925static void EchoSetter(Local<String> name,
5926 Local<Value> value,
5927 const AccessorInfo&) {
5928 if (value->IsNumber())
5929 g_echo_value = value->Int32Value();
5930}
5931
5932
5933static v8::Handle<Value> UnreachableGetter(Local<String> name,
5934 const AccessorInfo& info) {
5935 CHECK(false); // This function should not be called..
5936 return v8::Undefined();
5937}
5938
5939
5940static void UnreachableSetter(Local<String>, Local<Value>,
5941 const AccessorInfo&) {
5942 CHECK(false); // This function should nto be called.
5943}
5944
5945
Steve Block1e0659c2011-05-24 12:43:12 +01005946TEST(AccessControl) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005947 v8::HandleScope handle_scope;
5948 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
5949
5950 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
5951 IndexedAccessBlocker);
5952
5953 // Add an accessor accessible by cross-domain JS code.
5954 global_template->SetAccessor(
5955 v8_str("accessible_prop"),
5956 EchoGetter, EchoSetter,
5957 v8::Handle<Value>(),
5958 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
5959
5960 // Add an accessor that is not accessible by cross-domain JS code.
5961 global_template->SetAccessor(v8_str("blocked_prop"),
5962 UnreachableGetter, UnreachableSetter,
5963 v8::Handle<Value>(),
5964 v8::DEFAULT);
5965
5966 // Create an environment
5967 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
5968 context0->Enter();
5969
5970 v8::Handle<v8::Object> global0 = context0->Global();
5971
Steve Block1e0659c2011-05-24 12:43:12 +01005972 // Define a property with JS getter and setter.
5973 CompileRun(
5974 "function getter() { return 'getter'; };\n"
5975 "function setter() { return 'setter'; }\n"
5976 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
5977
5978 Local<Value> getter = global0->Get(v8_str("getter"));
5979 Local<Value> setter = global0->Get(v8_str("setter"));
5980
5981 // And define normal element.
5982 global0->Set(239, v8_str("239"));
5983
5984 // Define an element with JS getter and setter.
5985 CompileRun(
5986 "function el_getter() { return 'el_getter'; };\n"
5987 "function el_setter() { return 'el_setter'; };\n"
5988 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
5989
5990 Local<Value> el_getter = global0->Get(v8_str("el_getter"));
5991 Local<Value> el_setter = global0->Get(v8_str("el_setter"));
5992
Steve Blocka7e24c12009-10-30 11:49:00 +00005993 v8::HandleScope scope1;
5994
5995 v8::Persistent<Context> context1 = Context::New();
5996 context1->Enter();
5997
5998 v8::Handle<v8::Object> global1 = context1->Global();
5999 global1->Set(v8_str("other"), global0);
6000
Steve Block1e0659c2011-05-24 12:43:12 +01006001 // Access blocked property.
6002 CompileRun("other.blocked_prop = 1");
6003
6004 ExpectUndefined("other.blocked_prop");
6005 ExpectUndefined(
6006 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
6007 ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
6008
6009 // Enable ACCESS_HAS
6010 allowed_access_type[v8::ACCESS_HAS] = true;
6011 ExpectUndefined("other.blocked_prop");
6012 // ... and now we can get the descriptor...
6013 ExpectUndefined(
6014 "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
6015 // ... and enumerate the property.
6016 ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
6017 allowed_access_type[v8::ACCESS_HAS] = false;
6018
6019 // Access blocked element.
6020 CompileRun("other[239] = 1");
6021
6022 ExpectUndefined("other[239]");
6023 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
6024 ExpectFalse("propertyIsEnumerable.call(other, '239')");
6025
6026 // Enable ACCESS_HAS
6027 allowed_access_type[v8::ACCESS_HAS] = true;
6028 ExpectUndefined("other[239]");
6029 // ... and now we can get the descriptor...
6030 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
6031 // ... and enumerate the property.
6032 ExpectTrue("propertyIsEnumerable.call(other, '239')");
6033 allowed_access_type[v8::ACCESS_HAS] = false;
6034
6035 // Access a property with JS accessor.
6036 CompileRun("other.js_accessor_p = 2");
6037
6038 ExpectUndefined("other.js_accessor_p");
6039 ExpectUndefined(
6040 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
6041
6042 // Enable ACCESS_HAS.
6043 allowed_access_type[v8::ACCESS_HAS] = true;
6044 ExpectUndefined("other.js_accessor_p");
6045 ExpectUndefined(
6046 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
6047 ExpectUndefined(
6048 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
6049 ExpectUndefined(
6050 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6051 allowed_access_type[v8::ACCESS_HAS] = false;
6052
6053 // Enable both ACCESS_HAS and ACCESS_GET.
6054 allowed_access_type[v8::ACCESS_HAS] = true;
6055 allowed_access_type[v8::ACCESS_GET] = true;
6056
6057 ExpectString("other.js_accessor_p", "getter");
6058 ExpectObject(
6059 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
6060 ExpectUndefined(
6061 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
6062 ExpectUndefined(
6063 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6064
6065 allowed_access_type[v8::ACCESS_GET] = false;
6066 allowed_access_type[v8::ACCESS_HAS] = false;
6067
6068 // Enable both ACCESS_HAS and ACCESS_SET.
6069 allowed_access_type[v8::ACCESS_HAS] = true;
6070 allowed_access_type[v8::ACCESS_SET] = true;
6071
6072 ExpectUndefined("other.js_accessor_p");
6073 ExpectUndefined(
6074 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
6075 ExpectObject(
6076 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
6077 ExpectUndefined(
6078 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6079
6080 allowed_access_type[v8::ACCESS_SET] = false;
6081 allowed_access_type[v8::ACCESS_HAS] = false;
6082
6083 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
6084 allowed_access_type[v8::ACCESS_HAS] = true;
6085 allowed_access_type[v8::ACCESS_GET] = true;
6086 allowed_access_type[v8::ACCESS_SET] = true;
6087
6088 ExpectString("other.js_accessor_p", "getter");
6089 ExpectObject(
6090 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
6091 ExpectObject(
6092 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
6093 ExpectUndefined(
6094 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6095
6096 allowed_access_type[v8::ACCESS_SET] = false;
6097 allowed_access_type[v8::ACCESS_GET] = false;
6098 allowed_access_type[v8::ACCESS_HAS] = false;
6099
6100 // Access an element with JS accessor.
6101 CompileRun("other[42] = 2");
6102
6103 ExpectUndefined("other[42]");
6104 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
6105
6106 // Enable ACCESS_HAS.
6107 allowed_access_type[v8::ACCESS_HAS] = true;
6108 ExpectUndefined("other[42]");
6109 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
6110 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
6111 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6112 allowed_access_type[v8::ACCESS_HAS] = false;
6113
6114 // Enable both ACCESS_HAS and ACCESS_GET.
6115 allowed_access_type[v8::ACCESS_HAS] = true;
6116 allowed_access_type[v8::ACCESS_GET] = true;
6117
6118 ExpectString("other[42]", "el_getter");
6119 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
6120 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
6121 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6122
6123 allowed_access_type[v8::ACCESS_GET] = false;
6124 allowed_access_type[v8::ACCESS_HAS] = false;
6125
6126 // Enable both ACCESS_HAS and ACCESS_SET.
6127 allowed_access_type[v8::ACCESS_HAS] = true;
6128 allowed_access_type[v8::ACCESS_SET] = true;
6129
6130 ExpectUndefined("other[42]");
6131 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
6132 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
6133 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6134
6135 allowed_access_type[v8::ACCESS_SET] = false;
6136 allowed_access_type[v8::ACCESS_HAS] = false;
6137
6138 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
6139 allowed_access_type[v8::ACCESS_HAS] = true;
6140 allowed_access_type[v8::ACCESS_GET] = true;
6141 allowed_access_type[v8::ACCESS_SET] = true;
6142
6143 ExpectString("other[42]", "el_getter");
6144 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
6145 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
6146 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6147
6148 allowed_access_type[v8::ACCESS_SET] = false;
6149 allowed_access_type[v8::ACCESS_GET] = false;
6150 allowed_access_type[v8::ACCESS_HAS] = false;
6151
Steve Blocka7e24c12009-10-30 11:49:00 +00006152 v8::Handle<Value> value;
6153
Steve Blocka7e24c12009-10-30 11:49:00 +00006154 // Access accessible property
Steve Block1e0659c2011-05-24 12:43:12 +01006155 value = CompileRun("other.accessible_prop = 3");
Steve Blocka7e24c12009-10-30 11:49:00 +00006156 CHECK(value->IsNumber());
6157 CHECK_EQ(3, value->Int32Value());
Andrei Popescu31002712010-02-23 13:46:05 +00006158 CHECK_EQ(3, g_echo_value);
Steve Blocka7e24c12009-10-30 11:49:00 +00006159
Steve Block1e0659c2011-05-24 12:43:12 +01006160 value = CompileRun("other.accessible_prop");
Steve Blocka7e24c12009-10-30 11:49:00 +00006161 CHECK(value->IsNumber());
6162 CHECK_EQ(3, value->Int32Value());
6163
Steve Block1e0659c2011-05-24 12:43:12 +01006164 value = CompileRun(
6165 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
6166 CHECK(value->IsNumber());
6167 CHECK_EQ(3, value->Int32Value());
6168
6169 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
Steve Blocka7e24c12009-10-30 11:49:00 +00006170 CHECK(value->IsTrue());
6171
6172 // Enumeration doesn't enumerate accessors from inaccessible objects in
6173 // the prototype chain even if the accessors are in themselves accessible.
Steve Block1e0659c2011-05-24 12:43:12 +01006174 value =
Steve Blocka7e24c12009-10-30 11:49:00 +00006175 CompileRun("(function(){var obj = {'__proto__':other};"
6176 "for (var p in obj)"
6177 " if (p == 'accessible_prop' || p == 'blocked_prop') {"
6178 " return false;"
6179 " }"
6180 "return true;})()");
Steve Block1e0659c2011-05-24 12:43:12 +01006181 CHECK(value->IsTrue());
Steve Blocka7e24c12009-10-30 11:49:00 +00006182
6183 context1->Exit();
6184 context0->Exit();
6185 context1.Dispose();
6186 context0.Dispose();
6187}
6188
6189
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006190TEST(AccessControlES5) {
6191 v8::HandleScope handle_scope;
6192 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
6193
6194 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
6195 IndexedAccessBlocker);
6196
Steve Block44f0eee2011-05-26 01:26:41 +01006197 // Add accessible accessor.
6198 global_template->SetAccessor(
6199 v8_str("accessible_prop"),
6200 EchoGetter, EchoSetter,
6201 v8::Handle<Value>(),
6202 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
6203
6204
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006205 // Add an accessor that is not accessible by cross-domain JS code.
6206 global_template->SetAccessor(v8_str("blocked_prop"),
6207 UnreachableGetter, UnreachableSetter,
6208 v8::Handle<Value>(),
6209 v8::DEFAULT);
6210
6211 // Create an environment
6212 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6213 context0->Enter();
6214
6215 v8::Handle<v8::Object> global0 = context0->Global();
6216
6217 v8::Persistent<Context> context1 = Context::New();
6218 context1->Enter();
6219 v8::Handle<v8::Object> global1 = context1->Global();
6220 global1->Set(v8_str("other"), global0);
6221
6222 // Regression test for issue 1154.
6223 ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
6224
6225 ExpectUndefined("other.blocked_prop");
6226
6227 // Regression test for issue 1027.
6228 CompileRun("Object.defineProperty(\n"
6229 " other, 'blocked_prop', {configurable: false})");
6230 ExpectUndefined("other.blocked_prop");
6231 ExpectUndefined(
6232 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
6233
6234 // Regression test for issue 1171.
6235 ExpectTrue("Object.isExtensible(other)");
6236 CompileRun("Object.preventExtensions(other)");
6237 ExpectTrue("Object.isExtensible(other)");
6238
6239 // Object.seal and Object.freeze.
6240 CompileRun("Object.freeze(other)");
6241 ExpectTrue("Object.isExtensible(other)");
6242
6243 CompileRun("Object.seal(other)");
6244 ExpectTrue("Object.isExtensible(other)");
Steve Block44f0eee2011-05-26 01:26:41 +01006245
6246 // Regression test for issue 1250.
6247 // Make sure that we can set the accessible accessors value using normal
6248 // assignment.
6249 CompileRun("other.accessible_prop = 42");
6250 CHECK_EQ(42, g_echo_value);
6251
6252 v8::Handle<Value> value;
6253 // We follow Safari in ignoring assignments to host object accessors.
6254 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
6255 value = CompileRun("other.accessible_prop == 42");
6256 CHECK(value->IsTrue());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006257}
6258
6259
Leon Clarke4515c472010-02-03 11:58:03 +00006260static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
6261 Local<Value> name,
6262 v8::AccessType type,
6263 Local<Value> data) {
6264 return false;
6265}
6266
6267
6268static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
6269 uint32_t key,
6270 v8::AccessType type,
6271 Local<Value> data) {
6272 return false;
6273}
6274
6275
6276THREADED_TEST(AccessControlGetOwnPropertyNames) {
6277 v8::HandleScope handle_scope;
6278 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
6279
6280 obj_template->Set(v8_str("x"), v8::Integer::New(42));
6281 obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
6282 GetOwnPropertyNamesIndexedBlocker);
6283
6284 // Create an environment
6285 v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
6286 context0->Enter();
6287
6288 v8::Handle<v8::Object> global0 = context0->Global();
6289
6290 v8::HandleScope scope1;
6291
6292 v8::Persistent<Context> context1 = Context::New();
6293 context1->Enter();
6294
6295 v8::Handle<v8::Object> global1 = context1->Global();
6296 global1->Set(v8_str("other"), global0);
6297 global1->Set(v8_str("object"), obj_template->NewInstance());
6298
6299 v8::Handle<Value> value;
6300
6301 // Attempt to get the property names of the other global object and
6302 // of an object that requires access checks. Accessing the other
6303 // global object should be blocked by access checks on the global
6304 // proxy object. Accessing the object that requires access checks
6305 // is blocked by the access checks on the object itself.
6306 value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
6307 CHECK(value->IsTrue());
6308
6309 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
6310 CHECK(value->IsTrue());
6311
6312 context1->Exit();
6313 context0->Exit();
6314 context1.Dispose();
6315 context0.Dispose();
6316}
6317
6318
Steve Block8defd9f2010-07-08 12:39:36 +01006319static v8::Handle<v8::Array> NamedPropertyEnumerator(const AccessorInfo& info) {
6320 v8::Handle<v8::Array> result = v8::Array::New(1);
6321 result->Set(0, v8_str("x"));
6322 return result;
6323}
6324
6325
6326THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
6327 v8::HandleScope handle_scope;
6328 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
6329
6330 obj_template->Set(v8_str("x"), v8::Integer::New(42));
6331 obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
6332 NamedPropertyEnumerator);
6333
6334 LocalContext context;
6335 v8::Handle<v8::Object> global = context->Global();
6336 global->Set(v8_str("object"), obj_template->NewInstance());
6337
6338 v8::Handle<Value> value =
6339 CompileRun("Object.getOwnPropertyNames(object).join(',')");
6340 CHECK_EQ(v8_str("x"), value);
6341}
6342
6343
Steve Blocka7e24c12009-10-30 11:49:00 +00006344static v8::Handle<Value> ConstTenGetter(Local<String> name,
6345 const AccessorInfo& info) {
6346 return v8_num(10);
6347}
6348
6349
6350THREADED_TEST(CrossDomainAccessors) {
6351 v8::HandleScope handle_scope;
6352
6353 v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
6354
6355 v8::Handle<v8::ObjectTemplate> global_template =
6356 func_template->InstanceTemplate();
6357
6358 v8::Handle<v8::ObjectTemplate> proto_template =
6359 func_template->PrototypeTemplate();
6360
6361 // Add an accessor to proto that's accessible by cross-domain JS code.
6362 proto_template->SetAccessor(v8_str("accessible"),
6363 ConstTenGetter, 0,
6364 v8::Handle<Value>(),
6365 v8::ALL_CAN_READ);
6366
6367 // Add an accessor that is not accessible by cross-domain JS code.
6368 global_template->SetAccessor(v8_str("unreachable"),
6369 UnreachableGetter, 0,
6370 v8::Handle<Value>(),
6371 v8::DEFAULT);
6372
6373 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6374 context0->Enter();
6375
6376 Local<v8::Object> global = context0->Global();
6377 // Add a normal property that shadows 'accessible'
6378 global->Set(v8_str("accessible"), v8_num(11));
6379
6380 // Enter a new context.
6381 v8::HandleScope scope1;
6382 v8::Persistent<Context> context1 = Context::New();
6383 context1->Enter();
6384
6385 v8::Handle<v8::Object> global1 = context1->Global();
6386 global1->Set(v8_str("other"), global);
6387
6388 // Should return 10, instead of 11
6389 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
6390 CHECK(value->IsNumber());
6391 CHECK_EQ(10, value->Int32Value());
6392
6393 value = v8_compile("other.unreachable")->Run();
6394 CHECK(value->IsUndefined());
6395
6396 context1->Exit();
6397 context0->Exit();
6398 context1.Dispose();
6399 context0.Dispose();
6400}
6401
6402
6403static int named_access_count = 0;
6404static int indexed_access_count = 0;
6405
6406static bool NamedAccessCounter(Local<v8::Object> global,
6407 Local<Value> name,
6408 v8::AccessType type,
6409 Local<Value> data) {
6410 named_access_count++;
6411 return true;
6412}
6413
6414
6415static bool IndexedAccessCounter(Local<v8::Object> global,
6416 uint32_t key,
6417 v8::AccessType type,
6418 Local<Value> data) {
6419 indexed_access_count++;
6420 return true;
6421}
6422
6423
6424// This one is too easily disturbed by other tests.
6425TEST(AccessControlIC) {
6426 named_access_count = 0;
6427 indexed_access_count = 0;
6428
6429 v8::HandleScope handle_scope;
6430
6431 // Create an environment.
6432 v8::Persistent<Context> context0 = Context::New();
6433 context0->Enter();
6434
6435 // Create an object that requires access-check functions to be
6436 // called for cross-domain access.
6437 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
6438 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
6439 IndexedAccessCounter);
6440 Local<v8::Object> object = object_template->NewInstance();
6441
6442 v8::HandleScope scope1;
6443
6444 // Create another environment.
6445 v8::Persistent<Context> context1 = Context::New();
6446 context1->Enter();
6447
6448 // Make easy access to the object from the other environment.
6449 v8::Handle<v8::Object> global1 = context1->Global();
6450 global1->Set(v8_str("obj"), object);
6451
6452 v8::Handle<Value> value;
6453
6454 // Check that the named access-control function is called every time.
6455 CompileRun("function testProp(obj) {"
6456 " for (var i = 0; i < 10; i++) obj.prop = 1;"
6457 " for (var j = 0; j < 10; j++) obj.prop;"
6458 " return obj.prop"
6459 "}");
6460 value = CompileRun("testProp(obj)");
6461 CHECK(value->IsNumber());
6462 CHECK_EQ(1, value->Int32Value());
6463 CHECK_EQ(21, named_access_count);
6464
6465 // Check that the named access-control function is called every time.
6466 CompileRun("var p = 'prop';"
6467 "function testKeyed(obj) {"
6468 " for (var i = 0; i < 10; i++) obj[p] = 1;"
6469 " for (var j = 0; j < 10; j++) obj[p];"
6470 " return obj[p];"
6471 "}");
6472 // Use obj which requires access checks. No inline caching is used
6473 // in that case.
6474 value = CompileRun("testKeyed(obj)");
6475 CHECK(value->IsNumber());
6476 CHECK_EQ(1, value->Int32Value());
6477 CHECK_EQ(42, named_access_count);
6478 // Force the inline caches into generic state and try again.
6479 CompileRun("testKeyed({ a: 0 })");
6480 CompileRun("testKeyed({ b: 0 })");
6481 value = CompileRun("testKeyed(obj)");
6482 CHECK(value->IsNumber());
6483 CHECK_EQ(1, value->Int32Value());
6484 CHECK_EQ(63, named_access_count);
6485
6486 // Check that the indexed access-control function is called every time.
6487 CompileRun("function testIndexed(obj) {"
6488 " for (var i = 0; i < 10; i++) obj[0] = 1;"
6489 " for (var j = 0; j < 10; j++) obj[0];"
6490 " return obj[0]"
6491 "}");
6492 value = CompileRun("testIndexed(obj)");
6493 CHECK(value->IsNumber());
6494 CHECK_EQ(1, value->Int32Value());
6495 CHECK_EQ(21, indexed_access_count);
6496 // Force the inline caches into generic state.
6497 CompileRun("testIndexed(new Array(1))");
6498 // Test that the indexed access check is called.
6499 value = CompileRun("testIndexed(obj)");
6500 CHECK(value->IsNumber());
6501 CHECK_EQ(1, value->Int32Value());
6502 CHECK_EQ(42, indexed_access_count);
6503
6504 // Check that the named access check is called when invoking
6505 // functions on an object that requires access checks.
6506 CompileRun("obj.f = function() {}");
6507 CompileRun("function testCallNormal(obj) {"
6508 " for (var i = 0; i < 10; i++) obj.f();"
6509 "}");
6510 CompileRun("testCallNormal(obj)");
6511 CHECK_EQ(74, named_access_count);
6512
6513 // Force obj into slow case.
6514 value = CompileRun("delete obj.prop");
6515 CHECK(value->BooleanValue());
6516 // Force inline caches into dictionary probing mode.
6517 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
6518 // Test that the named access check is called.
6519 value = CompileRun("testProp(obj);");
6520 CHECK(value->IsNumber());
6521 CHECK_EQ(1, value->Int32Value());
6522 CHECK_EQ(96, named_access_count);
6523
6524 // Force the call inline cache into dictionary probing mode.
6525 CompileRun("o.f = function() {}; testCallNormal(o)");
6526 // Test that the named access check is still called for each
6527 // invocation of the function.
6528 value = CompileRun("testCallNormal(obj)");
6529 CHECK_EQ(106, named_access_count);
6530
6531 context1->Exit();
6532 context0->Exit();
6533 context1.Dispose();
6534 context0.Dispose();
6535}
6536
6537
6538static bool NamedAccessFlatten(Local<v8::Object> global,
6539 Local<Value> name,
6540 v8::AccessType type,
6541 Local<Value> data) {
6542 char buf[100];
6543 int len;
6544
6545 CHECK(name->IsString());
6546
6547 memset(buf, 0x1, sizeof(buf));
Steve Block6ded16b2010-05-10 14:33:55 +01006548 len = name.As<String>()->WriteAscii(buf);
Steve Blocka7e24c12009-10-30 11:49:00 +00006549 CHECK_EQ(4, len);
6550
6551 uint16_t buf2[100];
6552
6553 memset(buf, 0x1, sizeof(buf));
Steve Block6ded16b2010-05-10 14:33:55 +01006554 len = name.As<String>()->Write(buf2);
Steve Blocka7e24c12009-10-30 11:49:00 +00006555 CHECK_EQ(4, len);
6556
6557 return true;
6558}
6559
6560
6561static bool IndexedAccessFlatten(Local<v8::Object> global,
6562 uint32_t key,
6563 v8::AccessType type,
6564 Local<Value> data) {
6565 return true;
6566}
6567
6568
6569// Regression test. In access checks, operations that may cause
6570// garbage collection are not allowed. It used to be the case that
6571// using the Write operation on a string could cause a garbage
6572// collection due to flattening of the string. This is no longer the
6573// case.
6574THREADED_TEST(AccessControlFlatten) {
6575 named_access_count = 0;
6576 indexed_access_count = 0;
6577
6578 v8::HandleScope handle_scope;
6579
6580 // Create an environment.
6581 v8::Persistent<Context> context0 = Context::New();
6582 context0->Enter();
6583
6584 // Create an object that requires access-check functions to be
6585 // called for cross-domain access.
6586 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
6587 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
6588 IndexedAccessFlatten);
6589 Local<v8::Object> object = object_template->NewInstance();
6590
6591 v8::HandleScope scope1;
6592
6593 // Create another environment.
6594 v8::Persistent<Context> context1 = Context::New();
6595 context1->Enter();
6596
6597 // Make easy access to the object from the other environment.
6598 v8::Handle<v8::Object> global1 = context1->Global();
6599 global1->Set(v8_str("obj"), object);
6600
6601 v8::Handle<Value> value;
6602
6603 value = v8_compile("var p = 'as' + 'df';")->Run();
6604 value = v8_compile("obj[p];")->Run();
6605
6606 context1->Exit();
6607 context0->Exit();
6608 context1.Dispose();
6609 context0.Dispose();
6610}
6611
6612
6613static v8::Handle<Value> AccessControlNamedGetter(
6614 Local<String>, const AccessorInfo&) {
6615 return v8::Integer::New(42);
6616}
6617
6618
6619static v8::Handle<Value> AccessControlNamedSetter(
6620 Local<String>, Local<Value> value, const AccessorInfo&) {
6621 return value;
6622}
6623
6624
6625static v8::Handle<Value> AccessControlIndexedGetter(
6626 uint32_t index,
6627 const AccessorInfo& info) {
6628 return v8_num(42);
6629}
6630
6631
6632static v8::Handle<Value> AccessControlIndexedSetter(
6633 uint32_t, Local<Value> value, const AccessorInfo&) {
6634 return value;
6635}
6636
6637
6638THREADED_TEST(AccessControlInterceptorIC) {
6639 named_access_count = 0;
6640 indexed_access_count = 0;
6641
6642 v8::HandleScope handle_scope;
6643
6644 // Create an environment.
6645 v8::Persistent<Context> context0 = Context::New();
6646 context0->Enter();
6647
6648 // Create an object that requires access-check functions to be
6649 // called for cross-domain access. The object also has interceptors
6650 // interceptor.
6651 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
6652 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
6653 IndexedAccessCounter);
6654 object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
6655 AccessControlNamedSetter);
6656 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
6657 AccessControlIndexedSetter);
6658 Local<v8::Object> object = object_template->NewInstance();
6659
6660 v8::HandleScope scope1;
6661
6662 // Create another environment.
6663 v8::Persistent<Context> context1 = Context::New();
6664 context1->Enter();
6665
6666 // Make easy access to the object from the other environment.
6667 v8::Handle<v8::Object> global1 = context1->Global();
6668 global1->Set(v8_str("obj"), object);
6669
6670 v8::Handle<Value> value;
6671
6672 // Check that the named access-control function is called every time
6673 // eventhough there is an interceptor on the object.
6674 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
6675 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
6676 "obj.x")->Run();
6677 CHECK(value->IsNumber());
6678 CHECK_EQ(42, value->Int32Value());
6679 CHECK_EQ(21, named_access_count);
6680
6681 value = v8_compile("var p = 'x';")->Run();
6682 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
6683 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
6684 "obj[p]")->Run();
6685 CHECK(value->IsNumber());
6686 CHECK_EQ(42, value->Int32Value());
6687 CHECK_EQ(42, named_access_count);
6688
6689 // Check that the indexed access-control function is called every
6690 // time eventhough there is an interceptor on the object.
6691 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
6692 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
6693 "obj[0]")->Run();
6694 CHECK(value->IsNumber());
6695 CHECK_EQ(42, value->Int32Value());
6696 CHECK_EQ(21, indexed_access_count);
6697
6698 context1->Exit();
6699 context0->Exit();
6700 context1.Dispose();
6701 context0.Dispose();
6702}
6703
6704
6705THREADED_TEST(Version) {
6706 v8::V8::GetVersion();
6707}
6708
6709
6710static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
6711 ApiTestFuzzer::Fuzz();
6712 return v8_num(12);
6713}
6714
6715
6716THREADED_TEST(InstanceProperties) {
6717 v8::HandleScope handle_scope;
6718 LocalContext context;
6719
6720 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6721 Local<ObjectTemplate> instance = t->InstanceTemplate();
6722
6723 instance->Set(v8_str("x"), v8_num(42));
6724 instance->Set(v8_str("f"),
6725 v8::FunctionTemplate::New(InstanceFunctionCallback));
6726
6727 Local<Value> o = t->GetFunction()->NewInstance();
6728
6729 context->Global()->Set(v8_str("i"), o);
6730 Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
6731 CHECK_EQ(42, value->Int32Value());
6732
6733 value = Script::Compile(v8_str("i.f()"))->Run();
6734 CHECK_EQ(12, value->Int32Value());
6735}
6736
6737
6738static v8::Handle<Value>
6739GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
6740 ApiTestFuzzer::Fuzz();
6741 return v8::Handle<Value>();
6742}
6743
6744
6745THREADED_TEST(GlobalObjectInstanceProperties) {
6746 v8::HandleScope handle_scope;
6747
6748 Local<Value> global_object;
6749
6750 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6751 t->InstanceTemplate()->SetNamedPropertyHandler(
6752 GlobalObjectInstancePropertiesGet);
6753 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
6754 instance_template->Set(v8_str("x"), v8_num(42));
6755 instance_template->Set(v8_str("f"),
6756 v8::FunctionTemplate::New(InstanceFunctionCallback));
6757
Ben Murdochb0fe1622011-05-05 13:52:32 +01006758 // The script to check how Crankshaft compiles missing global function
6759 // invocations. function g is not defined and should throw on call.
6760 const char* script =
6761 "function wrapper(call) {"
6762 " var x = 0, y = 1;"
6763 " for (var i = 0; i < 1000; i++) {"
6764 " x += i * 100;"
6765 " y += i * 100;"
6766 " }"
6767 " if (call) g();"
6768 "}"
6769 "for (var i = 0; i < 17; i++) wrapper(false);"
6770 "var thrown = 0;"
6771 "try { wrapper(true); } catch (e) { thrown = 1; };"
6772 "thrown";
6773
Steve Blocka7e24c12009-10-30 11:49:00 +00006774 {
6775 LocalContext env(NULL, instance_template);
6776 // Hold on to the global object so it can be used again in another
6777 // environment initialization.
6778 global_object = env->Global();
6779
6780 Local<Value> value = Script::Compile(v8_str("x"))->Run();
6781 CHECK_EQ(42, value->Int32Value());
6782 value = Script::Compile(v8_str("f()"))->Run();
6783 CHECK_EQ(12, value->Int32Value());
Ben Murdochb0fe1622011-05-05 13:52:32 +01006784 value = Script::Compile(v8_str(script))->Run();
6785 CHECK_EQ(1, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00006786 }
6787
6788 {
6789 // Create new environment reusing the global object.
6790 LocalContext env(NULL, instance_template, global_object);
6791 Local<Value> value = Script::Compile(v8_str("x"))->Run();
6792 CHECK_EQ(42, value->Int32Value());
6793 value = Script::Compile(v8_str("f()"))->Run();
6794 CHECK_EQ(12, value->Int32Value());
Ben Murdochb0fe1622011-05-05 13:52:32 +01006795 value = Script::Compile(v8_str(script))->Run();
6796 CHECK_EQ(1, value->Int32Value());
6797 }
6798}
6799
6800
6801THREADED_TEST(CallKnownGlobalReceiver) {
6802 v8::HandleScope handle_scope;
6803
6804 Local<Value> global_object;
6805
6806 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6807 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
6808
6809 // The script to check that we leave global object not
6810 // global object proxy on stack when we deoptimize from inside
6811 // arguments evaluation.
6812 // To provoke error we need to both force deoptimization
6813 // from arguments evaluation and to force CallIC to take
6814 // CallIC_Miss code path that can't cope with global proxy.
6815 const char* script =
6816 "function bar(x, y) { try { } finally { } }"
6817 "function baz(x) { try { } finally { } }"
6818 "function bom(x) { try { } finally { } }"
6819 "function foo(x) { bar([x], bom(2)); }"
6820 "for (var i = 0; i < 10000; i++) foo(1);"
6821 "foo";
6822
6823 Local<Value> foo;
6824 {
6825 LocalContext env(NULL, instance_template);
6826 // Hold on to the global object so it can be used again in another
6827 // environment initialization.
6828 global_object = env->Global();
6829 foo = Script::Compile(v8_str(script))->Run();
6830 }
6831
6832 {
6833 // Create new environment reusing the global object.
6834 LocalContext env(NULL, instance_template, global_object);
6835 env->Global()->Set(v8_str("foo"), foo);
6836 Local<Value> value = Script::Compile(v8_str("foo()"))->Run();
Steve Blocka7e24c12009-10-30 11:49:00 +00006837 }
6838}
6839
6840
6841static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
6842 ApiTestFuzzer::Fuzz();
6843 return v8_num(42);
6844}
6845
6846
6847static int shadow_y;
6848static int shadow_y_setter_call_count;
6849static int shadow_y_getter_call_count;
6850
6851
6852static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
6853 shadow_y_setter_call_count++;
6854 shadow_y = 42;
6855}
6856
6857
6858static v8::Handle<Value> ShadowYGetter(Local<String> name,
6859 const AccessorInfo& info) {
6860 ApiTestFuzzer::Fuzz();
6861 shadow_y_getter_call_count++;
6862 return v8_num(shadow_y);
6863}
6864
6865
6866static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
6867 const AccessorInfo& info) {
6868 return v8::Handle<Value>();
6869}
6870
6871
6872static v8::Handle<Value> ShadowNamedGet(Local<String> key,
6873 const AccessorInfo&) {
6874 return v8::Handle<Value>();
6875}
6876
6877
6878THREADED_TEST(ShadowObject) {
6879 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
6880 v8::HandleScope handle_scope;
6881
6882 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
6883 LocalContext context(NULL, global_template);
6884
6885 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6886 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
6887 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
6888 Local<ObjectTemplate> proto = t->PrototypeTemplate();
6889 Local<ObjectTemplate> instance = t->InstanceTemplate();
6890
6891 // Only allow calls of f on instances of t.
6892 Local<v8::Signature> signature = v8::Signature::New(t);
6893 proto->Set(v8_str("f"),
6894 v8::FunctionTemplate::New(ShadowFunctionCallback,
6895 Local<Value>(),
6896 signature));
6897 proto->Set(v8_str("x"), v8_num(12));
6898
6899 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
6900
6901 Local<Value> o = t->GetFunction()->NewInstance();
6902 context->Global()->Set(v8_str("__proto__"), o);
6903
6904 Local<Value> value =
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006905 Script::Compile(v8_str("this.propertyIsEnumerable(0)"))->Run();
Steve Blocka7e24c12009-10-30 11:49:00 +00006906 CHECK(value->IsBoolean());
6907 CHECK(!value->BooleanValue());
6908
6909 value = Script::Compile(v8_str("x"))->Run();
6910 CHECK_EQ(12, value->Int32Value());
6911
6912 value = Script::Compile(v8_str("f()"))->Run();
6913 CHECK_EQ(42, value->Int32Value());
6914
6915 Script::Compile(v8_str("y = 42"))->Run();
6916 CHECK_EQ(1, shadow_y_setter_call_count);
6917 value = Script::Compile(v8_str("y"))->Run();
6918 CHECK_EQ(1, shadow_y_getter_call_count);
6919 CHECK_EQ(42, value->Int32Value());
6920}
6921
6922
6923THREADED_TEST(HiddenPrototype) {
6924 v8::HandleScope handle_scope;
6925 LocalContext context;
6926
6927 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
6928 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
6929 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
6930 t1->SetHiddenPrototype(true);
6931 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
6932 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
6933 t2->SetHiddenPrototype(true);
6934 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
6935 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
6936 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
6937
6938 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
6939 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
6940 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
6941 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
6942
6943 // Setting the prototype on an object skips hidden prototypes.
6944 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6945 o0->Set(v8_str("__proto__"), o1);
6946 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6947 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6948 o0->Set(v8_str("__proto__"), o2);
6949 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6950 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6951 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6952 o0->Set(v8_str("__proto__"), o3);
6953 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6954 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6955 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6956 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
6957
6958 // Getting the prototype of o0 should get the first visible one
6959 // which is o3. Therefore, z should not be defined on the prototype
6960 // object.
6961 Local<Value> proto = o0->Get(v8_str("__proto__"));
6962 CHECK(proto->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01006963 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
Steve Blocka7e24c12009-10-30 11:49:00 +00006964}
6965
6966
Andrei Popescu402d9372010-02-26 13:31:12 +00006967THREADED_TEST(SetPrototype) {
6968 v8::HandleScope handle_scope;
6969 LocalContext context;
6970
6971 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
6972 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
6973 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
6974 t1->SetHiddenPrototype(true);
6975 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
6976 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
6977 t2->SetHiddenPrototype(true);
6978 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
6979 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
6980 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
6981
6982 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
6983 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
6984 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
6985 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
6986
6987 // Setting the prototype on an object does not skip hidden prototypes.
6988 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6989 CHECK(o0->SetPrototype(o1));
6990 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6991 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6992 CHECK(o1->SetPrototype(o2));
6993 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6994 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6995 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6996 CHECK(o2->SetPrototype(o3));
6997 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6998 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6999 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7000 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
7001
7002 // Getting the prototype of o0 should get the first visible one
7003 // which is o3. Therefore, z should not be defined on the prototype
7004 // object.
7005 Local<Value> proto = o0->Get(v8_str("__proto__"));
7006 CHECK(proto->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01007007 CHECK_EQ(proto.As<v8::Object>(), o3);
Andrei Popescu402d9372010-02-26 13:31:12 +00007008
7009 // However, Object::GetPrototype ignores hidden prototype.
7010 Local<Value> proto0 = o0->GetPrototype();
7011 CHECK(proto0->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01007012 CHECK_EQ(proto0.As<v8::Object>(), o1);
Andrei Popescu402d9372010-02-26 13:31:12 +00007013
7014 Local<Value> proto1 = o1->GetPrototype();
7015 CHECK(proto1->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01007016 CHECK_EQ(proto1.As<v8::Object>(), o2);
Andrei Popescu402d9372010-02-26 13:31:12 +00007017
7018 Local<Value> proto2 = o2->GetPrototype();
7019 CHECK(proto2->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01007020 CHECK_EQ(proto2.As<v8::Object>(), o3);
Andrei Popescu402d9372010-02-26 13:31:12 +00007021}
7022
7023
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007024THREADED_TEST(SetPrototypeProperties) {
7025 v8::HandleScope handle_scope;
7026 LocalContext context;
7027
7028 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
7029 t1->SetPrototypeAttributes(v8::DontDelete);
7030 context->Global()->Set(v8_str("func1"), t1->GetFunction());
7031 CHECK(CompileRun(
7032 "(function() {"
7033 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
7034 " return (descriptor['writable'] == true) &&"
7035 " (descriptor['enumerable'] == true) &&"
7036 " (descriptor['configurable'] == false);"
7037 "})()")->BooleanValue());
7038
7039 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
7040 t2->SetPrototypeAttributes(v8::DontEnum);
7041 context->Global()->Set(v8_str("func2"), t2->GetFunction());
7042 CHECK(CompileRun(
7043 "(function() {"
7044 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
7045 " return (descriptor['writable'] == true) &&"
7046 " (descriptor['enumerable'] == false) &&"
7047 " (descriptor['configurable'] == true);"
7048 "})()")->BooleanValue());
7049
7050 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
7051 t3->SetPrototypeAttributes(v8::ReadOnly);
7052 context->Global()->Set(v8_str("func3"), t3->GetFunction());
7053 CHECK(CompileRun(
7054 "(function() {"
7055 " descriptor = Object.getOwnPropertyDescriptor(func3, 'prototype');"
7056 " return (descriptor['writable'] == false) &&"
7057 " (descriptor['enumerable'] == true) &&"
7058 " (descriptor['configurable'] == true);"
7059 "})()")->BooleanValue());
7060
7061 Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New();
7062 t4->SetPrototypeAttributes(v8::ReadOnly | v8::DontEnum | v8::DontDelete);
7063 context->Global()->Set(v8_str("func4"), t4->GetFunction());
7064 CHECK(CompileRun(
7065 "(function() {"
7066 " descriptor = Object.getOwnPropertyDescriptor(func4, 'prototype');"
7067 " return (descriptor['writable'] == false) &&"
7068 " (descriptor['enumerable'] == false) &&"
7069 " (descriptor['configurable'] == false);"
7070 "})()")->BooleanValue());
7071}
7072
7073
Andrei Popescu402d9372010-02-26 13:31:12 +00007074THREADED_TEST(SetPrototypeThrows) {
7075 v8::HandleScope handle_scope;
7076 LocalContext context;
7077
7078 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7079
7080 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
7081 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
7082
7083 CHECK(o0->SetPrototype(o1));
7084 // If setting the prototype leads to the cycle, SetPrototype should
7085 // return false and keep VM in sane state.
7086 v8::TryCatch try_catch;
7087 CHECK(!o1->SetPrototype(o0));
7088 CHECK(!try_catch.HasCaught());
Steve Block44f0eee2011-05-26 01:26:41 +01007089 ASSERT(!i::Isolate::Current()->has_pending_exception());
Andrei Popescu402d9372010-02-26 13:31:12 +00007090
7091 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
7092}
7093
7094
Steve Blocka7e24c12009-10-30 11:49:00 +00007095THREADED_TEST(GetterSetterExceptions) {
7096 v8::HandleScope handle_scope;
7097 LocalContext context;
7098 CompileRun(
7099 "function Foo() { };"
7100 "function Throw() { throw 5; };"
7101 "var x = { };"
7102 "x.__defineSetter__('set', Throw);"
7103 "x.__defineGetter__('get', Throw);");
7104 Local<v8::Object> x =
7105 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
7106 v8::TryCatch try_catch;
7107 x->Set(v8_str("set"), v8::Integer::New(8));
7108 x->Get(v8_str("get"));
7109 x->Set(v8_str("set"), v8::Integer::New(8));
7110 x->Get(v8_str("get"));
7111 x->Set(v8_str("set"), v8::Integer::New(8));
7112 x->Get(v8_str("get"));
7113 x->Set(v8_str("set"), v8::Integer::New(8));
7114 x->Get(v8_str("get"));
7115}
7116
7117
7118THREADED_TEST(Constructor) {
7119 v8::HandleScope handle_scope;
7120 LocalContext context;
7121 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7122 templ->SetClassName(v8_str("Fun"));
7123 Local<Function> cons = templ->GetFunction();
7124 context->Global()->Set(v8_str("Fun"), cons);
7125 Local<v8::Object> inst = cons->NewInstance();
7126 i::Handle<i::JSObject> obj = v8::Utils::OpenHandle(*inst);
7127 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
7128 CHECK(value->BooleanValue());
7129}
7130
Ben Murdoch257744e2011-11-30 15:57:28 +00007131
7132static Handle<Value> ConstructorCallback(const Arguments& args) {
7133 ApiTestFuzzer::Fuzz();
7134 Local<Object> This;
7135
7136 if (args.IsConstructCall()) {
7137 Local<Object> Holder = args.Holder();
7138 This = Object::New();
7139 Local<Value> proto = Holder->GetPrototype();
7140 if (proto->IsObject()) {
7141 This->SetPrototype(proto);
7142 }
7143 } else {
7144 This = args.This();
7145 }
7146
7147 This->Set(v8_str("a"), args[0]);
7148 return This;
7149}
7150
7151
7152static Handle<Value> FakeConstructorCallback(const Arguments& args) {
7153 ApiTestFuzzer::Fuzz();
7154 return args[0];
7155}
7156
7157
7158THREADED_TEST(ConstructorForObject) {
7159 v8::HandleScope handle_scope;
7160 LocalContext context;
7161
7162 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7163 instance_template->SetCallAsFunctionHandler(ConstructorCallback);
7164 Local<Object> instance = instance_template->NewInstance();
7165 context->Global()->Set(v8_str("obj"), instance);
7166 v8::TryCatch try_catch;
7167 Local<Value> value;
7168 CHECK(!try_catch.HasCaught());
7169
7170 // Call the Object's constructor with a 32-bit signed integer.
7171 value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
7172 CHECK(!try_catch.HasCaught());
7173 CHECK(value->IsInt32());
7174 CHECK_EQ(28, value->Int32Value());
7175
7176 Local<Value> args1[] = { v8_num(28) };
7177 Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
7178 CHECK(value_obj1->IsObject());
7179 Local<Object> object1 = Local<Object>::Cast(value_obj1);
7180 value = object1->Get(v8_str("a"));
7181 CHECK(value->IsInt32());
7182 CHECK(!try_catch.HasCaught());
7183 CHECK_EQ(28, value->Int32Value());
7184
7185 // Call the Object's constructor with a String.
7186 value = CompileRun(
7187 "(function() { var o = new obj('tipli'); return o.a; })()");
7188 CHECK(!try_catch.HasCaught());
7189 CHECK(value->IsString());
7190 String::AsciiValue string_value1(value->ToString());
7191 CHECK_EQ("tipli", *string_value1);
7192
7193 Local<Value> args2[] = { v8_str("tipli") };
7194 Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
7195 CHECK(value_obj2->IsObject());
7196 Local<Object> object2 = Local<Object>::Cast(value_obj2);
7197 value = object2->Get(v8_str("a"));
7198 CHECK(!try_catch.HasCaught());
7199 CHECK(value->IsString());
7200 String::AsciiValue string_value2(value->ToString());
7201 CHECK_EQ("tipli", *string_value2);
7202
7203 // Call the Object's constructor with a Boolean.
7204 value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
7205 CHECK(!try_catch.HasCaught());
7206 CHECK(value->IsBoolean());
7207 CHECK_EQ(true, value->BooleanValue());
7208
7209 Handle<Value> args3[] = { v8::Boolean::New(true) };
7210 Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
7211 CHECK(value_obj3->IsObject());
7212 Local<Object> object3 = Local<Object>::Cast(value_obj3);
7213 value = object3->Get(v8_str("a"));
7214 CHECK(!try_catch.HasCaught());
7215 CHECK(value->IsBoolean());
7216 CHECK_EQ(true, value->BooleanValue());
7217
7218 // Call the Object's constructor with undefined.
7219 Handle<Value> args4[] = { v8::Undefined() };
7220 Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
7221 CHECK(value_obj4->IsObject());
7222 Local<Object> object4 = Local<Object>::Cast(value_obj4);
7223 value = object4->Get(v8_str("a"));
7224 CHECK(!try_catch.HasCaught());
7225 CHECK(value->IsUndefined());
7226
7227 // Call the Object's constructor with null.
7228 Handle<Value> args5[] = { v8::Null() };
7229 Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
7230 CHECK(value_obj5->IsObject());
7231 Local<Object> object5 = Local<Object>::Cast(value_obj5);
7232 value = object5->Get(v8_str("a"));
7233 CHECK(!try_catch.HasCaught());
7234 CHECK(value->IsNull());
7235 }
7236
7237 // Check exception handling when there is no constructor set for the Object.
7238 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7239 Local<Object> instance = instance_template->NewInstance();
7240 context->Global()->Set(v8_str("obj2"), instance);
7241 v8::TryCatch try_catch;
7242 Local<Value> value;
7243 CHECK(!try_catch.HasCaught());
7244
7245 value = CompileRun("new obj2(28)");
7246 CHECK(try_catch.HasCaught());
7247 String::AsciiValue exception_value1(try_catch.Exception());
7248 CHECK_EQ("TypeError: object is not a function", *exception_value1);
7249 try_catch.Reset();
7250
7251 Local<Value> args[] = { v8_num(29) };
7252 value = instance->CallAsConstructor(1, args);
7253 CHECK(try_catch.HasCaught());
7254 String::AsciiValue exception_value2(try_catch.Exception());
7255 CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
7256 try_catch.Reset();
7257 }
7258
7259 // Check the case when constructor throws exception.
7260 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7261 instance_template->SetCallAsFunctionHandler(ThrowValue);
7262 Local<Object> instance = instance_template->NewInstance();
7263 context->Global()->Set(v8_str("obj3"), instance);
7264 v8::TryCatch try_catch;
7265 Local<Value> value;
7266 CHECK(!try_catch.HasCaught());
7267
7268 value = CompileRun("new obj3(22)");
7269 CHECK(try_catch.HasCaught());
7270 String::AsciiValue exception_value1(try_catch.Exception());
7271 CHECK_EQ("22", *exception_value1);
7272 try_catch.Reset();
7273
7274 Local<Value> args[] = { v8_num(23) };
7275 value = instance->CallAsConstructor(1, args);
7276 CHECK(try_catch.HasCaught());
7277 String::AsciiValue exception_value2(try_catch.Exception());
7278 CHECK_EQ("23", *exception_value2);
7279 try_catch.Reset();
7280 }
7281
7282 // Check whether constructor returns with an object or non-object.
7283 { Local<FunctionTemplate> function_template =
7284 FunctionTemplate::New(FakeConstructorCallback);
7285 Local<Function> function = function_template->GetFunction();
7286 Local<Object> instance1 = function;
7287 context->Global()->Set(v8_str("obj4"), instance1);
7288 v8::TryCatch try_catch;
7289 Local<Value> value;
7290 CHECK(!try_catch.HasCaught());
7291
7292 CHECK(instance1->IsObject());
7293 CHECK(instance1->IsFunction());
7294
7295 value = CompileRun("new obj4(28)");
7296 CHECK(!try_catch.HasCaught());
7297 CHECK(value->IsObject());
7298
7299 Local<Value> args1[] = { v8_num(28) };
7300 value = instance1->CallAsConstructor(1, args1);
7301 CHECK(!try_catch.HasCaught());
7302 CHECK(value->IsObject());
7303
7304 Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7305 instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
7306 Local<Object> instance2 = instance_template->NewInstance();
7307 context->Global()->Set(v8_str("obj5"), instance2);
7308 CHECK(!try_catch.HasCaught());
7309
7310 CHECK(instance2->IsObject());
7311 CHECK(!instance2->IsFunction());
7312
7313 value = CompileRun("new obj5(28)");
7314 CHECK(!try_catch.HasCaught());
7315 CHECK(!value->IsObject());
7316
7317 Local<Value> args2[] = { v8_num(28) };
7318 value = instance2->CallAsConstructor(1, args2);
7319 CHECK(!try_catch.HasCaught());
7320 CHECK(!value->IsObject());
7321 }
7322}
7323
7324
Steve Blocka7e24c12009-10-30 11:49:00 +00007325THREADED_TEST(FunctionDescriptorException) {
7326 v8::HandleScope handle_scope;
7327 LocalContext context;
7328 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7329 templ->SetClassName(v8_str("Fun"));
7330 Local<Function> cons = templ->GetFunction();
7331 context->Global()->Set(v8_str("Fun"), cons);
7332 Local<Value> value = CompileRun(
7333 "function test() {"
7334 " try {"
7335 " (new Fun()).blah()"
7336 " } catch (e) {"
7337 " var str = String(e);"
7338 " if (str.indexOf('TypeError') == -1) return 1;"
7339 " if (str.indexOf('[object Fun]') != -1) return 2;"
Steve Block1e0659c2011-05-24 12:43:12 +01007340 " if (str.indexOf('#<Fun>') == -1) return 3;"
Steve Blocka7e24c12009-10-30 11:49:00 +00007341 " return 0;"
7342 " }"
7343 " return 4;"
7344 "}"
7345 "test();");
7346 CHECK_EQ(0, value->Int32Value());
7347}
7348
7349
7350THREADED_TEST(EvalAliasedDynamic) {
7351 v8::HandleScope scope;
7352 LocalContext current;
7353
7354 // Tests where aliased eval can only be resolved dynamically.
7355 Local<Script> script =
7356 Script::Compile(v8_str("function f(x) { "
7357 " var foo = 2;"
7358 " with (x) { return eval('foo'); }"
7359 "}"
7360 "foo = 0;"
7361 "result1 = f(new Object());"
7362 "result2 = f(this);"
7363 "var x = new Object();"
7364 "x.eval = function(x) { return 1; };"
7365 "result3 = f(x);"));
7366 script->Run();
7367 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
7368 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
7369 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
7370
7371 v8::TryCatch try_catch;
7372 script =
7373 Script::Compile(v8_str("function f(x) { "
7374 " var bar = 2;"
7375 " with (x) { return eval('bar'); }"
7376 "}"
7377 "f(this)"));
7378 script->Run();
7379 CHECK(try_catch.HasCaught());
7380 try_catch.Reset();
7381}
7382
7383
7384THREADED_TEST(CrossEval) {
7385 v8::HandleScope scope;
7386 LocalContext other;
7387 LocalContext current;
7388
7389 Local<String> token = v8_str("<security token>");
7390 other->SetSecurityToken(token);
7391 current->SetSecurityToken(token);
7392
7393 // Setup reference from current to other.
7394 current->Global()->Set(v8_str("other"), other->Global());
7395
7396 // Check that new variables are introduced in other context.
7397 Local<Script> script =
7398 Script::Compile(v8_str("other.eval('var foo = 1234')"));
7399 script->Run();
7400 Local<Value> foo = other->Global()->Get(v8_str("foo"));
7401 CHECK_EQ(1234, foo->Int32Value());
7402 CHECK(!current->Global()->Has(v8_str("foo")));
7403
7404 // Check that writing to non-existing properties introduces them in
7405 // the other context.
7406 script =
7407 Script::Compile(v8_str("other.eval('na = 1234')"));
7408 script->Run();
7409 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
7410 CHECK(!current->Global()->Has(v8_str("na")));
7411
7412 // Check that global variables in current context are not visible in other
7413 // context.
7414 v8::TryCatch try_catch;
7415 script =
7416 Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
7417 Local<Value> result = script->Run();
7418 CHECK(try_catch.HasCaught());
7419 try_catch.Reset();
7420
7421 // Check that local variables in current context are not visible in other
7422 // context.
7423 script =
7424 Script::Compile(v8_str("(function() { "
7425 " var baz = 87;"
7426 " return other.eval('baz');"
7427 "})();"));
7428 result = script->Run();
7429 CHECK(try_catch.HasCaught());
7430 try_catch.Reset();
7431
7432 // Check that global variables in the other environment are visible
7433 // when evaluting code.
7434 other->Global()->Set(v8_str("bis"), v8_num(1234));
7435 script = Script::Compile(v8_str("other.eval('bis')"));
7436 CHECK_EQ(1234, script->Run()->Int32Value());
7437 CHECK(!try_catch.HasCaught());
7438
7439 // Check that the 'this' pointer points to the global object evaluating
7440 // code.
7441 other->Global()->Set(v8_str("t"), other->Global());
7442 script = Script::Compile(v8_str("other.eval('this == t')"));
7443 result = script->Run();
7444 CHECK(result->IsTrue());
7445 CHECK(!try_catch.HasCaught());
7446
7447 // Check that variables introduced in with-statement are not visible in
7448 // other context.
7449 script =
7450 Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
7451 result = script->Run();
7452 CHECK(try_catch.HasCaught());
7453 try_catch.Reset();
7454
7455 // Check that you cannot use 'eval.call' with another object than the
7456 // current global object.
7457 script =
7458 Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
7459 result = script->Run();
7460 CHECK(try_catch.HasCaught());
7461}
7462
7463
7464// Test that calling eval in a context which has been detached from
7465// its global throws an exception. This behavior is consistent with
7466// other JavaScript implementations.
7467THREADED_TEST(EvalInDetachedGlobal) {
7468 v8::HandleScope scope;
7469
7470 v8::Persistent<Context> context0 = Context::New();
7471 v8::Persistent<Context> context1 = Context::New();
7472
7473 // Setup function in context0 that uses eval from context0.
7474 context0->Enter();
7475 v8::Handle<v8::Value> fun =
7476 CompileRun("var x = 42;"
7477 "(function() {"
7478 " var e = eval;"
7479 " return function(s) { return e(s); }"
7480 "})()");
7481 context0->Exit();
7482
7483 // Put the function into context1 and call it before and after
7484 // detaching the global. Before detaching, the call succeeds and
7485 // after detaching and exception is thrown.
7486 context1->Enter();
7487 context1->Global()->Set(v8_str("fun"), fun);
7488 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
7489 CHECK_EQ(42, x_value->Int32Value());
7490 context0->DetachGlobal();
7491 v8::TryCatch catcher;
7492 x_value = CompileRun("fun('x')");
7493 CHECK(x_value.IsEmpty());
7494 CHECK(catcher.HasCaught());
7495 context1->Exit();
7496
7497 context1.Dispose();
7498 context0.Dispose();
7499}
7500
7501
7502THREADED_TEST(CrossLazyLoad) {
7503 v8::HandleScope scope;
7504 LocalContext other;
7505 LocalContext current;
7506
7507 Local<String> token = v8_str("<security token>");
7508 other->SetSecurityToken(token);
7509 current->SetSecurityToken(token);
7510
7511 // Setup reference from current to other.
7512 current->Global()->Set(v8_str("other"), other->Global());
7513
7514 // Trigger lazy loading in other context.
7515 Local<Script> script =
7516 Script::Compile(v8_str("other.eval('new Date(42)')"));
7517 Local<Value> value = script->Run();
7518 CHECK_EQ(42.0, value->NumberValue());
7519}
7520
7521
7522static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
Andrei Popescu402d9372010-02-26 13:31:12 +00007523 ApiTestFuzzer::Fuzz();
Steve Blocka7e24c12009-10-30 11:49:00 +00007524 if (args.IsConstructCall()) {
7525 if (args[0]->IsInt32()) {
7526 return v8_num(-args[0]->Int32Value());
7527 }
7528 }
7529
7530 return args[0];
7531}
7532
7533
7534// Test that a call handler can be set for objects which will allow
7535// non-function objects created through the API to be called as
7536// functions.
7537THREADED_TEST(CallAsFunction) {
7538 v8::HandleScope scope;
7539 LocalContext context;
7540
Ben Murdoch257744e2011-11-30 15:57:28 +00007541 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7542 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7543 instance_template->SetCallAsFunctionHandler(call_as_function);
7544 Local<v8::Object> instance = t->GetFunction()->NewInstance();
7545 context->Global()->Set(v8_str("obj"), instance);
7546 v8::TryCatch try_catch;
7547 Local<Value> value;
7548 CHECK(!try_catch.HasCaught());
Steve Blocka7e24c12009-10-30 11:49:00 +00007549
Ben Murdoch257744e2011-11-30 15:57:28 +00007550 value = CompileRun("obj(42)");
7551 CHECK(!try_catch.HasCaught());
7552 CHECK_EQ(42, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00007553
Ben Murdoch257744e2011-11-30 15:57:28 +00007554 value = CompileRun("(function(o){return o(49)})(obj)");
7555 CHECK(!try_catch.HasCaught());
7556 CHECK_EQ(49, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00007557
Ben Murdoch257744e2011-11-30 15:57:28 +00007558 // test special case of call as function
7559 value = CompileRun("[obj]['0'](45)");
7560 CHECK(!try_catch.HasCaught());
7561 CHECK_EQ(45, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00007562
Ben Murdoch257744e2011-11-30 15:57:28 +00007563 value = CompileRun("obj.call = Function.prototype.call;"
7564 "obj.call(null, 87)");
7565 CHECK(!try_catch.HasCaught());
7566 CHECK_EQ(87, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00007567
Ben Murdoch257744e2011-11-30 15:57:28 +00007568 // Regression tests for bug #1116356: Calling call through call/apply
7569 // must work for non-function receivers.
7570 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
7571 value = CompileRun(apply_99);
7572 CHECK(!try_catch.HasCaught());
7573 CHECK_EQ(99, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00007574
Ben Murdoch257744e2011-11-30 15:57:28 +00007575 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
7576 value = CompileRun(call_17);
7577 CHECK(!try_catch.HasCaught());
7578 CHECK_EQ(17, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00007579
Ben Murdoch257744e2011-11-30 15:57:28 +00007580 // Check that the call-as-function handler can be called through
7581 // new.
7582 value = CompileRun("new obj(43)");
7583 CHECK(!try_catch.HasCaught());
7584 CHECK_EQ(-43, value->Int32Value());
7585
7586 // Check that the call-as-function handler can be called through
7587 // the API.
7588 v8::Handle<Value> args[] = { v8_num(28) };
7589 value = instance->CallAsFunction(instance, 1, args);
7590 CHECK(!try_catch.HasCaught());
7591 CHECK_EQ(28, value->Int32Value());
7592 }
7593
7594 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7595 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7596 Local<v8::Object> instance = t->GetFunction()->NewInstance();
7597 context->Global()->Set(v8_str("obj2"), instance);
7598 v8::TryCatch try_catch;
7599 Local<Value> value;
7600 CHECK(!try_catch.HasCaught());
7601
7602 // Call an object without call-as-function handler through the JS
7603 value = CompileRun("obj2(28)");
7604 CHECK(value.IsEmpty());
7605 CHECK(try_catch.HasCaught());
7606 String::AsciiValue exception_value1(try_catch.Exception());
7607 CHECK_EQ("TypeError: Property 'obj2' of object #<Object> is not a function",
7608 *exception_value1);
7609 try_catch.Reset();
7610
7611 // Call an object without call-as-function handler through the API
7612 value = CompileRun("obj2(28)");
7613 v8::Handle<Value> args[] = { v8_num(28) };
7614 value = instance->CallAsFunction(instance, 1, args);
7615 CHECK(value.IsEmpty());
7616 CHECK(try_catch.HasCaught());
7617 String::AsciiValue exception_value2(try_catch.Exception());
7618 CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
7619 try_catch.Reset();
7620 }
7621
7622 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7623 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7624 instance_template->SetCallAsFunctionHandler(ThrowValue);
7625 Local<v8::Object> instance = t->GetFunction()->NewInstance();
7626 context->Global()->Set(v8_str("obj3"), instance);
7627 v8::TryCatch try_catch;
7628 Local<Value> value;
7629 CHECK(!try_catch.HasCaught());
7630
7631 // Catch the exception which is thrown by call-as-function handler
7632 value = CompileRun("obj3(22)");
7633 CHECK(try_catch.HasCaught());
7634 String::AsciiValue exception_value1(try_catch.Exception());
7635 CHECK_EQ("22", *exception_value1);
7636 try_catch.Reset();
7637
7638 v8::Handle<Value> args[] = { v8_num(23) };
7639 value = instance->CallAsFunction(instance, 1, args);
7640 CHECK(try_catch.HasCaught());
7641 String::AsciiValue exception_value2(try_catch.Exception());
7642 CHECK_EQ("23", *exception_value2);
7643 try_catch.Reset();
7644 }
7645}
7646
7647
7648// Check whether a non-function object is callable.
7649THREADED_TEST(CallableObject) {
7650 v8::HandleScope scope;
7651 LocalContext context;
7652
7653 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7654 instance_template->SetCallAsFunctionHandler(call_as_function);
7655 Local<Object> instance = instance_template->NewInstance();
7656 v8::TryCatch try_catch;
7657
7658 CHECK(instance->IsCallable());
7659 CHECK(!try_catch.HasCaught());
7660 }
7661
7662 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7663 Local<Object> instance = instance_template->NewInstance();
7664 v8::TryCatch try_catch;
7665
7666 CHECK(!instance->IsCallable());
7667 CHECK(!try_catch.HasCaught());
7668 }
7669
7670 { Local<FunctionTemplate> function_template =
7671 FunctionTemplate::New(call_as_function);
7672 Local<Function> function = function_template->GetFunction();
7673 Local<Object> instance = function;
7674 v8::TryCatch try_catch;
7675
7676 CHECK(instance->IsCallable());
7677 CHECK(!try_catch.HasCaught());
7678 }
7679
7680 { Local<FunctionTemplate> function_template = FunctionTemplate::New();
7681 Local<Function> function = function_template->GetFunction();
7682 Local<Object> instance = function;
7683 v8::TryCatch try_catch;
7684
7685 CHECK(instance->IsCallable());
7686 CHECK(!try_catch.HasCaught());
7687 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007688}
7689
7690
7691static int CountHandles() {
7692 return v8::HandleScope::NumberOfHandles();
7693}
7694
7695
7696static int Recurse(int depth, int iterations) {
7697 v8::HandleScope scope;
7698 if (depth == 0) return CountHandles();
7699 for (int i = 0; i < iterations; i++) {
7700 Local<v8::Number> n = v8::Integer::New(42);
7701 }
7702 return Recurse(depth - 1, iterations);
7703}
7704
7705
7706THREADED_TEST(HandleIteration) {
7707 static const int kIterations = 500;
7708 static const int kNesting = 200;
7709 CHECK_EQ(0, CountHandles());
7710 {
7711 v8::HandleScope scope1;
7712 CHECK_EQ(0, CountHandles());
7713 for (int i = 0; i < kIterations; i++) {
7714 Local<v8::Number> n = v8::Integer::New(42);
7715 CHECK_EQ(i + 1, CountHandles());
7716 }
7717
7718 CHECK_EQ(kIterations, CountHandles());
7719 {
7720 v8::HandleScope scope2;
7721 for (int j = 0; j < kIterations; j++) {
7722 Local<v8::Number> n = v8::Integer::New(42);
7723 CHECK_EQ(j + 1 + kIterations, CountHandles());
7724 }
7725 }
7726 CHECK_EQ(kIterations, CountHandles());
7727 }
7728 CHECK_EQ(0, CountHandles());
7729 CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
7730}
7731
7732
7733static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
7734 Local<String> name,
7735 const AccessorInfo& info) {
7736 ApiTestFuzzer::Fuzz();
7737 return v8::Handle<Value>();
7738}
7739
7740
7741THREADED_TEST(InterceptorHasOwnProperty) {
7742 v8::HandleScope scope;
7743 LocalContext context;
7744 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7745 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
7746 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
7747 Local<Function> function = fun_templ->GetFunction();
7748 context->Global()->Set(v8_str("constructor"), function);
7749 v8::Handle<Value> value = CompileRun(
7750 "var o = new constructor();"
7751 "o.hasOwnProperty('ostehaps');");
7752 CHECK_EQ(false, value->BooleanValue());
7753 value = CompileRun(
7754 "o.ostehaps = 42;"
7755 "o.hasOwnProperty('ostehaps');");
7756 CHECK_EQ(true, value->BooleanValue());
7757 value = CompileRun(
7758 "var p = new constructor();"
7759 "p.hasOwnProperty('ostehaps');");
7760 CHECK_EQ(false, value->BooleanValue());
7761}
7762
7763
7764static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
7765 Local<String> name,
7766 const AccessorInfo& info) {
7767 ApiTestFuzzer::Fuzz();
Steve Block44f0eee2011-05-26 01:26:41 +01007768 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +00007769 return v8::Handle<Value>();
7770}
7771
7772
7773THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
7774 v8::HandleScope scope;
7775 LocalContext context;
7776 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7777 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
7778 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
7779 Local<Function> function = fun_templ->GetFunction();
7780 context->Global()->Set(v8_str("constructor"), function);
7781 // Let's first make some stuff so we can be sure to get a good GC.
7782 CompileRun(
7783 "function makestr(size) {"
7784 " switch (size) {"
7785 " case 1: return 'f';"
7786 " case 2: return 'fo';"
7787 " case 3: return 'foo';"
7788 " }"
7789 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
7790 "}"
7791 "var x = makestr(12345);"
7792 "x = makestr(31415);"
7793 "x = makestr(23456);");
7794 v8::Handle<Value> value = CompileRun(
7795 "var o = new constructor();"
7796 "o.__proto__ = new String(x);"
7797 "o.hasOwnProperty('ostehaps');");
7798 CHECK_EQ(false, value->BooleanValue());
7799}
7800
7801
7802typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
7803 const AccessorInfo& info);
7804
7805
7806static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
7807 const char* source,
7808 int expected) {
7809 v8::HandleScope scope;
7810 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08007811 templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
Steve Blocka7e24c12009-10-30 11:49:00 +00007812 LocalContext context;
7813 context->Global()->Set(v8_str("o"), templ->NewInstance());
7814 v8::Handle<Value> value = CompileRun(source);
7815 CHECK_EQ(expected, value->Int32Value());
7816}
7817
7818
7819static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
7820 const AccessorInfo& info) {
7821 ApiTestFuzzer::Fuzz();
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08007822 CHECK_EQ(v8_str("data"), info.Data());
7823 CHECK_EQ(v8_str("x"), name);
Steve Blocka7e24c12009-10-30 11:49:00 +00007824 return v8::Integer::New(42);
7825}
7826
7827
7828// This test should hit the load IC for the interceptor case.
7829THREADED_TEST(InterceptorLoadIC) {
7830 CheckInterceptorLoadIC(InterceptorLoadICGetter,
7831 "var result = 0;"
7832 "for (var i = 0; i < 1000; i++) {"
7833 " result = o.x;"
7834 "}",
7835 42);
7836}
7837
7838
7839// Below go several tests which verify that JITing for various
7840// configurations of interceptor and explicit fields works fine
7841// (those cases are special cased to get better performance).
7842
7843static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
7844 const AccessorInfo& info) {
7845 ApiTestFuzzer::Fuzz();
7846 return v8_str("x")->Equals(name)
7847 ? v8::Integer::New(42) : v8::Handle<v8::Value>();
7848}
7849
7850
7851THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
7852 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7853 "var result = 0;"
7854 "o.y = 239;"
7855 "for (var i = 0; i < 1000; i++) {"
7856 " result = o.y;"
7857 "}",
7858 239);
7859}
7860
7861
7862THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
7863 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7864 "var result = 0;"
7865 "o.__proto__ = { 'y': 239 };"
7866 "for (var i = 0; i < 1000; i++) {"
7867 " result = o.y + o.x;"
7868 "}",
7869 239 + 42);
7870}
7871
7872
7873THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
7874 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7875 "var result = 0;"
7876 "o.__proto__.y = 239;"
7877 "for (var i = 0; i < 1000; i++) {"
7878 " result = o.y + o.x;"
7879 "}",
7880 239 + 42);
7881}
7882
7883
7884THREADED_TEST(InterceptorLoadICUndefined) {
7885 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7886 "var result = 0;"
7887 "for (var i = 0; i < 1000; i++) {"
7888 " result = (o.y == undefined) ? 239 : 42;"
7889 "}",
7890 239);
7891}
7892
7893
7894THREADED_TEST(InterceptorLoadICWithOverride) {
7895 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7896 "fst = new Object(); fst.__proto__ = o;"
7897 "snd = new Object(); snd.__proto__ = fst;"
7898 "var result1 = 0;"
7899 "for (var i = 0; i < 1000; i++) {"
7900 " result1 = snd.x;"
7901 "}"
7902 "fst.x = 239;"
7903 "var result = 0;"
7904 "for (var i = 0; i < 1000; i++) {"
7905 " result = snd.x;"
7906 "}"
7907 "result + result1",
7908 239 + 42);
7909}
7910
7911
7912// Test the case when we stored field into
7913// a stub, but interceptor produced value on its own.
7914THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
7915 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7916 "proto = new Object();"
7917 "o.__proto__ = proto;"
7918 "proto.x = 239;"
7919 "for (var i = 0; i < 1000; i++) {"
7920 " o.x;"
7921 // Now it should be ICed and keep a reference to x defined on proto
7922 "}"
7923 "var result = 0;"
7924 "for (var i = 0; i < 1000; i++) {"
7925 " result += o.x;"
7926 "}"
7927 "result;",
7928 42 * 1000);
7929}
7930
7931
7932// Test the case when we stored field into
7933// a stub, but it got invalidated later on.
7934THREADED_TEST(InterceptorLoadICInvalidatedField) {
7935 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7936 "proto1 = new Object();"
7937 "proto2 = new Object();"
7938 "o.__proto__ = proto1;"
7939 "proto1.__proto__ = proto2;"
7940 "proto2.y = 239;"
7941 "for (var i = 0; i < 1000; i++) {"
7942 " o.y;"
7943 // Now it should be ICed and keep a reference to y defined on proto2
7944 "}"
7945 "proto1.y = 42;"
7946 "var result = 0;"
7947 "for (var i = 0; i < 1000; i++) {"
7948 " result += o.y;"
7949 "}"
7950 "result;",
7951 42 * 1000);
7952}
7953
7954
Steve Block6ded16b2010-05-10 14:33:55 +01007955static int interceptor_load_not_handled_calls = 0;
7956static v8::Handle<Value> InterceptorLoadNotHandled(Local<String> name,
7957 const AccessorInfo& info) {
7958 ++interceptor_load_not_handled_calls;
7959 return v8::Handle<v8::Value>();
7960}
7961
7962
7963// Test how post-interceptor lookups are done in the non-cacheable
7964// case: the interceptor should not be invoked during this lookup.
7965THREADED_TEST(InterceptorLoadICPostInterceptor) {
7966 interceptor_load_not_handled_calls = 0;
7967 CheckInterceptorLoadIC(InterceptorLoadNotHandled,
7968 "receiver = new Object();"
7969 "receiver.__proto__ = o;"
7970 "proto = new Object();"
7971 "/* Make proto a slow-case object. */"
7972 "for (var i = 0; i < 1000; i++) {"
7973 " proto[\"xxxxxxxx\" + i] = [];"
7974 "}"
7975 "proto.x = 17;"
7976 "o.__proto__ = proto;"
7977 "var result = 0;"
7978 "for (var i = 0; i < 1000; i++) {"
7979 " result += receiver.x;"
7980 "}"
7981 "result;",
7982 17 * 1000);
7983 CHECK_EQ(1000, interceptor_load_not_handled_calls);
7984}
7985
7986
Steve Blocka7e24c12009-10-30 11:49:00 +00007987// Test the case when we stored field into
7988// a stub, but it got invalidated later on due to override on
7989// global object which is between interceptor and fields' holders.
7990THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
7991 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7992 "o.__proto__ = this;" // set a global to be a proto of o.
7993 "this.__proto__.y = 239;"
7994 "for (var i = 0; i < 10; i++) {"
7995 " if (o.y != 239) throw 'oops: ' + o.y;"
7996 // Now it should be ICed and keep a reference to y defined on field_holder.
7997 "}"
7998 "this.y = 42;" // Assign on a global.
7999 "var result = 0;"
8000 "for (var i = 0; i < 10; i++) {"
8001 " result += o.y;"
8002 "}"
8003 "result;",
8004 42 * 10);
8005}
8006
8007
Steve Blocka7e24c12009-10-30 11:49:00 +00008008static void SetOnThis(Local<String> name,
8009 Local<Value> value,
8010 const AccessorInfo& info) {
8011 info.This()->ForceSet(name, value);
8012}
8013
8014
8015THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
8016 v8::HandleScope scope;
8017 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8018 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8019 templ->SetAccessor(v8_str("y"), Return239);
8020 LocalContext context;
8021 context->Global()->Set(v8_str("o"), templ->NewInstance());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008022
8023 // Check the case when receiver and interceptor's holder
8024 // are the same objects.
Steve Blocka7e24c12009-10-30 11:49:00 +00008025 v8::Handle<Value> value = CompileRun(
8026 "var result = 0;"
8027 "for (var i = 0; i < 7; i++) {"
8028 " result = o.y;"
8029 "}");
8030 CHECK_EQ(239, value->Int32Value());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008031
8032 // Check the case when interceptor's holder is in proto chain
8033 // of receiver.
8034 value = CompileRun(
8035 "r = { __proto__: o };"
8036 "var result = 0;"
8037 "for (var i = 0; i < 7; i++) {"
8038 " result = r.y;"
8039 "}");
8040 CHECK_EQ(239, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00008041}
8042
8043
8044THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
8045 v8::HandleScope scope;
8046 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8047 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8048 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8049 templ_p->SetAccessor(v8_str("y"), Return239);
8050
8051 LocalContext context;
8052 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8053 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8054
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008055 // Check the case when receiver and interceptor's holder
8056 // are the same objects.
Steve Blocka7e24c12009-10-30 11:49:00 +00008057 v8::Handle<Value> value = CompileRun(
8058 "o.__proto__ = p;"
8059 "var result = 0;"
8060 "for (var i = 0; i < 7; i++) {"
8061 " result = o.x + o.y;"
8062 "}");
8063 CHECK_EQ(239 + 42, value->Int32Value());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008064
8065 // Check the case when interceptor's holder is in proto chain
8066 // of receiver.
8067 value = CompileRun(
8068 "r = { __proto__: o };"
8069 "var result = 0;"
8070 "for (var i = 0; i < 7; i++) {"
8071 " result = r.x + r.y;"
8072 "}");
8073 CHECK_EQ(239 + 42, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00008074}
8075
8076
8077THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
8078 v8::HandleScope scope;
8079 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8080 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8081 templ->SetAccessor(v8_str("y"), Return239);
8082
8083 LocalContext context;
8084 context->Global()->Set(v8_str("o"), templ->NewInstance());
8085
8086 v8::Handle<Value> value = CompileRun(
8087 "fst = new Object(); fst.__proto__ = o;"
8088 "snd = new Object(); snd.__proto__ = fst;"
8089 "var result1 = 0;"
8090 "for (var i = 0; i < 7; i++) {"
8091 " result1 = snd.x;"
8092 "}"
8093 "fst.x = 239;"
8094 "var result = 0;"
8095 "for (var i = 0; i < 7; i++) {"
8096 " result = snd.x;"
8097 "}"
8098 "result + result1");
8099 CHECK_EQ(239 + 42, value->Int32Value());
8100}
8101
8102
8103// Test the case when we stored callback into
8104// a stub, but interceptor produced value on its own.
8105THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
8106 v8::HandleScope scope;
8107 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8108 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8109 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8110 templ_p->SetAccessor(v8_str("y"), Return239);
8111
8112 LocalContext context;
8113 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8114 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8115
8116 v8::Handle<Value> value = CompileRun(
8117 "o.__proto__ = p;"
8118 "for (var i = 0; i < 7; i++) {"
8119 " o.x;"
8120 // Now it should be ICed and keep a reference to x defined on p
8121 "}"
8122 "var result = 0;"
8123 "for (var i = 0; i < 7; i++) {"
8124 " result += o.x;"
8125 "}"
8126 "result");
8127 CHECK_EQ(42 * 7, value->Int32Value());
8128}
8129
8130
8131// Test the case when we stored callback into
8132// a stub, but it got invalidated later on.
8133THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
8134 v8::HandleScope scope;
8135 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8136 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8137 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8138 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
8139
8140 LocalContext context;
8141 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8142 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8143
8144 v8::Handle<Value> value = CompileRun(
8145 "inbetween = new Object();"
8146 "o.__proto__ = inbetween;"
8147 "inbetween.__proto__ = p;"
8148 "for (var i = 0; i < 10; i++) {"
8149 " o.y;"
8150 // Now it should be ICed and keep a reference to y defined on p
8151 "}"
8152 "inbetween.y = 42;"
8153 "var result = 0;"
8154 "for (var i = 0; i < 10; i++) {"
8155 " result += o.y;"
8156 "}"
8157 "result");
8158 CHECK_EQ(42 * 10, value->Int32Value());
8159}
8160
8161
8162// Test the case when we stored callback into
8163// a stub, but it got invalidated later on due to override on
8164// global object which is between interceptor and callbacks' holders.
8165THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
8166 v8::HandleScope scope;
8167 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8168 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8169 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8170 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
8171
8172 LocalContext context;
8173 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8174 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8175
8176 v8::Handle<Value> value = CompileRun(
8177 "o.__proto__ = this;"
8178 "this.__proto__ = p;"
8179 "for (var i = 0; i < 10; i++) {"
8180 " if (o.y != 239) throw 'oops: ' + o.y;"
8181 // Now it should be ICed and keep a reference to y defined on p
8182 "}"
8183 "this.y = 42;"
8184 "var result = 0;"
8185 "for (var i = 0; i < 10; i++) {"
8186 " result += o.y;"
8187 "}"
8188 "result");
8189 CHECK_EQ(42 * 10, value->Int32Value());
8190}
8191
8192
8193static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
8194 const AccessorInfo& info) {
8195 ApiTestFuzzer::Fuzz();
8196 CHECK(v8_str("x")->Equals(name));
8197 return v8::Integer::New(0);
8198}
8199
8200
8201THREADED_TEST(InterceptorReturningZero) {
8202 CheckInterceptorLoadIC(InterceptorLoadICGetter0,
8203 "o.x == undefined ? 1 : 0",
8204 0);
8205}
8206
8207
8208static v8::Handle<Value> InterceptorStoreICSetter(
8209 Local<String> key, Local<Value> value, const AccessorInfo&) {
8210 CHECK(v8_str("x")->Equals(key));
8211 CHECK_EQ(42, value->Int32Value());
8212 return value;
8213}
8214
8215
8216// This test should hit the store IC for the interceptor case.
8217THREADED_TEST(InterceptorStoreIC) {
8218 v8::HandleScope scope;
8219 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8220 templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08008221 InterceptorStoreICSetter,
8222 0, 0, 0, v8_str("data"));
Steve Blocka7e24c12009-10-30 11:49:00 +00008223 LocalContext context;
8224 context->Global()->Set(v8_str("o"), templ->NewInstance());
8225 v8::Handle<Value> value = CompileRun(
8226 "for (var i = 0; i < 1000; i++) {"
8227 " o.x = 42;"
8228 "}");
8229}
8230
8231
8232THREADED_TEST(InterceptorStoreICWithNoSetter) {
8233 v8::HandleScope scope;
8234 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8235 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8236 LocalContext context;
8237 context->Global()->Set(v8_str("o"), templ->NewInstance());
8238 v8::Handle<Value> value = CompileRun(
8239 "for (var i = 0; i < 1000; i++) {"
8240 " o.y = 239;"
8241 "}"
8242 "42 + o.y");
8243 CHECK_EQ(239 + 42, value->Int32Value());
8244}
8245
8246
8247
8248
8249v8::Handle<Value> call_ic_function;
8250v8::Handle<Value> call_ic_function2;
8251v8::Handle<Value> call_ic_function3;
8252
8253static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
8254 const AccessorInfo& info) {
8255 ApiTestFuzzer::Fuzz();
8256 CHECK(v8_str("x")->Equals(name));
8257 return call_ic_function;
8258}
8259
8260
8261// This test should hit the call IC for the interceptor case.
8262THREADED_TEST(InterceptorCallIC) {
8263 v8::HandleScope scope;
8264 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8265 templ->SetNamedPropertyHandler(InterceptorCallICGetter);
8266 LocalContext context;
8267 context->Global()->Set(v8_str("o"), templ->NewInstance());
8268 call_ic_function =
8269 v8_compile("function f(x) { return x + 1; }; f")->Run();
8270 v8::Handle<Value> value = CompileRun(
8271 "var result = 0;"
8272 "for (var i = 0; i < 1000; i++) {"
8273 " result = o.x(41);"
8274 "}");
8275 CHECK_EQ(42, value->Int32Value());
8276}
8277
8278
8279// This test checks that if interceptor doesn't provide
8280// a value, we can fetch regular value.
8281THREADED_TEST(InterceptorCallICSeesOthers) {
8282 v8::HandleScope scope;
8283 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8284 templ->SetNamedPropertyHandler(NoBlockGetterX);
8285 LocalContext context;
8286 context->Global()->Set(v8_str("o"), templ->NewInstance());
8287 v8::Handle<Value> value = CompileRun(
8288 "o.x = function f(x) { return x + 1; };"
8289 "var result = 0;"
8290 "for (var i = 0; i < 7; i++) {"
8291 " result = o.x(41);"
8292 "}");
8293 CHECK_EQ(42, value->Int32Value());
8294}
8295
8296
8297static v8::Handle<Value> call_ic_function4;
8298static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
8299 const AccessorInfo& info) {
8300 ApiTestFuzzer::Fuzz();
8301 CHECK(v8_str("x")->Equals(name));
8302 return call_ic_function4;
8303}
8304
8305
8306// This test checks that if interceptor provides a function,
8307// even if we cached shadowed variant, interceptor's function
8308// is invoked
8309THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
8310 v8::HandleScope scope;
8311 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8312 templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
8313 LocalContext context;
8314 context->Global()->Set(v8_str("o"), templ->NewInstance());
8315 call_ic_function4 =
8316 v8_compile("function f(x) { return x - 1; }; f")->Run();
8317 v8::Handle<Value> value = CompileRun(
8318 "o.__proto__.x = function(x) { return x + 1; };"
8319 "var result = 0;"
8320 "for (var i = 0; i < 1000; i++) {"
8321 " result = o.x(42);"
8322 "}");
8323 CHECK_EQ(41, value->Int32Value());
8324}
8325
8326
8327// Test the case when we stored cacheable lookup into
8328// a stub, but it got invalidated later on
8329THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
8330 v8::HandleScope scope;
8331 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8332 templ->SetNamedPropertyHandler(NoBlockGetterX);
8333 LocalContext context;
8334 context->Global()->Set(v8_str("o"), templ->NewInstance());
8335 v8::Handle<Value> value = CompileRun(
8336 "proto1 = new Object();"
8337 "proto2 = new Object();"
8338 "o.__proto__ = proto1;"
8339 "proto1.__proto__ = proto2;"
8340 "proto2.y = function(x) { return x + 1; };"
8341 // Invoke it many times to compile a stub
8342 "for (var i = 0; i < 7; i++) {"
8343 " o.y(42);"
8344 "}"
8345 "proto1.y = function(x) { return x - 1; };"
8346 "var result = 0;"
8347 "for (var i = 0; i < 7; i++) {"
8348 " result += o.y(42);"
8349 "}");
8350 CHECK_EQ(41 * 7, value->Int32Value());
8351}
8352
8353
8354static v8::Handle<Value> call_ic_function5;
8355static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
8356 const AccessorInfo& info) {
8357 ApiTestFuzzer::Fuzz();
8358 if (v8_str("x")->Equals(name))
8359 return call_ic_function5;
8360 else
8361 return Local<Value>();
8362}
8363
8364
8365// This test checks that if interceptor doesn't provide a function,
8366// cached constant function is used
8367THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
8368 v8::HandleScope scope;
8369 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8370 templ->SetNamedPropertyHandler(NoBlockGetterX);
8371 LocalContext context;
8372 context->Global()->Set(v8_str("o"), templ->NewInstance());
8373 v8::Handle<Value> value = CompileRun(
8374 "function inc(x) { return x + 1; };"
8375 "inc(1);"
8376 "o.x = inc;"
8377 "var result = 0;"
8378 "for (var i = 0; i < 1000; i++) {"
8379 " result = o.x(42);"
8380 "}");
8381 CHECK_EQ(43, value->Int32Value());
8382}
8383
8384
8385// This test checks that if interceptor provides a function,
8386// even if we cached constant function, interceptor's function
8387// is invoked
8388THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
8389 v8::HandleScope scope;
8390 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8391 templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
8392 LocalContext context;
8393 context->Global()->Set(v8_str("o"), templ->NewInstance());
8394 call_ic_function5 =
8395 v8_compile("function f(x) { return x - 1; }; f")->Run();
8396 v8::Handle<Value> value = CompileRun(
8397 "function inc(x) { return x + 1; };"
8398 "inc(1);"
8399 "o.x = inc;"
8400 "var result = 0;"
8401 "for (var i = 0; i < 1000; i++) {"
8402 " result = o.x(42);"
8403 "}");
8404 CHECK_EQ(41, value->Int32Value());
8405}
8406
8407
8408// Test the case when we stored constant function into
8409// a stub, but it got invalidated later on
8410THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
8411 v8::HandleScope scope;
8412 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8413 templ->SetNamedPropertyHandler(NoBlockGetterX);
8414 LocalContext context;
8415 context->Global()->Set(v8_str("o"), templ->NewInstance());
8416 v8::Handle<Value> value = CompileRun(
8417 "function inc(x) { return x + 1; };"
8418 "inc(1);"
8419 "proto1 = new Object();"
8420 "proto2 = new Object();"
8421 "o.__proto__ = proto1;"
8422 "proto1.__proto__ = proto2;"
8423 "proto2.y = inc;"
8424 // Invoke it many times to compile a stub
8425 "for (var i = 0; i < 7; i++) {"
8426 " o.y(42);"
8427 "}"
8428 "proto1.y = function(x) { return x - 1; };"
8429 "var result = 0;"
8430 "for (var i = 0; i < 7; i++) {"
8431 " result += o.y(42);"
8432 "}");
8433 CHECK_EQ(41 * 7, value->Int32Value());
8434}
8435
8436
8437// Test the case when we stored constant function into
8438// a stub, but it got invalidated later on due to override on
8439// global object which is between interceptor and constant function' holders.
8440THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
8441 v8::HandleScope scope;
8442 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8443 templ->SetNamedPropertyHandler(NoBlockGetterX);
8444 LocalContext context;
8445 context->Global()->Set(v8_str("o"), templ->NewInstance());
8446 v8::Handle<Value> value = CompileRun(
8447 "function inc(x) { return x + 1; };"
8448 "inc(1);"
8449 "o.__proto__ = this;"
8450 "this.__proto__.y = inc;"
8451 // Invoke it many times to compile a stub
8452 "for (var i = 0; i < 7; i++) {"
8453 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
8454 "}"
8455 "this.y = function(x) { return x - 1; };"
8456 "var result = 0;"
8457 "for (var i = 0; i < 7; i++) {"
8458 " result += o.y(42);"
8459 "}");
8460 CHECK_EQ(41 * 7, value->Int32Value());
8461}
8462
8463
Leon Clarke4515c472010-02-03 11:58:03 +00008464// Test the case when actual function to call sits on global object.
8465THREADED_TEST(InterceptorCallICCachedFromGlobal) {
8466 v8::HandleScope scope;
8467 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8468 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
8469
8470 LocalContext context;
8471 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8472
8473 v8::Handle<Value> value = CompileRun(
8474 "try {"
8475 " o.__proto__ = this;"
8476 " for (var i = 0; i < 10; i++) {"
8477 " var v = o.parseFloat('239');"
8478 " if (v != 239) throw v;"
8479 // Now it should be ICed and keep a reference to parseFloat.
8480 " }"
8481 " var result = 0;"
8482 " for (var i = 0; i < 10; i++) {"
8483 " result += o.parseFloat('239');"
8484 " }"
8485 " result"
8486 "} catch(e) {"
8487 " e"
8488 "};");
8489 CHECK_EQ(239 * 10, value->Int32Value());
8490}
8491
Andrei Popescu402d9372010-02-26 13:31:12 +00008492static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
8493 const AccessorInfo& info) {
8494 ApiTestFuzzer::Fuzz();
8495 int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data()));
8496 ++(*call_count);
8497 if ((*call_count) % 20 == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01008498 HEAP->CollectAllGarbage(true);
Andrei Popescu402d9372010-02-26 13:31:12 +00008499 }
8500 return v8::Handle<Value>();
8501}
8502
8503static v8::Handle<Value> FastApiCallback_TrivialSignature(
8504 const v8::Arguments& args) {
8505 ApiTestFuzzer::Fuzz();
8506 CHECK_EQ(args.This(), args.Holder());
8507 CHECK(args.Data()->Equals(v8_str("method_data")));
8508 return v8::Integer::New(args[0]->Int32Value() + 1);
8509}
8510
8511static v8::Handle<Value> FastApiCallback_SimpleSignature(
8512 const v8::Arguments& args) {
8513 ApiTestFuzzer::Fuzz();
8514 CHECK_EQ(args.This()->GetPrototype(), args.Holder());
8515 CHECK(args.Data()->Equals(v8_str("method_data")));
8516 // Note, we're using HasRealNamedProperty instead of Has to avoid
8517 // invoking the interceptor again.
8518 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
8519 return v8::Integer::New(args[0]->Int32Value() + 1);
8520}
8521
8522// Helper to maximize the odds of object moving.
8523static void GenerateSomeGarbage() {
8524 CompileRun(
8525 "var garbage;"
8526 "for (var i = 0; i < 1000; i++) {"
8527 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
8528 "}"
8529 "garbage = undefined;");
8530}
8531
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008532
Steve Block1e0659c2011-05-24 12:43:12 +01008533v8::Handle<v8::Value> DirectApiCallback(const v8::Arguments& args) {
8534 static int count = 0;
8535 if (count++ % 3 == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01008536 HEAP-> CollectAllGarbage(true); // This should move the stub
Steve Block1e0659c2011-05-24 12:43:12 +01008537 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
8538 }
8539 return v8::Handle<v8::Value>();
8540}
8541
8542
8543THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
8544 v8::HandleScope scope;
8545 LocalContext context;
8546 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
8547 nativeobject_templ->Set("callback",
8548 v8::FunctionTemplate::New(DirectApiCallback));
8549 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
8550 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
8551 // call the api function multiple times to ensure direct call stub creation.
8552 CompileRun(
8553 "function f() {"
8554 " for (var i = 1; i <= 30; i++) {"
8555 " nativeobject.callback();"
8556 " }"
8557 "}"
8558 "f();");
8559}
8560
8561
8562v8::Handle<v8::Value> ThrowingDirectApiCallback(const v8::Arguments& args) {
8563 return v8::ThrowException(v8_str("g"));
8564}
8565
8566
8567THREADED_TEST(CallICFastApi_DirectCall_Throw) {
8568 v8::HandleScope scope;
8569 LocalContext context;
8570 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
8571 nativeobject_templ->Set("callback",
8572 v8::FunctionTemplate::New(ThrowingDirectApiCallback));
8573 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
8574 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
8575 // call the api function multiple times to ensure direct call stub creation.
8576 v8::Handle<Value> result = CompileRun(
8577 "var result = '';"
8578 "function f() {"
8579 " for (var i = 1; i <= 5; i++) {"
8580 " try { nativeobject.callback(); } catch (e) { result += e; }"
8581 " }"
8582 "}"
8583 "f(); result;");
8584 CHECK_EQ(v8_str("ggggg"), result);
8585}
8586
8587
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008588v8::Handle<v8::Value> DirectGetterCallback(Local<String> name,
8589 const v8::AccessorInfo& info) {
8590 if (++p_getter_count % 3 == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01008591 HEAP->CollectAllGarbage(true);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008592 GenerateSomeGarbage();
8593 }
8594 return v8::Handle<v8::Value>();
8595}
8596
8597
8598THREADED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
8599 v8::HandleScope scope;
8600 LocalContext context;
8601 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
8602 obj->SetAccessor(v8_str("p1"), DirectGetterCallback);
8603 context->Global()->Set(v8_str("o1"), obj->NewInstance());
8604 p_getter_count = 0;
8605 CompileRun(
8606 "function f() {"
8607 " for (var i = 0; i < 30; i++) o1.p1;"
8608 "}"
8609 "f();");
8610 CHECK_EQ(30, p_getter_count);
8611}
8612
8613
8614v8::Handle<v8::Value> ThrowingDirectGetterCallback(
8615 Local<String> name, const v8::AccessorInfo& info) {
8616 return v8::ThrowException(v8_str("g"));
8617}
8618
8619
8620THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
8621 v8::HandleScope scope;
8622 LocalContext context;
8623 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
8624 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
8625 context->Global()->Set(v8_str("o1"), obj->NewInstance());
8626 v8::Handle<Value> result = CompileRun(
8627 "var result = '';"
8628 "for (var i = 0; i < 5; i++) {"
8629 " try { o1.p1; } catch (e) { result += e; }"
8630 "}"
8631 "result;");
8632 CHECK_EQ(v8_str("ggggg"), result);
8633}
8634
8635
Andrei Popescu402d9372010-02-26 13:31:12 +00008636THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
8637 int interceptor_call_count = 0;
8638 v8::HandleScope scope;
8639 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8640 v8::Handle<v8::FunctionTemplate> method_templ =
8641 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
8642 v8_str("method_data"),
8643 v8::Handle<v8::Signature>());
8644 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8645 proto_templ->Set(v8_str("method"), method_templ);
8646 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8647 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8648 NULL, NULL, NULL, NULL,
8649 v8::External::Wrap(&interceptor_call_count));
8650 LocalContext context;
8651 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8652 GenerateSomeGarbage();
8653 context->Global()->Set(v8_str("o"), fun->NewInstance());
8654 v8::Handle<Value> value = CompileRun(
8655 "var result = 0;"
8656 "for (var i = 0; i < 100; i++) {"
8657 " result = o.method(41);"
8658 "}");
8659 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
8660 CHECK_EQ(100, interceptor_call_count);
8661}
8662
8663THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
8664 int interceptor_call_count = 0;
8665 v8::HandleScope scope;
8666 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8667 v8::Handle<v8::FunctionTemplate> method_templ =
8668 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8669 v8_str("method_data"),
8670 v8::Signature::New(fun_templ));
8671 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8672 proto_templ->Set(v8_str("method"), method_templ);
8673 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8674 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8675 NULL, NULL, NULL, NULL,
8676 v8::External::Wrap(&interceptor_call_count));
8677 LocalContext context;
8678 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8679 GenerateSomeGarbage();
8680 context->Global()->Set(v8_str("o"), fun->NewInstance());
8681 v8::Handle<Value> value = CompileRun(
8682 "o.foo = 17;"
8683 "var receiver = {};"
8684 "receiver.__proto__ = o;"
8685 "var result = 0;"
8686 "for (var i = 0; i < 100; i++) {"
8687 " result = receiver.method(41);"
8688 "}");
8689 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
8690 CHECK_EQ(100, interceptor_call_count);
8691}
8692
8693THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
8694 int interceptor_call_count = 0;
8695 v8::HandleScope scope;
8696 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8697 v8::Handle<v8::FunctionTemplate> method_templ =
8698 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8699 v8_str("method_data"),
8700 v8::Signature::New(fun_templ));
8701 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8702 proto_templ->Set(v8_str("method"), method_templ);
8703 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8704 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8705 NULL, NULL, NULL, NULL,
8706 v8::External::Wrap(&interceptor_call_count));
8707 LocalContext context;
8708 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8709 GenerateSomeGarbage();
8710 context->Global()->Set(v8_str("o"), fun->NewInstance());
8711 v8::Handle<Value> value = CompileRun(
8712 "o.foo = 17;"
8713 "var receiver = {};"
8714 "receiver.__proto__ = o;"
8715 "var result = 0;"
8716 "var saved_result = 0;"
8717 "for (var i = 0; i < 100; i++) {"
8718 " result = receiver.method(41);"
8719 " if (i == 50) {"
8720 " saved_result = result;"
8721 " receiver = {method: function(x) { return x - 1 }};"
8722 " }"
8723 "}");
8724 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
8725 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8726 CHECK_GE(interceptor_call_count, 50);
8727}
8728
8729THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
8730 int interceptor_call_count = 0;
8731 v8::HandleScope scope;
8732 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8733 v8::Handle<v8::FunctionTemplate> method_templ =
8734 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8735 v8_str("method_data"),
8736 v8::Signature::New(fun_templ));
8737 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8738 proto_templ->Set(v8_str("method"), method_templ);
8739 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8740 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8741 NULL, NULL, NULL, NULL,
8742 v8::External::Wrap(&interceptor_call_count));
8743 LocalContext context;
8744 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8745 GenerateSomeGarbage();
8746 context->Global()->Set(v8_str("o"), fun->NewInstance());
8747 v8::Handle<Value> value = CompileRun(
8748 "o.foo = 17;"
8749 "var receiver = {};"
8750 "receiver.__proto__ = o;"
8751 "var result = 0;"
8752 "var saved_result = 0;"
8753 "for (var i = 0; i < 100; i++) {"
8754 " result = receiver.method(41);"
8755 " if (i == 50) {"
8756 " saved_result = result;"
8757 " o.method = function(x) { return x - 1 };"
8758 " }"
8759 "}");
8760 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
8761 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8762 CHECK_GE(interceptor_call_count, 50);
8763}
8764
Steve Block6ded16b2010-05-10 14:33:55 +01008765THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
8766 int interceptor_call_count = 0;
8767 v8::HandleScope scope;
8768 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8769 v8::Handle<v8::FunctionTemplate> method_templ =
8770 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8771 v8_str("method_data"),
8772 v8::Signature::New(fun_templ));
8773 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8774 proto_templ->Set(v8_str("method"), method_templ);
8775 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8776 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8777 NULL, NULL, NULL, NULL,
8778 v8::External::Wrap(&interceptor_call_count));
8779 LocalContext context;
8780 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8781 GenerateSomeGarbage();
8782 context->Global()->Set(v8_str("o"), fun->NewInstance());
8783 v8::TryCatch try_catch;
8784 v8::Handle<Value> value = CompileRun(
8785 "o.foo = 17;"
8786 "var receiver = {};"
8787 "receiver.__proto__ = o;"
8788 "var result = 0;"
8789 "var saved_result = 0;"
8790 "for (var i = 0; i < 100; i++) {"
8791 " result = receiver.method(41);"
8792 " if (i == 50) {"
8793 " saved_result = result;"
8794 " receiver = 333;"
8795 " }"
8796 "}");
8797 CHECK(try_catch.HasCaught());
8798 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
8799 try_catch.Exception()->ToString());
8800 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8801 CHECK_GE(interceptor_call_count, 50);
8802}
8803
Andrei Popescu402d9372010-02-26 13:31:12 +00008804THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
8805 int interceptor_call_count = 0;
8806 v8::HandleScope scope;
8807 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8808 v8::Handle<v8::FunctionTemplate> method_templ =
8809 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8810 v8_str("method_data"),
8811 v8::Signature::New(fun_templ));
8812 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8813 proto_templ->Set(v8_str("method"), method_templ);
8814 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8815 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8816 NULL, NULL, NULL, NULL,
8817 v8::External::Wrap(&interceptor_call_count));
8818 LocalContext context;
8819 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8820 GenerateSomeGarbage();
8821 context->Global()->Set(v8_str("o"), fun->NewInstance());
8822 v8::TryCatch try_catch;
8823 v8::Handle<Value> value = CompileRun(
8824 "o.foo = 17;"
8825 "var receiver = {};"
8826 "receiver.__proto__ = o;"
8827 "var result = 0;"
8828 "var saved_result = 0;"
8829 "for (var i = 0; i < 100; i++) {"
8830 " result = receiver.method(41);"
8831 " if (i == 50) {"
8832 " saved_result = result;"
8833 " receiver = {method: receiver.method};"
8834 " }"
8835 "}");
8836 CHECK(try_catch.HasCaught());
8837 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
8838 try_catch.Exception()->ToString());
8839 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8840 CHECK_GE(interceptor_call_count, 50);
8841}
8842
8843THREADED_TEST(CallICFastApi_TrivialSignature) {
8844 v8::HandleScope scope;
8845 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8846 v8::Handle<v8::FunctionTemplate> method_templ =
8847 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
8848 v8_str("method_data"),
8849 v8::Handle<v8::Signature>());
8850 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8851 proto_templ->Set(v8_str("method"), method_templ);
8852 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8853 LocalContext context;
8854 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8855 GenerateSomeGarbage();
8856 context->Global()->Set(v8_str("o"), fun->NewInstance());
8857 v8::Handle<Value> value = CompileRun(
8858 "var result = 0;"
8859 "for (var i = 0; i < 100; i++) {"
8860 " result = o.method(41);"
8861 "}");
8862
8863 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
8864}
8865
8866THREADED_TEST(CallICFastApi_SimpleSignature) {
8867 v8::HandleScope scope;
8868 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8869 v8::Handle<v8::FunctionTemplate> method_templ =
8870 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8871 v8_str("method_data"),
8872 v8::Signature::New(fun_templ));
8873 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8874 proto_templ->Set(v8_str("method"), method_templ);
8875 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8876 LocalContext context;
8877 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8878 GenerateSomeGarbage();
8879 context->Global()->Set(v8_str("o"), fun->NewInstance());
8880 v8::Handle<Value> value = CompileRun(
8881 "o.foo = 17;"
8882 "var receiver = {};"
8883 "receiver.__proto__ = o;"
8884 "var result = 0;"
8885 "for (var i = 0; i < 100; i++) {"
8886 " result = receiver.method(41);"
8887 "}");
8888
8889 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
8890}
8891
Steve Block6ded16b2010-05-10 14:33:55 +01008892THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) {
Andrei Popescu402d9372010-02-26 13:31:12 +00008893 v8::HandleScope scope;
8894 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8895 v8::Handle<v8::FunctionTemplate> method_templ =
8896 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8897 v8_str("method_data"),
8898 v8::Signature::New(fun_templ));
8899 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8900 proto_templ->Set(v8_str("method"), method_templ);
8901 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8902 LocalContext context;
8903 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8904 GenerateSomeGarbage();
8905 context->Global()->Set(v8_str("o"), fun->NewInstance());
8906 v8::Handle<Value> value = CompileRun(
8907 "o.foo = 17;"
8908 "var receiver = {};"
8909 "receiver.__proto__ = o;"
8910 "var result = 0;"
8911 "var saved_result = 0;"
8912 "for (var i = 0; i < 100; i++) {"
8913 " result = receiver.method(41);"
8914 " if (i == 50) {"
8915 " saved_result = result;"
8916 " receiver = {method: function(x) { return x - 1 }};"
8917 " }"
8918 "}");
8919 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
8920 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8921}
8922
Steve Block6ded16b2010-05-10 14:33:55 +01008923THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) {
8924 v8::HandleScope scope;
8925 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8926 v8::Handle<v8::FunctionTemplate> method_templ =
8927 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8928 v8_str("method_data"),
8929 v8::Signature::New(fun_templ));
8930 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8931 proto_templ->Set(v8_str("method"), method_templ);
8932 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8933 LocalContext context;
8934 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8935 GenerateSomeGarbage();
8936 context->Global()->Set(v8_str("o"), fun->NewInstance());
8937 v8::TryCatch try_catch;
8938 v8::Handle<Value> value = CompileRun(
8939 "o.foo = 17;"
8940 "var receiver = {};"
8941 "receiver.__proto__ = o;"
8942 "var result = 0;"
8943 "var saved_result = 0;"
8944 "for (var i = 0; i < 100; i++) {"
8945 " result = receiver.method(41);"
8946 " if (i == 50) {"
8947 " saved_result = result;"
8948 " receiver = 333;"
8949 " }"
8950 "}");
8951 CHECK(try_catch.HasCaught());
8952 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
8953 try_catch.Exception()->ToString());
8954 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8955}
8956
Leon Clarke4515c472010-02-03 11:58:03 +00008957
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008958v8::Handle<Value> keyed_call_ic_function;
8959
8960static v8::Handle<Value> InterceptorKeyedCallICGetter(
8961 Local<String> name, const AccessorInfo& info) {
8962 ApiTestFuzzer::Fuzz();
8963 if (v8_str("x")->Equals(name)) {
8964 return keyed_call_ic_function;
8965 }
8966 return v8::Handle<Value>();
8967}
8968
8969
8970// Test the case when we stored cacheable lookup into
8971// a stub, but the function name changed (to another cacheable function).
8972THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
8973 v8::HandleScope scope;
8974 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8975 templ->SetNamedPropertyHandler(NoBlockGetterX);
8976 LocalContext context;
8977 context->Global()->Set(v8_str("o"), templ->NewInstance());
8978 v8::Handle<Value> value = CompileRun(
8979 "proto = new Object();"
8980 "proto.y = function(x) { return x + 1; };"
8981 "proto.z = function(x) { return x - 1; };"
8982 "o.__proto__ = proto;"
8983 "var result = 0;"
8984 "var method = 'y';"
8985 "for (var i = 0; i < 10; i++) {"
8986 " if (i == 5) { method = 'z'; };"
8987 " result += o[method](41);"
8988 "}");
8989 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
8990}
8991
8992
8993// Test the case when we stored cacheable lookup into
8994// a stub, but the function name changed (and the new function is present
8995// both before and after the interceptor in the prototype chain).
8996THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
8997 v8::HandleScope scope;
8998 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8999 templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
9000 LocalContext context;
9001 context->Global()->Set(v8_str("proto1"), templ->NewInstance());
9002 keyed_call_ic_function =
9003 v8_compile("function f(x) { return x - 1; }; f")->Run();
9004 v8::Handle<Value> value = CompileRun(
9005 "o = new Object();"
9006 "proto2 = new Object();"
9007 "o.y = function(x) { return x + 1; };"
9008 "proto2.y = function(x) { return x + 2; };"
9009 "o.__proto__ = proto1;"
9010 "proto1.__proto__ = proto2;"
9011 "var result = 0;"
9012 "var method = 'x';"
9013 "for (var i = 0; i < 10; i++) {"
9014 " if (i == 5) { method = 'y'; };"
9015 " result += o[method](41);"
9016 "}");
9017 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9018}
9019
9020
9021// Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
9022// on the global object.
9023THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
9024 v8::HandleScope scope;
9025 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9026 templ->SetNamedPropertyHandler(NoBlockGetterX);
9027 LocalContext context;
9028 context->Global()->Set(v8_str("o"), templ->NewInstance());
9029 v8::Handle<Value> value = CompileRun(
9030 "function inc(x) { return x + 1; };"
9031 "inc(1);"
9032 "function dec(x) { return x - 1; };"
9033 "dec(1);"
9034 "o.__proto__ = this;"
9035 "this.__proto__.x = inc;"
9036 "this.__proto__.y = dec;"
9037 "var result = 0;"
9038 "var method = 'x';"
9039 "for (var i = 0; i < 10; i++) {"
9040 " if (i == 5) { method = 'y'; };"
9041 " result += o[method](41);"
9042 "}");
9043 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9044}
9045
9046
9047// Test the case when actual function to call sits on global object.
9048THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
9049 v8::HandleScope scope;
9050 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9051 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9052 LocalContext context;
9053 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9054
9055 v8::Handle<Value> value = CompileRun(
9056 "function len(x) { return x.length; };"
9057 "o.__proto__ = this;"
9058 "var m = 'parseFloat';"
9059 "var result = 0;"
9060 "for (var i = 0; i < 10; i++) {"
9061 " if (i == 5) {"
9062 " m = 'len';"
9063 " saved_result = result;"
9064 " };"
9065 " result = o[m]('239');"
9066 "}");
9067 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
9068 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9069}
9070
9071// Test the map transition before the interceptor.
9072THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
9073 v8::HandleScope scope;
9074 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9075 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9076 LocalContext context;
9077 context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
9078
9079 v8::Handle<Value> value = CompileRun(
9080 "var o = new Object();"
9081 "o.__proto__ = proto;"
9082 "o.method = function(x) { return x + 1; };"
9083 "var m = 'method';"
9084 "var result = 0;"
9085 "for (var i = 0; i < 10; i++) {"
9086 " if (i == 5) { o.method = function(x) { return x - 1; }; };"
9087 " result += o[m](41);"
9088 "}");
9089 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9090}
9091
9092
9093// Test the map transition after the interceptor.
9094THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
9095 v8::HandleScope scope;
9096 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9097 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9098 LocalContext context;
9099 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9100
9101 v8::Handle<Value> value = CompileRun(
9102 "var proto = new Object();"
9103 "o.__proto__ = proto;"
9104 "proto.method = function(x) { return x + 1; };"
9105 "var m = 'method';"
9106 "var result = 0;"
9107 "for (var i = 0; i < 10; i++) {"
9108 " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
9109 " result += o[m](41);"
9110 "}");
9111 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9112}
9113
9114
Steve Blocka7e24c12009-10-30 11:49:00 +00009115static int interceptor_call_count = 0;
9116
9117static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
9118 const AccessorInfo& info) {
9119 ApiTestFuzzer::Fuzz();
9120 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
9121 return call_ic_function2;
9122 }
9123 return v8::Handle<Value>();
9124}
9125
9126
9127// This test should hit load and call ICs for the interceptor case.
9128// Once in a while, the interceptor will reply that a property was not
9129// found in which case we should get a reference error.
9130THREADED_TEST(InterceptorICReferenceErrors) {
9131 v8::HandleScope scope;
9132 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9133 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
9134 LocalContext context(0, templ, v8::Handle<Value>());
9135 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
9136 v8::Handle<Value> value = CompileRun(
9137 "function f() {"
9138 " for (var i = 0; i < 1000; i++) {"
9139 " try { x; } catch(e) { return true; }"
9140 " }"
9141 " return false;"
9142 "};"
9143 "f();");
9144 CHECK_EQ(true, value->BooleanValue());
9145 interceptor_call_count = 0;
9146 value = CompileRun(
9147 "function g() {"
9148 " for (var i = 0; i < 1000; i++) {"
9149 " try { x(42); } catch(e) { return true; }"
9150 " }"
9151 " return false;"
9152 "};"
9153 "g();");
9154 CHECK_EQ(true, value->BooleanValue());
9155}
9156
9157
9158static int interceptor_ic_exception_get_count = 0;
9159
9160static v8::Handle<Value> InterceptorICExceptionGetter(
9161 Local<String> name,
9162 const AccessorInfo& info) {
9163 ApiTestFuzzer::Fuzz();
9164 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
9165 return call_ic_function3;
9166 }
9167 if (interceptor_ic_exception_get_count == 20) {
9168 return v8::ThrowException(v8_num(42));
9169 }
9170 // Do not handle get for properties other than x.
9171 return v8::Handle<Value>();
9172}
9173
9174// Test interceptor load/call IC where the interceptor throws an
9175// exception once in a while.
9176THREADED_TEST(InterceptorICGetterExceptions) {
9177 interceptor_ic_exception_get_count = 0;
9178 v8::HandleScope scope;
9179 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9180 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
9181 LocalContext context(0, templ, v8::Handle<Value>());
9182 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
9183 v8::Handle<Value> value = CompileRun(
9184 "function f() {"
9185 " for (var i = 0; i < 100; i++) {"
9186 " try { x; } catch(e) { return true; }"
9187 " }"
9188 " return false;"
9189 "};"
9190 "f();");
9191 CHECK_EQ(true, value->BooleanValue());
9192 interceptor_ic_exception_get_count = 0;
9193 value = CompileRun(
9194 "function f() {"
9195 " for (var i = 0; i < 100; i++) {"
9196 " try { x(42); } catch(e) { return true; }"
9197 " }"
9198 " return false;"
9199 "};"
9200 "f();");
9201 CHECK_EQ(true, value->BooleanValue());
9202}
9203
9204
9205static int interceptor_ic_exception_set_count = 0;
9206
9207static v8::Handle<Value> InterceptorICExceptionSetter(
9208 Local<String> key, Local<Value> value, const AccessorInfo&) {
9209 ApiTestFuzzer::Fuzz();
9210 if (++interceptor_ic_exception_set_count > 20) {
9211 return v8::ThrowException(v8_num(42));
9212 }
9213 // Do not actually handle setting.
9214 return v8::Handle<Value>();
9215}
9216
9217// Test interceptor store IC where the interceptor throws an exception
9218// once in a while.
9219THREADED_TEST(InterceptorICSetterExceptions) {
9220 interceptor_ic_exception_set_count = 0;
9221 v8::HandleScope scope;
9222 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9223 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
9224 LocalContext context(0, templ, v8::Handle<Value>());
9225 v8::Handle<Value> value = CompileRun(
9226 "function f() {"
9227 " for (var i = 0; i < 100; i++) {"
9228 " try { x = 42; } catch(e) { return true; }"
9229 " }"
9230 " return false;"
9231 "};"
9232 "f();");
9233 CHECK_EQ(true, value->BooleanValue());
9234}
9235
9236
9237// Test that we ignore null interceptors.
9238THREADED_TEST(NullNamedInterceptor) {
9239 v8::HandleScope scope;
9240 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9241 templ->SetNamedPropertyHandler(0);
9242 LocalContext context;
9243 templ->Set("x", v8_num(42));
9244 v8::Handle<v8::Object> obj = templ->NewInstance();
9245 context->Global()->Set(v8_str("obj"), obj);
9246 v8::Handle<Value> value = CompileRun("obj.x");
9247 CHECK(value->IsInt32());
9248 CHECK_EQ(42, value->Int32Value());
9249}
9250
9251
9252// Test that we ignore null interceptors.
9253THREADED_TEST(NullIndexedInterceptor) {
9254 v8::HandleScope scope;
9255 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9256 templ->SetIndexedPropertyHandler(0);
9257 LocalContext context;
9258 templ->Set("42", v8_num(42));
9259 v8::Handle<v8::Object> obj = templ->NewInstance();
9260 context->Global()->Set(v8_str("obj"), obj);
9261 v8::Handle<Value> value = CompileRun("obj[42]");
9262 CHECK(value->IsInt32());
9263 CHECK_EQ(42, value->Int32Value());
9264}
9265
9266
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009267THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
9268 v8::HandleScope scope;
9269 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9270 templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9271 LocalContext env;
9272 env->Global()->Set(v8_str("obj"),
9273 templ->GetFunction()->NewInstance());
9274 ExpectTrue("obj.x === 42");
9275 ExpectTrue("!obj.propertyIsEnumerable('x')");
9276}
9277
9278
Ben Murdoch8b112d22011-06-08 16:22:53 +01009279static Handle<Value> ThrowingGetter(Local<String> name,
9280 const AccessorInfo& info) {
9281 ApiTestFuzzer::Fuzz();
9282 ThrowException(Handle<Value>());
9283 return Undefined();
9284}
9285
9286
9287THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
9288 HandleScope scope;
9289 LocalContext context;
9290
9291 Local<FunctionTemplate> templ = FunctionTemplate::New();
9292 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
9293 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
9294
9295 Local<Object> instance = templ->GetFunction()->NewInstance();
9296
9297 Local<Object> another = Object::New();
9298 another->SetPrototype(instance);
9299
9300 Local<Object> with_js_getter = CompileRun(
9301 "o = {};\n"
9302 "o.__defineGetter__('f', function() { throw undefined; });\n"
9303 "o\n").As<Object>();
9304 CHECK(!with_js_getter.IsEmpty());
9305
9306 TryCatch try_catch;
9307
9308 Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
9309 CHECK(try_catch.HasCaught());
9310 try_catch.Reset();
9311 CHECK(result.IsEmpty());
9312
9313 result = another->GetRealNamedProperty(v8_str("f"));
9314 CHECK(try_catch.HasCaught());
9315 try_catch.Reset();
9316 CHECK(result.IsEmpty());
9317
9318 result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
9319 CHECK(try_catch.HasCaught());
9320 try_catch.Reset();
9321 CHECK(result.IsEmpty());
9322
9323 result = another->Get(v8_str("f"));
9324 CHECK(try_catch.HasCaught());
9325 try_catch.Reset();
9326 CHECK(result.IsEmpty());
9327
9328 result = with_js_getter->GetRealNamedProperty(v8_str("f"));
9329 CHECK(try_catch.HasCaught());
9330 try_catch.Reset();
9331 CHECK(result.IsEmpty());
9332
9333 result = with_js_getter->Get(v8_str("f"));
9334 CHECK(try_catch.HasCaught());
9335 try_catch.Reset();
9336 CHECK(result.IsEmpty());
9337}
9338
9339
9340static Handle<Value> ThrowingCallbackWithTryCatch(const Arguments& args) {
9341 TryCatch try_catch;
9342 // Verboseness is important: it triggers message delivery which can call into
9343 // external code.
9344 try_catch.SetVerbose(true);
9345 CompileRun("throw 'from JS';");
9346 CHECK(try_catch.HasCaught());
9347 CHECK(!i::Isolate::Current()->has_pending_exception());
9348 CHECK(!i::Isolate::Current()->has_scheduled_exception());
9349 return Undefined();
9350}
9351
9352
9353static int call_depth;
9354
9355
9356static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
9357 TryCatch try_catch;
9358}
9359
9360
9361static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
9362 if (--call_depth) CompileRun("throw 'ThrowInJS';");
9363}
9364
9365
9366static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
9367 if (--call_depth) ThrowException(v8_str("ThrowViaApi"));
9368}
9369
9370
9371static void WebKitLike(Handle<Message> message, Handle<Value> data) {
9372 Handle<String> errorMessageString = message->Get();
9373 CHECK(!errorMessageString.IsEmpty());
9374 message->GetStackTrace();
9375 message->GetScriptResourceName();
9376}
9377
9378THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
9379 HandleScope scope;
9380 LocalContext context;
9381
9382 Local<Function> func =
9383 FunctionTemplate::New(ThrowingCallbackWithTryCatch)->GetFunction();
9384 context->Global()->Set(v8_str("func"), func);
9385
9386 MessageCallback callbacks[] =
9387 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
9388 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
9389 MessageCallback callback = callbacks[i];
9390 if (callback != NULL) {
9391 V8::AddMessageListener(callback);
9392 }
Ben Murdoch257744e2011-11-30 15:57:28 +00009393 // Some small number to control number of times message handler should
9394 // throw an exception.
Ben Murdoch8b112d22011-06-08 16:22:53 +01009395 call_depth = 5;
9396 ExpectFalse(
9397 "var thrown = false;\n"
9398 "try { func(); } catch(e) { thrown = true; }\n"
9399 "thrown\n");
9400 if (callback != NULL) {
9401 V8::RemoveMessageListeners(callback);
9402 }
9403 }
9404}
9405
9406
Steve Blocka7e24c12009-10-30 11:49:00 +00009407static v8::Handle<Value> ParentGetter(Local<String> name,
9408 const AccessorInfo& info) {
9409 ApiTestFuzzer::Fuzz();
9410 return v8_num(1);
9411}
9412
9413
9414static v8::Handle<Value> ChildGetter(Local<String> name,
9415 const AccessorInfo& info) {
9416 ApiTestFuzzer::Fuzz();
9417 return v8_num(42);
9418}
9419
9420
9421THREADED_TEST(Overriding) {
9422 v8::HandleScope scope;
9423 LocalContext context;
9424
9425 // Parent template.
9426 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
9427 Local<ObjectTemplate> parent_instance_templ =
9428 parent_templ->InstanceTemplate();
9429 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
9430
9431 // Template that inherits from the parent template.
9432 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
9433 Local<ObjectTemplate> child_instance_templ =
9434 child_templ->InstanceTemplate();
9435 child_templ->Inherit(parent_templ);
9436 // Override 'f'. The child version of 'f' should get called for child
9437 // instances.
9438 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
9439 // Add 'g' twice. The 'g' added last should get called for instances.
9440 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
9441 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
9442
9443 // Add 'h' as an accessor to the proto template with ReadOnly attributes
9444 // so 'h' can be shadowed on the instance object.
9445 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
9446 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
9447 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
9448
9449 // Add 'i' as an accessor to the instance template with ReadOnly attributes
9450 // but the attribute does not have effect because it is duplicated with
9451 // NULL setter.
9452 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
9453 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
9454
9455
9456
9457 // Instantiate the child template.
9458 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
9459
9460 // Check that the child function overrides the parent one.
9461 context->Global()->Set(v8_str("o"), instance);
9462 Local<Value> value = v8_compile("o.f")->Run();
9463 // Check that the 'g' that was added last is hit.
9464 CHECK_EQ(42, value->Int32Value());
9465 value = v8_compile("o.g")->Run();
9466 CHECK_EQ(42, value->Int32Value());
9467
9468 // Check 'h' can be shadowed.
9469 value = v8_compile("o.h = 3; o.h")->Run();
9470 CHECK_EQ(3, value->Int32Value());
9471
9472 // Check 'i' is cannot be shadowed or changed.
9473 value = v8_compile("o.i = 3; o.i")->Run();
9474 CHECK_EQ(42, value->Int32Value());
9475}
9476
9477
9478static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
9479 ApiTestFuzzer::Fuzz();
9480 if (args.IsConstructCall()) {
9481 return v8::Boolean::New(true);
9482 }
9483 return v8::Boolean::New(false);
9484}
9485
9486
9487THREADED_TEST(IsConstructCall) {
9488 v8::HandleScope scope;
9489
9490 // Function template with call handler.
9491 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9492 templ->SetCallHandler(IsConstructHandler);
9493
9494 LocalContext context;
9495
9496 context->Global()->Set(v8_str("f"), templ->GetFunction());
9497 Local<Value> value = v8_compile("f()")->Run();
9498 CHECK(!value->BooleanValue());
9499 value = v8_compile("new f()")->Run();
9500 CHECK(value->BooleanValue());
9501}
9502
9503
9504THREADED_TEST(ObjectProtoToString) {
9505 v8::HandleScope scope;
9506 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9507 templ->SetClassName(v8_str("MyClass"));
9508
9509 LocalContext context;
9510
9511 Local<String> customized_tostring = v8_str("customized toString");
9512
9513 // Replace Object.prototype.toString
9514 v8_compile("Object.prototype.toString = function() {"
9515 " return 'customized toString';"
9516 "}")->Run();
9517
9518 // Normal ToString call should call replaced Object.prototype.toString
9519 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
9520 Local<String> value = instance->ToString();
9521 CHECK(value->IsString() && value->Equals(customized_tostring));
9522
9523 // ObjectProtoToString should not call replace toString function.
9524 value = instance->ObjectProtoToString();
9525 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
9526
9527 // Check global
9528 value = context->Global()->ObjectProtoToString();
9529 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
9530
9531 // Check ordinary object
9532 Local<Value> object = v8_compile("new Object()")->Run();
Steve Block6ded16b2010-05-10 14:33:55 +01009533 value = object.As<v8::Object>()->ObjectProtoToString();
Steve Blocka7e24c12009-10-30 11:49:00 +00009534 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
9535}
9536
9537
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08009538THREADED_TEST(ObjectGetConstructorName) {
9539 v8::HandleScope scope;
9540 LocalContext context;
9541 v8_compile("function Parent() {};"
9542 "function Child() {};"
9543 "Child.prototype = new Parent();"
9544 "var outer = { inner: function() { } };"
9545 "var p = new Parent();"
9546 "var c = new Child();"
9547 "var x = new outer.inner();")->Run();
9548
9549 Local<v8::Value> p = context->Global()->Get(v8_str("p"));
9550 CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
9551 v8_str("Parent")));
9552
9553 Local<v8::Value> c = context->Global()->Get(v8_str("c"));
9554 CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
9555 v8_str("Child")));
9556
9557 Local<v8::Value> x = context->Global()->Get(v8_str("x"));
9558 CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
9559 v8_str("outer.inner")));
9560}
9561
9562
Steve Blocka7e24c12009-10-30 11:49:00 +00009563bool ApiTestFuzzer::fuzzing_ = false;
Steve Block8defd9f2010-07-08 12:39:36 +01009564i::Semaphore* ApiTestFuzzer::all_tests_done_=
9565 i::OS::CreateSemaphore(0);
Steve Blocka7e24c12009-10-30 11:49:00 +00009566int ApiTestFuzzer::active_tests_;
9567int ApiTestFuzzer::tests_being_run_;
9568int ApiTestFuzzer::current_;
9569
9570
9571// We are in a callback and want to switch to another thread (if we
9572// are currently running the thread fuzzing test).
9573void ApiTestFuzzer::Fuzz() {
9574 if (!fuzzing_) return;
9575 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
9576 test->ContextSwitch();
9577}
9578
9579
9580// Let the next thread go. Since it is also waiting on the V8 lock it may
9581// not start immediately.
9582bool ApiTestFuzzer::NextThread() {
9583 int test_position = GetNextTestNumber();
Steve Blockd0582a62009-12-15 09:54:21 +00009584 const char* test_name = RegisterThreadedTest::nth(current_)->name();
Steve Blocka7e24c12009-10-30 11:49:00 +00009585 if (test_position == current_) {
Steve Blockd0582a62009-12-15 09:54:21 +00009586 if (kLogThreading)
9587 printf("Stay with %s\n", test_name);
Steve Blocka7e24c12009-10-30 11:49:00 +00009588 return false;
9589 }
Steve Blockd0582a62009-12-15 09:54:21 +00009590 if (kLogThreading) {
9591 printf("Switch from %s to %s\n",
9592 test_name,
9593 RegisterThreadedTest::nth(test_position)->name());
9594 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009595 current_ = test_position;
9596 RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
9597 return true;
9598}
9599
9600
9601void ApiTestFuzzer::Run() {
9602 // When it is our turn...
9603 gate_->Wait();
9604 {
9605 // ... get the V8 lock and start running the test.
9606 v8::Locker locker;
9607 CallTest();
9608 }
9609 // This test finished.
9610 active_ = false;
9611 active_tests_--;
9612 // If it was the last then signal that fact.
9613 if (active_tests_ == 0) {
9614 all_tests_done_->Signal();
9615 } else {
9616 // Otherwise select a new test and start that.
9617 NextThread();
9618 }
9619}
9620
9621
9622static unsigned linear_congruential_generator;
9623
9624
9625void ApiTestFuzzer::Setup(PartOfTest part) {
9626 linear_congruential_generator = i::FLAG_testing_prng_seed;
9627 fuzzing_ = true;
Ben Murdoch257744e2011-11-30 15:57:28 +00009628 int count = RegisterThreadedTest::count();
9629 int start = count * part / (LAST_PART + 1);
9630 int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
9631 active_tests_ = tests_being_run_ = end - start + 1;
Steve Blocka7e24c12009-10-30 11:49:00 +00009632 for (int i = 0; i < tests_being_run_; i++) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009633 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
Steve Blocka7e24c12009-10-30 11:49:00 +00009634 }
9635 for (int i = 0; i < active_tests_; i++) {
9636 RegisterThreadedTest::nth(i)->fuzzer_->Start();
9637 }
9638}
9639
9640
9641static void CallTestNumber(int test_number) {
9642 (RegisterThreadedTest::nth(test_number)->callback())();
9643}
9644
9645
9646void ApiTestFuzzer::RunAllTests() {
9647 // Set off the first test.
9648 current_ = -1;
9649 NextThread();
9650 // Wait till they are all done.
9651 all_tests_done_->Wait();
9652}
9653
9654
9655int ApiTestFuzzer::GetNextTestNumber() {
9656 int next_test;
9657 do {
9658 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
9659 linear_congruential_generator *= 1664525u;
9660 linear_congruential_generator += 1013904223u;
9661 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
9662 return next_test;
9663}
9664
9665
9666void ApiTestFuzzer::ContextSwitch() {
9667 // If the new thread is the same as the current thread there is nothing to do.
9668 if (NextThread()) {
9669 // Now it can start.
9670 v8::Unlocker unlocker;
9671 // Wait till someone starts us again.
9672 gate_->Wait();
9673 // And we're off.
9674 }
9675}
9676
9677
9678void ApiTestFuzzer::TearDown() {
9679 fuzzing_ = false;
9680 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
9681 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
9682 if (fuzzer != NULL) fuzzer->Join();
9683 }
9684}
9685
9686
9687// Lets not be needlessly self-referential.
9688TEST(Threading) {
9689 ApiTestFuzzer::Setup(ApiTestFuzzer::FIRST_PART);
9690 ApiTestFuzzer::RunAllTests();
9691 ApiTestFuzzer::TearDown();
9692}
9693
9694TEST(Threading2) {
9695 ApiTestFuzzer::Setup(ApiTestFuzzer::SECOND_PART);
9696 ApiTestFuzzer::RunAllTests();
9697 ApiTestFuzzer::TearDown();
9698}
9699
Ben Murdoch257744e2011-11-30 15:57:28 +00009700TEST(Threading3) {
9701 ApiTestFuzzer::Setup(ApiTestFuzzer::THIRD_PART);
9702 ApiTestFuzzer::RunAllTests();
9703 ApiTestFuzzer::TearDown();
9704}
9705
9706TEST(Threading4) {
9707 ApiTestFuzzer::Setup(ApiTestFuzzer::FOURTH_PART);
9708 ApiTestFuzzer::RunAllTests();
9709 ApiTestFuzzer::TearDown();
9710}
Steve Blocka7e24c12009-10-30 11:49:00 +00009711
9712void ApiTestFuzzer::CallTest() {
Steve Blockd0582a62009-12-15 09:54:21 +00009713 if (kLogThreading)
9714 printf("Start test %d\n", test_number_);
Steve Blocka7e24c12009-10-30 11:49:00 +00009715 CallTestNumber(test_number_);
Steve Blockd0582a62009-12-15 09:54:21 +00009716 if (kLogThreading)
9717 printf("End test %d\n", test_number_);
Steve Blocka7e24c12009-10-30 11:49:00 +00009718}
9719
9720
9721static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
9722 CHECK(v8::Locker::IsLocked());
9723 ApiTestFuzzer::Fuzz();
9724 v8::Unlocker unlocker;
9725 const char* code = "throw 7;";
9726 {
9727 v8::Locker nested_locker;
9728 v8::HandleScope scope;
9729 v8::Handle<Value> exception;
9730 { v8::TryCatch try_catch;
9731 v8::Handle<Value> value = CompileRun(code);
9732 CHECK(value.IsEmpty());
9733 CHECK(try_catch.HasCaught());
9734 // Make sure to wrap the exception in a new handle because
9735 // the handle returned from the TryCatch is destroyed
9736 // when the TryCatch is destroyed.
9737 exception = Local<Value>::New(try_catch.Exception());
9738 }
9739 return v8::ThrowException(exception);
9740 }
9741}
9742
9743
9744static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
9745 CHECK(v8::Locker::IsLocked());
9746 ApiTestFuzzer::Fuzz();
9747 v8::Unlocker unlocker;
9748 const char* code = "throw 7;";
9749 {
9750 v8::Locker nested_locker;
9751 v8::HandleScope scope;
9752 v8::Handle<Value> value = CompileRun(code);
9753 CHECK(value.IsEmpty());
9754 return v8_str("foo");
9755 }
9756}
9757
9758
9759// These are locking tests that don't need to be run again
9760// as part of the locking aggregation tests.
9761TEST(NestedLockers) {
9762 v8::Locker locker;
9763 CHECK(v8::Locker::IsLocked());
9764 v8::HandleScope scope;
9765 LocalContext env;
9766 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
9767 Local<Function> fun = fun_templ->GetFunction();
9768 env->Global()->Set(v8_str("throw_in_js"), fun);
9769 Local<Script> script = v8_compile("(function () {"
9770 " try {"
9771 " throw_in_js();"
9772 " return 42;"
9773 " } catch (e) {"
9774 " return e * 13;"
9775 " }"
9776 "})();");
9777 CHECK_EQ(91, script->Run()->Int32Value());
9778}
9779
9780
9781// These are locking tests that don't need to be run again
9782// as part of the locking aggregation tests.
9783TEST(NestedLockersNoTryCatch) {
9784 v8::Locker locker;
9785 v8::HandleScope scope;
9786 LocalContext env;
9787 Local<v8::FunctionTemplate> fun_templ =
9788 v8::FunctionTemplate::New(ThrowInJSNoCatch);
9789 Local<Function> fun = fun_templ->GetFunction();
9790 env->Global()->Set(v8_str("throw_in_js"), fun);
9791 Local<Script> script = v8_compile("(function () {"
9792 " try {"
9793 " throw_in_js();"
9794 " return 42;"
9795 " } catch (e) {"
9796 " return e * 13;"
9797 " }"
9798 "})();");
9799 CHECK_EQ(91, script->Run()->Int32Value());
9800}
9801
9802
9803THREADED_TEST(RecursiveLocking) {
9804 v8::Locker locker;
9805 {
9806 v8::Locker locker2;
9807 CHECK(v8::Locker::IsLocked());
9808 }
9809}
9810
9811
9812static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
9813 ApiTestFuzzer::Fuzz();
9814 v8::Unlocker unlocker;
9815 return v8::Undefined();
9816}
9817
9818
9819THREADED_TEST(LockUnlockLock) {
9820 {
9821 v8::Locker locker;
9822 v8::HandleScope scope;
9823 LocalContext env;
9824 Local<v8::FunctionTemplate> fun_templ =
9825 v8::FunctionTemplate::New(UnlockForAMoment);
9826 Local<Function> fun = fun_templ->GetFunction();
9827 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
9828 Local<Script> script = v8_compile("(function () {"
9829 " unlock_for_a_moment();"
9830 " return 42;"
9831 "})();");
9832 CHECK_EQ(42, script->Run()->Int32Value());
9833 }
9834 {
9835 v8::Locker locker;
9836 v8::HandleScope scope;
9837 LocalContext env;
9838 Local<v8::FunctionTemplate> fun_templ =
9839 v8::FunctionTemplate::New(UnlockForAMoment);
9840 Local<Function> fun = fun_templ->GetFunction();
9841 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
9842 Local<Script> script = v8_compile("(function () {"
9843 " unlock_for_a_moment();"
9844 " return 42;"
9845 "})();");
9846 CHECK_EQ(42, script->Run()->Int32Value());
9847 }
9848}
9849
9850
Leon Clarked91b9f72010-01-27 17:25:45 +00009851static int GetGlobalObjectsCount() {
Leon Clarkeeab96aa2010-01-27 16:31:12 +00009852 int count = 0;
Steve Block8defd9f2010-07-08 12:39:36 +01009853 i::HeapIterator it;
Leon Clarked91b9f72010-01-27 17:25:45 +00009854 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
9855 if (object->IsJSGlobalObject()) count++;
9856 return count;
9857}
9858
9859
Ben Murdochf87a2032010-10-22 12:50:53 +01009860static void CheckSurvivingGlobalObjectsCount(int expected) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009861 // We need to collect all garbage twice to be sure that everything
9862 // has been collected. This is because inline caches are cleared in
9863 // the first garbage collection but some of the maps have already
9864 // been marked at that point. Therefore some of the maps are not
9865 // collected until the second garbage collection.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009866 HEAP->global_context_map();
Steve Block44f0eee2011-05-26 01:26:41 +01009867 HEAP->CollectAllGarbage(false);
9868 HEAP->CollectAllGarbage(false);
Leon Clarked91b9f72010-01-27 17:25:45 +00009869 int count = GetGlobalObjectsCount();
Steve Blocka7e24c12009-10-30 11:49:00 +00009870#ifdef DEBUG
Steve Block44f0eee2011-05-26 01:26:41 +01009871 if (count != expected) HEAP->TracePathToGlobal();
Steve Blocka7e24c12009-10-30 11:49:00 +00009872#endif
Ben Murdochf87a2032010-10-22 12:50:53 +01009873 CHECK_EQ(expected, count);
Steve Blocka7e24c12009-10-30 11:49:00 +00009874}
9875
9876
9877TEST(DontLeakGlobalObjects) {
9878 // Regression test for issues 1139850 and 1174891.
9879
9880 v8::V8::Initialize();
9881
Steve Blocka7e24c12009-10-30 11:49:00 +00009882 for (int i = 0; i < 5; i++) {
9883 { v8::HandleScope scope;
9884 LocalContext context;
9885 }
Ben Murdochf87a2032010-10-22 12:50:53 +01009886 CheckSurvivingGlobalObjectsCount(0);
Steve Blocka7e24c12009-10-30 11:49:00 +00009887
9888 { v8::HandleScope scope;
9889 LocalContext context;
9890 v8_compile("Date")->Run();
9891 }
Ben Murdochf87a2032010-10-22 12:50:53 +01009892 CheckSurvivingGlobalObjectsCount(0);
Steve Blocka7e24c12009-10-30 11:49:00 +00009893
9894 { v8::HandleScope scope;
9895 LocalContext context;
9896 v8_compile("/aaa/")->Run();
9897 }
Ben Murdochf87a2032010-10-22 12:50:53 +01009898 CheckSurvivingGlobalObjectsCount(0);
Steve Blocka7e24c12009-10-30 11:49:00 +00009899
9900 { v8::HandleScope scope;
9901 const char* extension_list[] = { "v8/gc" };
9902 v8::ExtensionConfiguration extensions(1, extension_list);
9903 LocalContext context(&extensions);
9904 v8_compile("gc();")->Run();
9905 }
Ben Murdochf87a2032010-10-22 12:50:53 +01009906 CheckSurvivingGlobalObjectsCount(0);
Steve Blocka7e24c12009-10-30 11:49:00 +00009907 }
9908}
9909
9910
9911v8::Persistent<v8::Object> some_object;
9912v8::Persistent<v8::Object> bad_handle;
9913
Kristian Monsen50ef84f2010-07-29 15:18:00 +01009914void NewPersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009915 v8::HandleScope scope;
9916 bad_handle = v8::Persistent<v8::Object>::New(some_object);
Kristian Monsen50ef84f2010-07-29 15:18:00 +01009917 handle.Dispose();
Steve Blocka7e24c12009-10-30 11:49:00 +00009918}
9919
9920
9921THREADED_TEST(NewPersistentHandleFromWeakCallback) {
9922 LocalContext context;
9923
9924 v8::Persistent<v8::Object> handle1, handle2;
9925 {
9926 v8::HandleScope scope;
9927 some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
9928 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
9929 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
9930 }
9931 // Note: order is implementation dependent alas: currently
9932 // global handle nodes are processed by PostGarbageCollectionProcessing
9933 // in reverse allocation order, so if second allocated handle is deleted,
9934 // weak callback of the first handle would be able to 'reallocate' it.
9935 handle1.MakeWeak(NULL, NewPersistentHandleCallback);
9936 handle2.Dispose();
Steve Block44f0eee2011-05-26 01:26:41 +01009937 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +00009938}
9939
9940
9941v8::Persistent<v8::Object> to_be_disposed;
9942
9943void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
9944 to_be_disposed.Dispose();
Steve Block44f0eee2011-05-26 01:26:41 +01009945 HEAP->CollectAllGarbage(false);
Kristian Monsen50ef84f2010-07-29 15:18:00 +01009946 handle.Dispose();
Steve Blocka7e24c12009-10-30 11:49:00 +00009947}
9948
9949
9950THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
9951 LocalContext context;
9952
9953 v8::Persistent<v8::Object> handle1, handle2;
9954 {
9955 v8::HandleScope scope;
9956 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
9957 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
9958 }
9959 handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
9960 to_be_disposed = handle2;
Steve Block44f0eee2011-05-26 01:26:41 +01009961 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +00009962}
9963
Steve Blockd0582a62009-12-15 09:54:21 +00009964void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
9965 handle.Dispose();
9966}
9967
9968void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
9969 v8::HandleScope scope;
9970 v8::Persistent<v8::Object>::New(v8::Object::New());
Kristian Monsen50ef84f2010-07-29 15:18:00 +01009971 handle.Dispose();
Steve Blockd0582a62009-12-15 09:54:21 +00009972}
9973
9974
9975THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
9976 LocalContext context;
9977
9978 v8::Persistent<v8::Object> handle1, handle2, handle3;
9979 {
9980 v8::HandleScope scope;
9981 handle3 = v8::Persistent<v8::Object>::New(v8::Object::New());
9982 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
9983 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
9984 }
9985 handle2.MakeWeak(NULL, DisposingCallback);
9986 handle3.MakeWeak(NULL, HandleCreatingCallback);
Steve Block44f0eee2011-05-26 01:26:41 +01009987 HEAP->CollectAllGarbage(false);
Steve Blockd0582a62009-12-15 09:54:21 +00009988}
9989
Steve Blocka7e24c12009-10-30 11:49:00 +00009990
9991THREADED_TEST(CheckForCrossContextObjectLiterals) {
9992 v8::V8::Initialize();
9993
9994 const int nof = 2;
9995 const char* sources[nof] = {
9996 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
9997 "Object()"
9998 };
9999
10000 for (int i = 0; i < nof; i++) {
10001 const char* source = sources[i];
10002 { v8::HandleScope scope;
10003 LocalContext context;
10004 CompileRun(source);
10005 }
10006 { v8::HandleScope scope;
10007 LocalContext context;
10008 CompileRun(source);
10009 }
10010 }
10011}
10012
10013
10014static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
10015 v8::HandleScope inner;
10016 env->Enter();
10017 v8::Handle<Value> three = v8_num(3);
10018 v8::Handle<Value> value = inner.Close(three);
10019 env->Exit();
10020 return value;
10021}
10022
10023
10024THREADED_TEST(NestedHandleScopeAndContexts) {
10025 v8::HandleScope outer;
10026 v8::Persistent<Context> env = Context::New();
10027 env->Enter();
10028 v8::Handle<Value> value = NestedScope(env);
10029 v8::Handle<String> str = value->ToString();
10030 env->Exit();
10031 env.Dispose();
10032}
10033
10034
10035THREADED_TEST(ExternalAllocatedMemory) {
10036 v8::HandleScope outer;
10037 v8::Persistent<Context> env = Context::New();
10038 const int kSize = 1024*1024;
10039 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
10040 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
10041}
10042
10043
10044THREADED_TEST(DisposeEnteredContext) {
10045 v8::HandleScope scope;
10046 LocalContext outer;
10047 { v8::Persistent<v8::Context> inner = v8::Context::New();
10048 inner->Enter();
10049 inner.Dispose();
10050 inner.Clear();
10051 inner->Exit();
10052 }
10053}
10054
10055
10056// Regression test for issue 54, object templates with internal fields
10057// but no accessors or interceptors did not get their internal field
10058// count set on instances.
10059THREADED_TEST(Regress54) {
10060 v8::HandleScope outer;
10061 LocalContext context;
10062 static v8::Persistent<v8::ObjectTemplate> templ;
10063 if (templ.IsEmpty()) {
10064 v8::HandleScope inner;
10065 v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
10066 local->SetInternalFieldCount(1);
10067 templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
10068 }
10069 v8::Handle<v8::Object> result = templ->NewInstance();
10070 CHECK_EQ(1, result->InternalFieldCount());
10071}
10072
10073
10074// If part of the threaded tests, this test makes ThreadingTest fail
10075// on mac.
10076TEST(CatchStackOverflow) {
10077 v8::HandleScope scope;
10078 LocalContext context;
10079 v8::TryCatch try_catch;
10080 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
10081 "function f() {"
10082 " return f();"
10083 "}"
10084 ""
10085 "f();"));
10086 v8::Handle<v8::Value> result = script->Run();
10087 CHECK(result.IsEmpty());
10088}
10089
10090
10091static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
10092 const char* resource_name,
10093 int line_offset) {
10094 v8::HandleScope scope;
10095 v8::TryCatch try_catch;
10096 v8::Handle<v8::Value> result = script->Run();
10097 CHECK(result.IsEmpty());
10098 CHECK(try_catch.HasCaught());
10099 v8::Handle<v8::Message> message = try_catch.Message();
10100 CHECK(!message.IsEmpty());
10101 CHECK_EQ(10 + line_offset, message->GetLineNumber());
10102 CHECK_EQ(91, message->GetStartPosition());
10103 CHECK_EQ(92, message->GetEndPosition());
10104 CHECK_EQ(2, message->GetStartColumn());
10105 CHECK_EQ(3, message->GetEndColumn());
10106 v8::String::AsciiValue line(message->GetSourceLine());
10107 CHECK_EQ(" throw 'nirk';", *line);
10108 v8::String::AsciiValue name(message->GetScriptResourceName());
10109 CHECK_EQ(resource_name, *name);
10110}
10111
10112
10113THREADED_TEST(TryCatchSourceInfo) {
10114 v8::HandleScope scope;
10115 LocalContext context;
10116 v8::Handle<v8::String> source = v8::String::New(
10117 "function Foo() {\n"
10118 " return Bar();\n"
10119 "}\n"
10120 "\n"
10121 "function Bar() {\n"
10122 " return Baz();\n"
10123 "}\n"
10124 "\n"
10125 "function Baz() {\n"
10126 " throw 'nirk';\n"
10127 "}\n"
10128 "\n"
10129 "Foo();\n");
10130
10131 const char* resource_name;
10132 v8::Handle<v8::Script> script;
10133 resource_name = "test.js";
10134 script = v8::Script::Compile(source, v8::String::New(resource_name));
10135 CheckTryCatchSourceInfo(script, resource_name, 0);
10136
10137 resource_name = "test1.js";
10138 v8::ScriptOrigin origin1(v8::String::New(resource_name));
10139 script = v8::Script::Compile(source, &origin1);
10140 CheckTryCatchSourceInfo(script, resource_name, 0);
10141
10142 resource_name = "test2.js";
10143 v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
10144 script = v8::Script::Compile(source, &origin2);
10145 CheckTryCatchSourceInfo(script, resource_name, 7);
10146}
10147
10148
10149THREADED_TEST(CompilationCache) {
10150 v8::HandleScope scope;
10151 LocalContext context;
10152 v8::Handle<v8::String> source0 = v8::String::New("1234");
10153 v8::Handle<v8::String> source1 = v8::String::New("1234");
10154 v8::Handle<v8::Script> script0 =
10155 v8::Script::Compile(source0, v8::String::New("test.js"));
10156 v8::Handle<v8::Script> script1 =
10157 v8::Script::Compile(source1, v8::String::New("test.js"));
10158 v8::Handle<v8::Script> script2 =
10159 v8::Script::Compile(source0); // different origin
10160 CHECK_EQ(1234, script0->Run()->Int32Value());
10161 CHECK_EQ(1234, script1->Run()->Int32Value());
10162 CHECK_EQ(1234, script2->Run()->Int32Value());
10163}
10164
10165
10166static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
10167 ApiTestFuzzer::Fuzz();
10168 return v8_num(42);
10169}
10170
10171
10172THREADED_TEST(CallbackFunctionName) {
10173 v8::HandleScope scope;
10174 LocalContext context;
10175 Local<ObjectTemplate> t = ObjectTemplate::New();
10176 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
10177 context->Global()->Set(v8_str("obj"), t->NewInstance());
10178 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
10179 CHECK(value->IsString());
10180 v8::String::AsciiValue name(value);
10181 CHECK_EQ("asdf", *name);
10182}
10183
10184
10185THREADED_TEST(DateAccess) {
10186 v8::HandleScope scope;
10187 LocalContext context;
10188 v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
10189 CHECK(date->IsDate());
Steve Block6ded16b2010-05-10 14:33:55 +010010190 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue());
Steve Blocka7e24c12009-10-30 11:49:00 +000010191}
10192
10193
10194void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
Steve Block6ded16b2010-05-10 14:33:55 +010010195 v8::Handle<v8::Object> obj = val.As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +000010196 v8::Handle<v8::Array> props = obj->GetPropertyNames();
10197 CHECK_EQ(elmc, props->Length());
10198 for (int i = 0; i < elmc; i++) {
10199 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
10200 CHECK_EQ(elmv[i], *elm);
10201 }
10202}
10203
10204
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010205void CheckOwnProperties(v8::Handle<v8::Value> val,
10206 int elmc,
10207 const char* elmv[]) {
10208 v8::Handle<v8::Object> obj = val.As<v8::Object>();
10209 v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
10210 CHECK_EQ(elmc, props->Length());
10211 for (int i = 0; i < elmc; i++) {
10212 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
10213 CHECK_EQ(elmv[i], *elm);
10214 }
10215}
10216
10217
Steve Blocka7e24c12009-10-30 11:49:00 +000010218THREADED_TEST(PropertyEnumeration) {
10219 v8::HandleScope scope;
10220 LocalContext context;
10221 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
10222 "var result = [];"
10223 "result[0] = {};"
10224 "result[1] = {a: 1, b: 2};"
10225 "result[2] = [1, 2, 3];"
10226 "var proto = {x: 1, y: 2, z: 3};"
10227 "var x = { __proto__: proto, w: 0, z: 1 };"
10228 "result[3] = x;"
10229 "result;"))->Run();
Steve Block6ded16b2010-05-10 14:33:55 +010010230 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +000010231 CHECK_EQ(4, elms->Length());
10232 int elmc0 = 0;
10233 const char** elmv0 = NULL;
10234 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010235 CheckOwnProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
Steve Blocka7e24c12009-10-30 11:49:00 +000010236 int elmc1 = 2;
10237 const char* elmv1[] = {"a", "b"};
10238 CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010239 CheckOwnProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
Steve Blocka7e24c12009-10-30 11:49:00 +000010240 int elmc2 = 3;
10241 const char* elmv2[] = {"0", "1", "2"};
10242 CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010243 CheckOwnProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
Steve Blocka7e24c12009-10-30 11:49:00 +000010244 int elmc3 = 4;
10245 const char* elmv3[] = {"w", "z", "x", "y"};
10246 CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010247 int elmc4 = 2;
10248 const char* elmv4[] = {"w", "z"};
10249 CheckOwnProperties(elms->Get(v8::Integer::New(3)), elmc4, elmv4);
Steve Blocka7e24c12009-10-30 11:49:00 +000010250}
10251
Steve Block44f0eee2011-05-26 01:26:41 +010010252THREADED_TEST(PropertyEnumeration2) {
10253 v8::HandleScope scope;
10254 LocalContext context;
10255 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
10256 "var result = [];"
10257 "result[0] = {};"
10258 "result[1] = {a: 1, b: 2};"
10259 "result[2] = [1, 2, 3];"
10260 "var proto = {x: 1, y: 2, z: 3};"
10261 "var x = { __proto__: proto, w: 0, z: 1 };"
10262 "result[3] = x;"
10263 "result;"))->Run();
10264 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
10265 CHECK_EQ(4, elms->Length());
10266 int elmc0 = 0;
10267 const char** elmv0 = NULL;
10268 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
10269
10270 v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(0));
10271 v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
10272 CHECK_EQ(0, props->Length());
10273 for (uint32_t i = 0; i < props->Length(); i++) {
10274 printf("p[%d]\n", i);
10275 }
10276}
Steve Blocka7e24c12009-10-30 11:49:00 +000010277
Steve Blocka7e24c12009-10-30 11:49:00 +000010278static bool NamedSetAccessBlocker(Local<v8::Object> obj,
10279 Local<Value> name,
10280 v8::AccessType type,
10281 Local<Value> data) {
10282 return type != v8::ACCESS_SET;
10283}
10284
10285
10286static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
10287 uint32_t key,
10288 v8::AccessType type,
10289 Local<Value> data) {
10290 return type != v8::ACCESS_SET;
10291}
10292
10293
10294THREADED_TEST(DisableAccessChecksWhileConfiguring) {
10295 v8::HandleScope scope;
10296 LocalContext context;
10297 Local<ObjectTemplate> templ = ObjectTemplate::New();
10298 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
10299 IndexedSetAccessBlocker);
10300 templ->Set(v8_str("x"), v8::True());
10301 Local<v8::Object> instance = templ->NewInstance();
10302 context->Global()->Set(v8_str("obj"), instance);
10303 Local<Value> value = CompileRun("obj.x");
10304 CHECK(value->BooleanValue());
10305}
10306
10307
10308static bool NamedGetAccessBlocker(Local<v8::Object> obj,
10309 Local<Value> name,
10310 v8::AccessType type,
10311 Local<Value> data) {
10312 return false;
10313}
10314
10315
10316static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
10317 uint32_t key,
10318 v8::AccessType type,
10319 Local<Value> data) {
10320 return false;
10321}
10322
10323
10324
10325THREADED_TEST(AccessChecksReenabledCorrectly) {
10326 v8::HandleScope scope;
10327 LocalContext context;
10328 Local<ObjectTemplate> templ = ObjectTemplate::New();
10329 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
10330 IndexedGetAccessBlocker);
10331 templ->Set(v8_str("a"), v8_str("a"));
10332 // Add more than 8 (see kMaxFastProperties) properties
10333 // so that the constructor will force copying map.
10334 // Cannot sprintf, gcc complains unsafety.
10335 char buf[4];
10336 for (char i = '0'; i <= '9' ; i++) {
10337 buf[0] = i;
10338 for (char j = '0'; j <= '9'; j++) {
10339 buf[1] = j;
10340 for (char k = '0'; k <= '9'; k++) {
10341 buf[2] = k;
10342 buf[3] = 0;
10343 templ->Set(v8_str(buf), v8::Number::New(k));
10344 }
10345 }
10346 }
10347
10348 Local<v8::Object> instance_1 = templ->NewInstance();
10349 context->Global()->Set(v8_str("obj_1"), instance_1);
10350
10351 Local<Value> value_1 = CompileRun("obj_1.a");
10352 CHECK(value_1->IsUndefined());
10353
10354 Local<v8::Object> instance_2 = templ->NewInstance();
10355 context->Global()->Set(v8_str("obj_2"), instance_2);
10356
10357 Local<Value> value_2 = CompileRun("obj_2.a");
10358 CHECK(value_2->IsUndefined());
10359}
10360
10361
10362// This tests that access check information remains on the global
10363// object template when creating contexts.
10364THREADED_TEST(AccessControlRepeatedContextCreation) {
10365 v8::HandleScope handle_scope;
10366 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
10367 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
10368 IndexedSetAccessBlocker);
10369 i::Handle<i::ObjectTemplateInfo> internal_template =
10370 v8::Utils::OpenHandle(*global_template);
10371 CHECK(!internal_template->constructor()->IsUndefined());
10372 i::Handle<i::FunctionTemplateInfo> constructor(
10373 i::FunctionTemplateInfo::cast(internal_template->constructor()));
10374 CHECK(!constructor->access_check_info()->IsUndefined());
10375 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
10376 CHECK(!constructor->access_check_info()->IsUndefined());
10377}
10378
10379
10380THREADED_TEST(TurnOnAccessCheck) {
10381 v8::HandleScope handle_scope;
10382
10383 // Create an environment with access check to the global object disabled by
10384 // default.
10385 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
10386 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
10387 IndexedGetAccessBlocker,
10388 v8::Handle<v8::Value>(),
10389 false);
10390 v8::Persistent<Context> context = Context::New(NULL, global_template);
10391 Context::Scope context_scope(context);
10392
10393 // Set up a property and a number of functions.
10394 context->Global()->Set(v8_str("a"), v8_num(1));
10395 CompileRun("function f1() {return a;}"
10396 "function f2() {return a;}"
10397 "function g1() {return h();}"
10398 "function g2() {return h();}"
10399 "function h() {return 1;}");
10400 Local<Function> f1 =
10401 Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
10402 Local<Function> f2 =
10403 Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
10404 Local<Function> g1 =
10405 Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
10406 Local<Function> g2 =
10407 Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
10408 Local<Function> h =
10409 Local<Function>::Cast(context->Global()->Get(v8_str("h")));
10410
10411 // Get the global object.
10412 v8::Handle<v8::Object> global = context->Global();
10413
10414 // Call f1 one time and f2 a number of times. This will ensure that f1 still
10415 // uses the runtime system to retreive property a whereas f2 uses global load
10416 // inline cache.
10417 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
10418 for (int i = 0; i < 4; i++) {
10419 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
10420 }
10421
10422 // Same for g1 and g2.
10423 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
10424 for (int i = 0; i < 4; i++) {
10425 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
10426 }
10427
10428 // Detach the global and turn on access check.
10429 context->DetachGlobal();
10430 context->Global()->TurnOnAccessCheck();
10431
10432 // Failing access check to property get results in undefined.
10433 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
10434 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
10435
10436 // Failing access check to function call results in exception.
10437 CHECK(g1->Call(global, 0, NULL).IsEmpty());
10438 CHECK(g2->Call(global, 0, NULL).IsEmpty());
10439
10440 // No failing access check when just returning a constant.
10441 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
10442}
10443
10444
Ben Murdochb0fe1622011-05-05 13:52:32 +010010445v8::Handle<v8::String> a;
10446v8::Handle<v8::String> h;
10447
10448static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
10449 Local<Value> name,
10450 v8::AccessType type,
10451 Local<Value> data) {
10452 return !(name->Equals(a) || name->Equals(h));
10453}
10454
10455
10456THREADED_TEST(TurnOnAccessCheckAndRecompile) {
10457 v8::HandleScope handle_scope;
10458
10459 // Create an environment with access check to the global object disabled by
10460 // default. When the registered access checker will block access to properties
10461 // a and h
10462 a = v8_str("a");
10463 h = v8_str("h");
10464 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
10465 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
10466 IndexedGetAccessBlocker,
10467 v8::Handle<v8::Value>(),
10468 false);
10469 v8::Persistent<Context> context = Context::New(NULL, global_template);
10470 Context::Scope context_scope(context);
10471
10472 // Set up a property and a number of functions.
10473 context->Global()->Set(v8_str("a"), v8_num(1));
10474 static const char* source = "function f1() {return a;}"
10475 "function f2() {return a;}"
10476 "function g1() {return h();}"
10477 "function g2() {return h();}"
10478 "function h() {return 1;}";
10479
10480 CompileRun(source);
10481 Local<Function> f1;
10482 Local<Function> f2;
10483 Local<Function> g1;
10484 Local<Function> g2;
10485 Local<Function> h;
10486 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
10487 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
10488 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
10489 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
10490 h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
10491
10492 // Get the global object.
10493 v8::Handle<v8::Object> global = context->Global();
10494
10495 // Call f1 one time and f2 a number of times. This will ensure that f1 still
10496 // uses the runtime system to retreive property a whereas f2 uses global load
10497 // inline cache.
10498 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
10499 for (int i = 0; i < 4; i++) {
10500 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
10501 }
10502
10503 // Same for g1 and g2.
10504 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
10505 for (int i = 0; i < 4; i++) {
10506 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
10507 }
10508
10509 // Detach the global and turn on access check now blocking access to property
10510 // a and function h.
10511 context->DetachGlobal();
10512 context->Global()->TurnOnAccessCheck();
10513
10514 // Failing access check to property get results in undefined.
10515 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
10516 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
10517
10518 // Failing access check to function call results in exception.
10519 CHECK(g1->Call(global, 0, NULL).IsEmpty());
10520 CHECK(g2->Call(global, 0, NULL).IsEmpty());
10521
10522 // No failing access check when just returning a constant.
10523 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
10524
10525 // Now compile the source again. And get the newly compiled functions, except
10526 // for h for which access is blocked.
10527 CompileRun(source);
10528 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
10529 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
10530 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
10531 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
10532 CHECK(context->Global()->Get(v8_str("h"))->IsUndefined());
10533
10534 // Failing access check to property get results in undefined.
10535 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
10536 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
10537
10538 // Failing access check to function call results in exception.
10539 CHECK(g1->Call(global, 0, NULL).IsEmpty());
10540 CHECK(g2->Call(global, 0, NULL).IsEmpty());
10541}
10542
10543
Steve Blocka7e24c12009-10-30 11:49:00 +000010544// This test verifies that pre-compilation (aka preparsing) can be called
10545// without initializing the whole VM. Thus we cannot run this test in a
10546// multi-threaded setup.
10547TEST(PreCompile) {
10548 // TODO(155): This test would break without the initialization of V8. This is
10549 // a workaround for now to make this test not fail.
10550 v8::V8::Initialize();
Leon Clarkef7060e22010-06-03 12:02:55 +010010551 const char* script = "function foo(a) { return a+1; }";
10552 v8::ScriptData* sd =
Steve Blockd0582a62009-12-15 09:54:21 +000010553 v8::ScriptData::PreCompile(script, i::StrLength(script));
Steve Blocka7e24c12009-10-30 11:49:00 +000010554 CHECK_NE(sd->Length(), 0);
10555 CHECK_NE(sd->Data(), NULL);
Leon Clarkee46be812010-01-19 14:06:41 +000010556 CHECK(!sd->HasError());
10557 delete sd;
10558}
10559
10560
10561TEST(PreCompileWithError) {
10562 v8::V8::Initialize();
Leon Clarkef7060e22010-06-03 12:02:55 +010010563 const char* script = "function foo(a) { return 1 * * 2; }";
10564 v8::ScriptData* sd =
Leon Clarkee46be812010-01-19 14:06:41 +000010565 v8::ScriptData::PreCompile(script, i::StrLength(script));
10566 CHECK(sd->HasError());
10567 delete sd;
10568}
10569
10570
10571TEST(Regress31661) {
10572 v8::V8::Initialize();
Leon Clarkef7060e22010-06-03 12:02:55 +010010573 const char* script = " The Definintive Guide";
10574 v8::ScriptData* sd =
Leon Clarkee46be812010-01-19 14:06:41 +000010575 v8::ScriptData::PreCompile(script, i::StrLength(script));
10576 CHECK(sd->HasError());
Steve Blocka7e24c12009-10-30 11:49:00 +000010577 delete sd;
10578}
10579
10580
Leon Clarkef7060e22010-06-03 12:02:55 +010010581// Tests that ScriptData can be serialized and deserialized.
10582TEST(PreCompileSerialization) {
10583 v8::V8::Initialize();
10584 const char* script = "function foo(a) { return a+1; }";
10585 v8::ScriptData* sd =
10586 v8::ScriptData::PreCompile(script, i::StrLength(script));
10587
10588 // Serialize.
10589 int serialized_data_length = sd->Length();
10590 char* serialized_data = i::NewArray<char>(serialized_data_length);
10591 memcpy(serialized_data, sd->Data(), serialized_data_length);
10592
10593 // Deserialize.
10594 v8::ScriptData* deserialized_sd =
10595 v8::ScriptData::New(serialized_data, serialized_data_length);
10596
10597 // Verify that the original is the same as the deserialized.
10598 CHECK_EQ(sd->Length(), deserialized_sd->Length());
10599 CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
10600 CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
10601
10602 delete sd;
10603 delete deserialized_sd;
10604}
10605
10606
10607// Attempts to deserialize bad data.
10608TEST(PreCompileDeserializationError) {
10609 v8::V8::Initialize();
10610 const char* data = "DONT CARE";
10611 int invalid_size = 3;
10612 v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
10613
10614 CHECK_EQ(0, sd->Length());
10615
10616 delete sd;
10617}
10618
10619
Leon Clarkeac952652010-07-15 11:15:24 +010010620// Attempts to deserialize bad data.
10621TEST(PreCompileInvalidPreparseDataError) {
10622 v8::V8::Initialize();
10623 v8::HandleScope scope;
10624 LocalContext context;
10625
10626 const char* script = "function foo(){ return 5;}\n"
10627 "function bar(){ return 6 + 7;} foo();";
10628 v8::ScriptData* sd =
10629 v8::ScriptData::PreCompile(script, i::StrLength(script));
10630 CHECK(!sd->HasError());
10631 // ScriptDataImpl private implementation details
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -080010632 const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
Iain Merrick9ac36c92010-09-13 15:29:50 +010010633 const int kFunctionEntrySize = i::FunctionEntry::kSize;
Leon Clarkeac952652010-07-15 11:15:24 +010010634 const int kFunctionEntryStartOffset = 0;
10635 const int kFunctionEntryEndOffset = 1;
10636 unsigned* sd_data =
10637 reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
Leon Clarkeac952652010-07-15 11:15:24 +010010638
10639 // Overwrite function bar's end position with 0.
10640 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
10641 v8::TryCatch try_catch;
10642
10643 Local<String> source = String::New(script);
10644 Local<Script> compiled_script = Script::New(source, NULL, sd);
10645 CHECK(try_catch.HasCaught());
10646 String::AsciiValue exception_value(try_catch.Message()->Get());
10647 CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
10648 *exception_value);
10649
10650 try_catch.Reset();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010651
Leon Clarkeac952652010-07-15 11:15:24 +010010652 // Overwrite function bar's start position with 200. The function entry
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010653 // will not be found when searching for it by position and we should fall
10654 // back on eager compilation.
Kristian Monsen80d68ea2010-09-08 11:05:35 +010010655 sd = v8::ScriptData::PreCompile(script, i::StrLength(script));
10656 sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
Leon Clarkeac952652010-07-15 11:15:24 +010010657 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
10658 200;
10659 compiled_script = Script::New(source, NULL, sd);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010660 CHECK(!try_catch.HasCaught());
Leon Clarkeac952652010-07-15 11:15:24 +010010661
10662 delete sd;
10663}
10664
10665
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010010666// Verifies that the Handle<String> and const char* versions of the API produce
10667// the same results (at least for one trivial case).
10668TEST(PreCompileAPIVariationsAreSame) {
10669 v8::V8::Initialize();
10670 v8::HandleScope scope;
10671
10672 const char* cstring = "function foo(a) { return a+1; }";
Ben Murdoch3bec4d22010-07-22 14:51:16 +010010673
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010010674 v8::ScriptData* sd_from_cstring =
10675 v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
10676
10677 TestAsciiResource* resource = new TestAsciiResource(cstring);
Ben Murdoch3bec4d22010-07-22 14:51:16 +010010678 v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile(
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010010679 v8::String::NewExternal(resource));
10680
Ben Murdoch3bec4d22010-07-22 14:51:16 +010010681 v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile(
10682 v8::String::New(cstring));
10683
10684 CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010010685 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
Ben Murdoch3bec4d22010-07-22 14:51:16 +010010686 sd_from_external_string->Data(),
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010010687 sd_from_cstring->Length()));
10688
Ben Murdoch3bec4d22010-07-22 14:51:16 +010010689 CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length());
10690 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
10691 sd_from_string->Data(),
10692 sd_from_cstring->Length()));
10693
10694
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010010695 delete sd_from_cstring;
Ben Murdoch3bec4d22010-07-22 14:51:16 +010010696 delete sd_from_external_string;
10697 delete sd_from_string;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010010698}
10699
10700
Steve Blocka7e24c12009-10-30 11:49:00 +000010701// This tests that we do not allow dictionary load/call inline caches
10702// to use functions that have not yet been compiled. The potential
10703// problem of loading a function that has not yet been compiled can
10704// arise because we share code between contexts via the compilation
10705// cache.
10706THREADED_TEST(DictionaryICLoadedFunction) {
10707 v8::HandleScope scope;
10708 // Test LoadIC.
10709 for (int i = 0; i < 2; i++) {
10710 LocalContext context;
10711 context->Global()->Set(v8_str("tmp"), v8::True());
10712 context->Global()->Delete(v8_str("tmp"));
10713 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
10714 }
10715 // Test CallIC.
10716 for (int i = 0; i < 2; i++) {
10717 LocalContext context;
10718 context->Global()->Set(v8_str("tmp"), v8::True());
10719 context->Global()->Delete(v8_str("tmp"));
10720 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
10721 }
10722}
10723
10724
10725// Test that cross-context new calls use the context of the callee to
10726// create the new JavaScript object.
10727THREADED_TEST(CrossContextNew) {
10728 v8::HandleScope scope;
10729 v8::Persistent<Context> context0 = Context::New();
10730 v8::Persistent<Context> context1 = Context::New();
10731
10732 // Allow cross-domain access.
10733 Local<String> token = v8_str("<security token>");
10734 context0->SetSecurityToken(token);
10735 context1->SetSecurityToken(token);
10736
10737 // Set an 'x' property on the Object prototype and define a
10738 // constructor function in context0.
10739 context0->Enter();
10740 CompileRun("Object.prototype.x = 42; function C() {};");
10741 context0->Exit();
10742
10743 // Call the constructor function from context0 and check that the
10744 // result has the 'x' property.
10745 context1->Enter();
10746 context1->Global()->Set(v8_str("other"), context0->Global());
10747 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
10748 CHECK(value->IsInt32());
10749 CHECK_EQ(42, value->Int32Value());
10750 context1->Exit();
10751
10752 // Dispose the contexts to allow them to be garbage collected.
10753 context0.Dispose();
10754 context1.Dispose();
10755}
10756
10757
10758class RegExpInterruptTest {
10759 public:
10760 RegExpInterruptTest() : block_(NULL) {}
10761 ~RegExpInterruptTest() { delete block_; }
10762 void RunTest() {
10763 block_ = i::OS::CreateSemaphore(0);
10764 gc_count_ = 0;
10765 gc_during_regexp_ = 0;
10766 regexp_success_ = false;
10767 gc_success_ = false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010768 GCThread gc_thread(this);
Steve Blocka7e24c12009-10-30 11:49:00 +000010769 gc_thread.Start();
10770 v8::Locker::StartPreemption(1);
10771
10772 LongRunningRegExp();
10773 {
10774 v8::Unlocker unlock;
10775 gc_thread.Join();
10776 }
10777 v8::Locker::StopPreemption();
10778 CHECK(regexp_success_);
10779 CHECK(gc_success_);
10780 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010781
Steve Blocka7e24c12009-10-30 11:49:00 +000010782 private:
10783 // Number of garbage collections required.
10784 static const int kRequiredGCs = 5;
10785
10786 class GCThread : public i::Thread {
10787 public:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010788 explicit GCThread(RegExpInterruptTest* test)
10789 : Thread("GCThread"), test_(test) {}
Steve Blocka7e24c12009-10-30 11:49:00 +000010790 virtual void Run() {
10791 test_->CollectGarbage();
10792 }
10793 private:
10794 RegExpInterruptTest* test_;
10795 };
10796
10797 void CollectGarbage() {
10798 block_->Wait();
10799 while (gc_during_regexp_ < kRequiredGCs) {
10800 {
10801 v8::Locker lock;
10802 // TODO(lrn): Perhaps create some garbage before collecting.
Steve Block44f0eee2011-05-26 01:26:41 +010010803 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +000010804 gc_count_++;
10805 }
10806 i::OS::Sleep(1);
10807 }
10808 gc_success_ = true;
10809 }
10810
10811 void LongRunningRegExp() {
10812 block_->Signal(); // Enable garbage collection thread on next preemption.
10813 int rounds = 0;
10814 while (gc_during_regexp_ < kRequiredGCs) {
10815 int gc_before = gc_count_;
10816 {
10817 // Match 15-30 "a"'s against 14 and a "b".
10818 const char* c_source =
10819 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
10820 ".exec('aaaaaaaaaaaaaaab') === null";
10821 Local<String> source = String::New(c_source);
10822 Local<Script> script = Script::Compile(source);
10823 Local<Value> result = script->Run();
10824 if (!result->BooleanValue()) {
10825 gc_during_regexp_ = kRequiredGCs; // Allow gc thread to exit.
10826 return;
10827 }
10828 }
10829 {
10830 // Match 15-30 "a"'s against 15 and a "b".
10831 const char* c_source =
10832 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
10833 ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
10834 Local<String> source = String::New(c_source);
10835 Local<Script> script = Script::Compile(source);
10836 Local<Value> result = script->Run();
10837 if (!result->BooleanValue()) {
10838 gc_during_regexp_ = kRequiredGCs;
10839 return;
10840 }
10841 }
10842 int gc_after = gc_count_;
10843 gc_during_regexp_ += gc_after - gc_before;
10844 rounds++;
10845 i::OS::Sleep(1);
10846 }
10847 regexp_success_ = true;
10848 }
10849
10850 i::Semaphore* block_;
10851 int gc_count_;
10852 int gc_during_regexp_;
10853 bool regexp_success_;
10854 bool gc_success_;
10855};
10856
10857
10858// Test that a regular expression execution can be interrupted and
10859// survive a garbage collection.
10860TEST(RegExpInterruption) {
10861 v8::Locker lock;
10862 v8::V8::Initialize();
10863 v8::HandleScope scope;
10864 Local<Context> local_env;
10865 {
10866 LocalContext env;
10867 local_env = env.local();
10868 }
10869
10870 // Local context should still be live.
10871 CHECK(!local_env.IsEmpty());
10872 local_env->Enter();
10873
10874 // Should complete without problems.
10875 RegExpInterruptTest().RunTest();
10876
10877 local_env->Exit();
10878}
10879
10880
10881class ApplyInterruptTest {
10882 public:
10883 ApplyInterruptTest() : block_(NULL) {}
10884 ~ApplyInterruptTest() { delete block_; }
10885 void RunTest() {
10886 block_ = i::OS::CreateSemaphore(0);
10887 gc_count_ = 0;
10888 gc_during_apply_ = 0;
10889 apply_success_ = false;
10890 gc_success_ = false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010891 GCThread gc_thread(this);
Steve Blocka7e24c12009-10-30 11:49:00 +000010892 gc_thread.Start();
10893 v8::Locker::StartPreemption(1);
10894
10895 LongRunningApply();
10896 {
10897 v8::Unlocker unlock;
10898 gc_thread.Join();
10899 }
10900 v8::Locker::StopPreemption();
10901 CHECK(apply_success_);
10902 CHECK(gc_success_);
10903 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010904
Steve Blocka7e24c12009-10-30 11:49:00 +000010905 private:
10906 // Number of garbage collections required.
10907 static const int kRequiredGCs = 2;
10908
10909 class GCThread : public i::Thread {
10910 public:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010911 explicit GCThread(ApplyInterruptTest* test)
10912 : Thread("GCThread"), test_(test) {}
Steve Blocka7e24c12009-10-30 11:49:00 +000010913 virtual void Run() {
10914 test_->CollectGarbage();
10915 }
10916 private:
10917 ApplyInterruptTest* test_;
10918 };
10919
10920 void CollectGarbage() {
10921 block_->Wait();
10922 while (gc_during_apply_ < kRequiredGCs) {
10923 {
10924 v8::Locker lock;
Steve Block44f0eee2011-05-26 01:26:41 +010010925 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +000010926 gc_count_++;
10927 }
10928 i::OS::Sleep(1);
10929 }
10930 gc_success_ = true;
10931 }
10932
10933 void LongRunningApply() {
10934 block_->Signal();
10935 int rounds = 0;
10936 while (gc_during_apply_ < kRequiredGCs) {
10937 int gc_before = gc_count_;
10938 {
10939 const char* c_source =
10940 "function do_very_little(bar) {"
10941 " this.foo = bar;"
10942 "}"
10943 "for (var i = 0; i < 100000; i++) {"
10944 " do_very_little.apply(this, ['bar']);"
10945 "}";
10946 Local<String> source = String::New(c_source);
10947 Local<Script> script = Script::Compile(source);
10948 Local<Value> result = script->Run();
10949 // Check that no exception was thrown.
10950 CHECK(!result.IsEmpty());
10951 }
10952 int gc_after = gc_count_;
10953 gc_during_apply_ += gc_after - gc_before;
10954 rounds++;
10955 }
10956 apply_success_ = true;
10957 }
10958
10959 i::Semaphore* block_;
10960 int gc_count_;
10961 int gc_during_apply_;
10962 bool apply_success_;
10963 bool gc_success_;
10964};
10965
10966
10967// Test that nothing bad happens if we get a preemption just when we were
10968// about to do an apply().
10969TEST(ApplyInterruption) {
10970 v8::Locker lock;
10971 v8::V8::Initialize();
10972 v8::HandleScope scope;
10973 Local<Context> local_env;
10974 {
10975 LocalContext env;
10976 local_env = env.local();
10977 }
10978
10979 // Local context should still be live.
10980 CHECK(!local_env.IsEmpty());
10981 local_env->Enter();
10982
10983 // Should complete without problems.
10984 ApplyInterruptTest().RunTest();
10985
10986 local_env->Exit();
10987}
10988
10989
10990// Verify that we can clone an object
10991TEST(ObjectClone) {
10992 v8::HandleScope scope;
10993 LocalContext env;
10994
10995 const char* sample =
10996 "var rv = {};" \
10997 "rv.alpha = 'hello';" \
10998 "rv.beta = 123;" \
10999 "rv;";
11000
11001 // Create an object, verify basics.
11002 Local<Value> val = CompileRun(sample);
11003 CHECK(val->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +010011004 Local<v8::Object> obj = val.As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +000011005 obj->Set(v8_str("gamma"), v8_str("cloneme"));
11006
11007 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
11008 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
11009 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
11010
11011 // Clone it.
11012 Local<v8::Object> clone = obj->Clone();
11013 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
11014 CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
11015 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
11016
11017 // Set a property on the clone, verify each object.
11018 clone->Set(v8_str("beta"), v8::Integer::New(456));
11019 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
11020 CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
11021}
11022
11023
11024class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
11025 public:
11026 explicit AsciiVectorResource(i::Vector<const char> vector)
11027 : data_(vector) {}
11028 virtual ~AsciiVectorResource() {}
11029 virtual size_t length() const { return data_.length(); }
11030 virtual const char* data() const { return data_.start(); }
11031 private:
11032 i::Vector<const char> data_;
11033};
11034
11035
11036class UC16VectorResource : public v8::String::ExternalStringResource {
11037 public:
11038 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
11039 : data_(vector) {}
11040 virtual ~UC16VectorResource() {}
11041 virtual size_t length() const { return data_.length(); }
11042 virtual const i::uc16* data() const { return data_.start(); }
11043 private:
11044 i::Vector<const i::uc16> data_;
11045};
11046
11047
11048static void MorphAString(i::String* string,
11049 AsciiVectorResource* ascii_resource,
11050 UC16VectorResource* uc16_resource) {
11051 CHECK(i::StringShape(string).IsExternal());
11052 if (string->IsAsciiRepresentation()) {
11053 // Check old map is not symbol or long.
Steve Block44f0eee2011-05-26 01:26:41 +010011054 CHECK(string->map() == HEAP->external_ascii_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +000011055 // Morph external string to be TwoByte string.
Steve Block44f0eee2011-05-26 01:26:41 +010011056 string->set_map(HEAP->external_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +000011057 i::ExternalTwoByteString* morphed =
11058 i::ExternalTwoByteString::cast(string);
11059 morphed->set_resource(uc16_resource);
11060 } else {
11061 // Check old map is not symbol or long.
Steve Block44f0eee2011-05-26 01:26:41 +010011062 CHECK(string->map() == HEAP->external_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +000011063 // Morph external string to be ASCII string.
Steve Block44f0eee2011-05-26 01:26:41 +010011064 string->set_map(HEAP->external_ascii_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +000011065 i::ExternalAsciiString* morphed =
11066 i::ExternalAsciiString::cast(string);
11067 morphed->set_resource(ascii_resource);
11068 }
11069}
11070
11071
11072// Test that we can still flatten a string if the components it is built up
11073// from have been turned into 16 bit strings in the mean time.
11074THREADED_TEST(MorphCompositeStringTest) {
11075 const char* c_string = "Now is the time for all good men"
11076 " to come to the aid of the party";
11077 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
11078 {
11079 v8::HandleScope scope;
11080 LocalContext env;
11081 AsciiVectorResource ascii_resource(
Steve Blockd0582a62009-12-15 09:54:21 +000011082 i::Vector<const char>(c_string, i::StrLength(c_string)));
Steve Blocka7e24c12009-10-30 11:49:00 +000011083 UC16VectorResource uc16_resource(
Steve Blockd0582a62009-12-15 09:54:21 +000011084 i::Vector<const uint16_t>(two_byte_string,
11085 i::StrLength(c_string)));
Steve Blocka7e24c12009-10-30 11:49:00 +000011086
11087 Local<String> lhs(v8::Utils::ToLocal(
Steve Block44f0eee2011-05-26 01:26:41 +010011088 FACTORY->NewExternalStringFromAscii(&ascii_resource)));
Steve Blocka7e24c12009-10-30 11:49:00 +000011089 Local<String> rhs(v8::Utils::ToLocal(
Steve Block44f0eee2011-05-26 01:26:41 +010011090 FACTORY->NewExternalStringFromAscii(&ascii_resource)));
Steve Blocka7e24c12009-10-30 11:49:00 +000011091
11092 env->Global()->Set(v8_str("lhs"), lhs);
11093 env->Global()->Set(v8_str("rhs"), rhs);
11094
11095 CompileRun(
11096 "var cons = lhs + rhs;"
11097 "var slice = lhs.substring(1, lhs.length - 1);"
11098 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
11099
11100 MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
11101 MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
11102
11103 // Now do some stuff to make sure the strings are flattened, etc.
11104 CompileRun(
11105 "/[^a-z]/.test(cons);"
11106 "/[^a-z]/.test(slice);"
11107 "/[^a-z]/.test(slice_on_cons);");
11108 const char* expected_cons =
11109 "Now is the time for all good men to come to the aid of the party"
11110 "Now is the time for all good men to come to the aid of the party";
11111 const char* expected_slice =
11112 "ow is the time for all good men to come to the aid of the part";
11113 const char* expected_slice_on_cons =
11114 "ow is the time for all good men to come to the aid of the party"
11115 "Now is the time for all good men to come to the aid of the part";
11116 CHECK_EQ(String::New(expected_cons),
11117 env->Global()->Get(v8_str("cons")));
11118 CHECK_EQ(String::New(expected_slice),
11119 env->Global()->Get(v8_str("slice")));
11120 CHECK_EQ(String::New(expected_slice_on_cons),
11121 env->Global()->Get(v8_str("slice_on_cons")));
11122 }
Ben Murdoch3bec4d22010-07-22 14:51:16 +010011123 i::DeleteArray(two_byte_string);
Steve Blocka7e24c12009-10-30 11:49:00 +000011124}
11125
11126
11127TEST(CompileExternalTwoByteSource) {
11128 v8::HandleScope scope;
11129 LocalContext context;
11130
11131 // This is a very short list of sources, which currently is to check for a
11132 // regression caused by r2703.
11133 const char* ascii_sources[] = {
11134 "0.5",
11135 "-0.5", // This mainly testes PushBack in the Scanner.
11136 "--0.5", // This mainly testes PushBack in the Scanner.
11137 NULL
11138 };
11139
11140 // Compile the sources as external two byte strings.
11141 for (int i = 0; ascii_sources[i] != NULL; i++) {
11142 uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
11143 UC16VectorResource uc16_resource(
Steve Blockd0582a62009-12-15 09:54:21 +000011144 i::Vector<const uint16_t>(two_byte_string,
11145 i::StrLength(ascii_sources[i])));
Steve Blocka7e24c12009-10-30 11:49:00 +000011146 v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
11147 v8::Script::Compile(source);
Ben Murdoch3bec4d22010-07-22 14:51:16 +010011148 i::DeleteArray(two_byte_string);
Steve Blocka7e24c12009-10-30 11:49:00 +000011149 }
11150}
11151
11152
11153class RegExpStringModificationTest {
11154 public:
11155 RegExpStringModificationTest()
11156 : block_(i::OS::CreateSemaphore(0)),
11157 morphs_(0),
11158 morphs_during_regexp_(0),
11159 ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
11160 uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
11161 ~RegExpStringModificationTest() { delete block_; }
11162 void RunTest() {
11163 regexp_success_ = false;
11164 morph_success_ = false;
11165
11166 // Initialize the contents of two_byte_content_ to be a uc16 representation
11167 // of "aaaaaaaaaaaaaab".
11168 for (int i = 0; i < 14; i++) {
11169 two_byte_content_[i] = 'a';
11170 }
11171 two_byte_content_[14] = 'b';
11172
11173 // Create the input string for the regexp - the one we are going to change
11174 // properties of.
Steve Block44f0eee2011-05-26 01:26:41 +010011175 input_ = FACTORY->NewExternalStringFromAscii(&ascii_resource_);
Steve Blocka7e24c12009-10-30 11:49:00 +000011176
11177 // Inject the input as a global variable.
11178 i::Handle<i::String> input_name =
Steve Block44f0eee2011-05-26 01:26:41 +010011179 FACTORY->NewStringFromAscii(i::Vector<const char>("input", 5));
11180 i::Isolate::Current()->global_context()->global()->SetProperty(
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011181 *input_name,
11182 *input_,
11183 NONE,
11184 i::kNonStrictMode)->ToObjectChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +000011185
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011186 MorphThread morph_thread(this);
Steve Blocka7e24c12009-10-30 11:49:00 +000011187 morph_thread.Start();
11188 v8::Locker::StartPreemption(1);
11189 LongRunningRegExp();
11190 {
11191 v8::Unlocker unlock;
11192 morph_thread.Join();
11193 }
11194 v8::Locker::StopPreemption();
11195 CHECK(regexp_success_);
11196 CHECK(morph_success_);
11197 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011198
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011199 private:
Steve Blocka7e24c12009-10-30 11:49:00 +000011200 // Number of string modifications required.
11201 static const int kRequiredModifications = 5;
11202 static const int kMaxModifications = 100;
11203
11204 class MorphThread : public i::Thread {
11205 public:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011206 explicit MorphThread(RegExpStringModificationTest* test)
11207 : Thread("MorphThread"), test_(test) {}
Steve Blocka7e24c12009-10-30 11:49:00 +000011208 virtual void Run() {
11209 test_->MorphString();
11210 }
11211 private:
11212 RegExpStringModificationTest* test_;
11213 };
11214
11215 void MorphString() {
11216 block_->Wait();
11217 while (morphs_during_regexp_ < kRequiredModifications &&
11218 morphs_ < kMaxModifications) {
11219 {
11220 v8::Locker lock;
11221 // Swap string between ascii and two-byte representation.
11222 i::String* string = *input_;
11223 MorphAString(string, &ascii_resource_, &uc16_resource_);
11224 morphs_++;
11225 }
11226 i::OS::Sleep(1);
11227 }
11228 morph_success_ = true;
11229 }
11230
11231 void LongRunningRegExp() {
11232 block_->Signal(); // Enable morphing thread on next preemption.
11233 while (morphs_during_regexp_ < kRequiredModifications &&
11234 morphs_ < kMaxModifications) {
11235 int morphs_before = morphs_;
11236 {
Steve Block791712a2010-08-27 10:21:07 +010011237 v8::HandleScope scope;
Steve Blocka7e24c12009-10-30 11:49:00 +000011238 // Match 15-30 "a"'s against 14 and a "b".
11239 const char* c_source =
11240 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
11241 ".exec(input) === null";
11242 Local<String> source = String::New(c_source);
11243 Local<Script> script = Script::Compile(source);
11244 Local<Value> result = script->Run();
11245 CHECK(result->IsTrue());
11246 }
11247 int morphs_after = morphs_;
11248 morphs_during_regexp_ += morphs_after - morphs_before;
11249 }
11250 regexp_success_ = true;
11251 }
11252
11253 i::uc16 two_byte_content_[15];
11254 i::Semaphore* block_;
11255 int morphs_;
11256 int morphs_during_regexp_;
11257 bool regexp_success_;
11258 bool morph_success_;
11259 i::Handle<i::String> input_;
11260 AsciiVectorResource ascii_resource_;
11261 UC16VectorResource uc16_resource_;
11262};
11263
11264
11265// Test that a regular expression execution can be interrupted and
11266// the string changed without failing.
11267TEST(RegExpStringModification) {
11268 v8::Locker lock;
11269 v8::V8::Initialize();
11270 v8::HandleScope scope;
11271 Local<Context> local_env;
11272 {
11273 LocalContext env;
11274 local_env = env.local();
11275 }
11276
11277 // Local context should still be live.
11278 CHECK(!local_env.IsEmpty());
11279 local_env->Enter();
11280
11281 // Should complete without problems.
11282 RegExpStringModificationTest().RunTest();
11283
11284 local_env->Exit();
11285}
11286
11287
11288// Test that we can set a property on the global object even if there
11289// is a read-only property in the prototype chain.
11290TEST(ReadOnlyPropertyInGlobalProto) {
11291 v8::HandleScope scope;
11292 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11293 LocalContext context(0, templ);
11294 v8::Handle<v8::Object> global = context->Global();
11295 v8::Handle<v8::Object> global_proto =
11296 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
11297 global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
11298 global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
11299 // Check without 'eval' or 'with'.
11300 v8::Handle<v8::Value> res =
11301 CompileRun("function f() { x = 42; return x; }; f()");
11302 // Check with 'eval'.
11303 res = CompileRun("function f() { eval('1'); y = 42; return y; }; f()");
11304 CHECK_EQ(v8::Integer::New(42), res);
11305 // Check with 'with'.
11306 res = CompileRun("function f() { with (this) { y = 42 }; return y; }; f()");
11307 CHECK_EQ(v8::Integer::New(42), res);
11308}
11309
11310static int force_set_set_count = 0;
11311static int force_set_get_count = 0;
11312bool pass_on_get = false;
11313
11314static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
11315 const v8::AccessorInfo& info) {
11316 force_set_get_count++;
11317 if (pass_on_get) {
11318 return v8::Handle<v8::Value>();
11319 } else {
11320 return v8::Int32::New(3);
11321 }
11322}
11323
11324static void ForceSetSetter(v8::Local<v8::String> name,
11325 v8::Local<v8::Value> value,
11326 const v8::AccessorInfo& info) {
11327 force_set_set_count++;
11328}
11329
11330static v8::Handle<v8::Value> ForceSetInterceptSetter(
11331 v8::Local<v8::String> name,
11332 v8::Local<v8::Value> value,
11333 const v8::AccessorInfo& info) {
11334 force_set_set_count++;
11335 return v8::Undefined();
11336}
11337
11338TEST(ForceSet) {
11339 force_set_get_count = 0;
11340 force_set_set_count = 0;
11341 pass_on_get = false;
11342
11343 v8::HandleScope scope;
11344 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11345 v8::Handle<v8::String> access_property = v8::String::New("a");
11346 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
11347 LocalContext context(NULL, templ);
11348 v8::Handle<v8::Object> global = context->Global();
11349
11350 // Ordinary properties
11351 v8::Handle<v8::String> simple_property = v8::String::New("p");
11352 global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
11353 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11354 // This should fail because the property is read-only
11355 global->Set(simple_property, v8::Int32::New(5));
11356 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11357 // This should succeed even though the property is read-only
11358 global->ForceSet(simple_property, v8::Int32::New(6));
11359 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
11360
11361 // Accessors
11362 CHECK_EQ(0, force_set_set_count);
11363 CHECK_EQ(0, force_set_get_count);
11364 CHECK_EQ(3, global->Get(access_property)->Int32Value());
11365 // CHECK_EQ the property shouldn't override it, just call the setter
11366 // which in this case does nothing.
11367 global->Set(access_property, v8::Int32::New(7));
11368 CHECK_EQ(3, global->Get(access_property)->Int32Value());
11369 CHECK_EQ(1, force_set_set_count);
11370 CHECK_EQ(2, force_set_get_count);
11371 // Forcing the property to be set should override the accessor without
11372 // calling it
11373 global->ForceSet(access_property, v8::Int32::New(8));
11374 CHECK_EQ(8, global->Get(access_property)->Int32Value());
11375 CHECK_EQ(1, force_set_set_count);
11376 CHECK_EQ(2, force_set_get_count);
11377}
11378
11379TEST(ForceSetWithInterceptor) {
11380 force_set_get_count = 0;
11381 force_set_set_count = 0;
11382 pass_on_get = false;
11383
11384 v8::HandleScope scope;
11385 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11386 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
11387 LocalContext context(NULL, templ);
11388 v8::Handle<v8::Object> global = context->Global();
11389
11390 v8::Handle<v8::String> some_property = v8::String::New("a");
11391 CHECK_EQ(0, force_set_set_count);
11392 CHECK_EQ(0, force_set_get_count);
11393 CHECK_EQ(3, global->Get(some_property)->Int32Value());
11394 // Setting the property shouldn't override it, just call the setter
11395 // which in this case does nothing.
11396 global->Set(some_property, v8::Int32::New(7));
11397 CHECK_EQ(3, global->Get(some_property)->Int32Value());
11398 CHECK_EQ(1, force_set_set_count);
11399 CHECK_EQ(2, force_set_get_count);
11400 // Getting the property when the interceptor returns an empty handle
11401 // should yield undefined, since the property isn't present on the
11402 // object itself yet.
11403 pass_on_get = true;
11404 CHECK(global->Get(some_property)->IsUndefined());
11405 CHECK_EQ(1, force_set_set_count);
11406 CHECK_EQ(3, force_set_get_count);
11407 // Forcing the property to be set should cause the value to be
11408 // set locally without calling the interceptor.
11409 global->ForceSet(some_property, v8::Int32::New(8));
11410 CHECK_EQ(8, global->Get(some_property)->Int32Value());
11411 CHECK_EQ(1, force_set_set_count);
11412 CHECK_EQ(4, force_set_get_count);
11413 // Reenabling the interceptor should cause it to take precedence over
11414 // the property
11415 pass_on_get = false;
11416 CHECK_EQ(3, global->Get(some_property)->Int32Value());
11417 CHECK_EQ(1, force_set_set_count);
11418 CHECK_EQ(5, force_set_get_count);
11419 // The interceptor should also work for other properties
11420 CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
11421 CHECK_EQ(1, force_set_set_count);
11422 CHECK_EQ(6, force_set_get_count);
11423}
11424
11425
11426THREADED_TEST(ForceDelete) {
11427 v8::HandleScope scope;
11428 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11429 LocalContext context(NULL, templ);
11430 v8::Handle<v8::Object> global = context->Global();
11431
11432 // Ordinary properties
11433 v8::Handle<v8::String> simple_property = v8::String::New("p");
11434 global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
11435 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11436 // This should fail because the property is dont-delete.
11437 CHECK(!global->Delete(simple_property));
11438 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11439 // This should succeed even though the property is dont-delete.
11440 CHECK(global->ForceDelete(simple_property));
11441 CHECK(global->Get(simple_property)->IsUndefined());
11442}
11443
11444
11445static int force_delete_interceptor_count = 0;
11446static bool pass_on_delete = false;
11447
11448
11449static v8::Handle<v8::Boolean> ForceDeleteDeleter(
11450 v8::Local<v8::String> name,
11451 const v8::AccessorInfo& info) {
11452 force_delete_interceptor_count++;
11453 if (pass_on_delete) {
11454 return v8::Handle<v8::Boolean>();
11455 } else {
11456 return v8::True();
11457 }
11458}
11459
11460
11461THREADED_TEST(ForceDeleteWithInterceptor) {
11462 force_delete_interceptor_count = 0;
11463 pass_on_delete = false;
11464
11465 v8::HandleScope scope;
11466 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11467 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
11468 LocalContext context(NULL, templ);
11469 v8::Handle<v8::Object> global = context->Global();
11470
11471 v8::Handle<v8::String> some_property = v8::String::New("a");
11472 global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
11473
11474 // Deleting a property should get intercepted and nothing should
11475 // happen.
11476 CHECK_EQ(0, force_delete_interceptor_count);
11477 CHECK(global->Delete(some_property));
11478 CHECK_EQ(1, force_delete_interceptor_count);
11479 CHECK_EQ(42, global->Get(some_property)->Int32Value());
11480 // Deleting the property when the interceptor returns an empty
11481 // handle should not delete the property since it is DontDelete.
11482 pass_on_delete = true;
11483 CHECK(!global->Delete(some_property));
11484 CHECK_EQ(2, force_delete_interceptor_count);
11485 CHECK_EQ(42, global->Get(some_property)->Int32Value());
11486 // Forcing the property to be deleted should delete the value
11487 // without calling the interceptor.
11488 CHECK(global->ForceDelete(some_property));
11489 CHECK(global->Get(some_property)->IsUndefined());
11490 CHECK_EQ(2, force_delete_interceptor_count);
11491}
11492
11493
11494// Make sure that forcing a delete invalidates any IC stubs, so we
11495// don't read the hole value.
11496THREADED_TEST(ForceDeleteIC) {
11497 v8::HandleScope scope;
11498 LocalContext context;
11499 // Create a DontDelete variable on the global object.
11500 CompileRun("this.__proto__ = { foo: 'horse' };"
11501 "var foo = 'fish';"
11502 "function f() { return foo.length; }");
11503 // Initialize the IC for foo in f.
11504 CompileRun("for (var i = 0; i < 4; i++) f();");
11505 // Make sure the value of foo is correct before the deletion.
11506 CHECK_EQ(4, CompileRun("f()")->Int32Value());
11507 // Force the deletion of foo.
11508 CHECK(context->Global()->ForceDelete(v8_str("foo")));
11509 // Make sure the value for foo is read from the prototype, and that
11510 // we don't get in trouble with reading the deleted cell value
11511 // sentinel.
11512 CHECK_EQ(5, CompileRun("f()")->Int32Value());
11513}
11514
11515
11516v8::Persistent<Context> calling_context0;
11517v8::Persistent<Context> calling_context1;
11518v8::Persistent<Context> calling_context2;
11519
11520
11521// Check that the call to the callback is initiated in
11522// calling_context2, the directly calling context is calling_context1
11523// and the callback itself is in calling_context0.
11524static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
11525 ApiTestFuzzer::Fuzz();
11526 CHECK(Context::GetCurrent() == calling_context0);
11527 CHECK(Context::GetCalling() == calling_context1);
11528 CHECK(Context::GetEntered() == calling_context2);
11529 return v8::Integer::New(42);
11530}
11531
11532
11533THREADED_TEST(GetCallingContext) {
11534 v8::HandleScope scope;
11535
11536 calling_context0 = Context::New();
11537 calling_context1 = Context::New();
11538 calling_context2 = Context::New();
11539
11540 // Allow cross-domain access.
11541 Local<String> token = v8_str("<security token>");
11542 calling_context0->SetSecurityToken(token);
11543 calling_context1->SetSecurityToken(token);
11544 calling_context2->SetSecurityToken(token);
11545
11546 // Create an object with a C++ callback in context0.
11547 calling_context0->Enter();
11548 Local<v8::FunctionTemplate> callback_templ =
11549 v8::FunctionTemplate::New(GetCallingContextCallback);
11550 calling_context0->Global()->Set(v8_str("callback"),
11551 callback_templ->GetFunction());
11552 calling_context0->Exit();
11553
11554 // Expose context0 in context1 and setup a function that calls the
11555 // callback function.
11556 calling_context1->Enter();
11557 calling_context1->Global()->Set(v8_str("context0"),
11558 calling_context0->Global());
11559 CompileRun("function f() { context0.callback() }");
11560 calling_context1->Exit();
11561
11562 // Expose context1 in context2 and call the callback function in
11563 // context0 indirectly through f in context1.
11564 calling_context2->Enter();
11565 calling_context2->Global()->Set(v8_str("context1"),
11566 calling_context1->Global());
11567 CompileRun("context1.f()");
11568 calling_context2->Exit();
11569
11570 // Dispose the contexts to allow them to be garbage collected.
11571 calling_context0.Dispose();
11572 calling_context1.Dispose();
11573 calling_context2.Dispose();
11574 calling_context0.Clear();
11575 calling_context1.Clear();
11576 calling_context2.Clear();
11577}
11578
11579
11580// Check that a variable declaration with no explicit initialization
11581// value does not shadow an existing property in the prototype chain.
11582//
11583// This is consistent with Firefox and Safari.
11584//
11585// See http://crbug.com/12548.
11586THREADED_TEST(InitGlobalVarInProtoChain) {
11587 v8::HandleScope scope;
11588 LocalContext context;
11589 // Introduce a variable in the prototype chain.
11590 CompileRun("__proto__.x = 42");
11591 v8::Handle<v8::Value> result = CompileRun("var x; x");
11592 CHECK(!result->IsUndefined());
11593 CHECK_EQ(42, result->Int32Value());
11594}
11595
11596
11597// Regression test for issue 398.
11598// If a function is added to an object, creating a constant function
11599// field, and the result is cloned, replacing the constant function on the
11600// original should not affect the clone.
11601// See http://code.google.com/p/v8/issues/detail?id=398
11602THREADED_TEST(ReplaceConstantFunction) {
11603 v8::HandleScope scope;
11604 LocalContext context;
11605 v8::Handle<v8::Object> obj = v8::Object::New();
11606 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
11607 v8::Handle<v8::String> foo_string = v8::String::New("foo");
11608 obj->Set(foo_string, func_templ->GetFunction());
11609 v8::Handle<v8::Object> obj_clone = obj->Clone();
11610 obj_clone->Set(foo_string, v8::String::New("Hello"));
11611 CHECK(!obj->Get(foo_string)->IsUndefined());
11612}
11613
11614
11615// Regression test for http://crbug.com/16276.
11616THREADED_TEST(Regress16276) {
11617 v8::HandleScope scope;
11618 LocalContext context;
11619 // Force the IC in f to be a dictionary load IC.
11620 CompileRun("function f(obj) { return obj.x; }\n"
11621 "var obj = { x: { foo: 42 }, y: 87 };\n"
11622 "var x = obj.x;\n"
11623 "delete obj.y;\n"
11624 "for (var i = 0; i < 5; i++) f(obj);");
11625 // Detach the global object to make 'this' refer directly to the
11626 // global object (not the proxy), and make sure that the dictionary
11627 // load IC doesn't mess up loading directly from the global object.
11628 context->DetachGlobal();
11629 CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
11630}
11631
11632
11633THREADED_TEST(PixelArray) {
11634 v8::HandleScope scope;
11635 LocalContext context;
Steve Blockd0582a62009-12-15 09:54:21 +000011636 const int kElementCount = 260;
Steve Blocka7e24c12009-10-30 11:49:00 +000011637 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
Steve Block44f0eee2011-05-26 01:26:41 +010011638 i::Handle<i::ExternalPixelArray> pixels =
11639 i::Handle<i::ExternalPixelArray>::cast(
11640 FACTORY->NewExternalArray(kElementCount,
11641 v8::kExternalPixelArray,
11642 pixel_data));
11643 HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
Steve Blocka7e24c12009-10-30 11:49:00 +000011644 for (int i = 0; i < kElementCount; i++) {
Steve Blockd0582a62009-12-15 09:54:21 +000011645 pixels->set(i, i % 256);
Steve Blocka7e24c12009-10-30 11:49:00 +000011646 }
Steve Block44f0eee2011-05-26 01:26:41 +010011647 HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
Steve Blocka7e24c12009-10-30 11:49:00 +000011648 for (int i = 0; i < kElementCount; i++) {
Steve Blockd0582a62009-12-15 09:54:21 +000011649 CHECK_EQ(i % 256, pixels->get(i));
11650 CHECK_EQ(i % 256, pixel_data[i]);
Steve Blocka7e24c12009-10-30 11:49:00 +000011651 }
11652
11653 v8::Handle<v8::Object> obj = v8::Object::New();
11654 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
11655 // Set the elements to be the pixels.
11656 // jsobj->set_elements(*pixels);
11657 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
John Reck59135872010-11-02 12:39:01 -070011658 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011659 obj->Set(v8_str("field"), v8::Int32::New(1503));
11660 context->Global()->Set(v8_str("pixels"), obj);
11661 v8::Handle<v8::Value> result = CompileRun("pixels.field");
11662 CHECK_EQ(1503, result->Int32Value());
11663 result = CompileRun("pixels[1]");
11664 CHECK_EQ(1, result->Int32Value());
11665
11666 result = CompileRun("var sum = 0;"
11667 "for (var i = 0; i < 8; i++) {"
11668 " sum += pixels[i] = pixels[i] = -i;"
11669 "}"
11670 "sum;");
11671 CHECK_EQ(-28, result->Int32Value());
11672
11673 result = CompileRun("var sum = 0;"
11674 "for (var i = 0; i < 8; i++) {"
11675 " sum += pixels[i] = pixels[i] = 0;"
11676 "}"
11677 "sum;");
11678 CHECK_EQ(0, result->Int32Value());
11679
11680 result = CompileRun("var sum = 0;"
11681 "for (var i = 0; i < 8; i++) {"
11682 " sum += pixels[i] = pixels[i] = 255;"
11683 "}"
11684 "sum;");
11685 CHECK_EQ(8 * 255, result->Int32Value());
11686
11687 result = CompileRun("var sum = 0;"
11688 "for (var i = 0; i < 8; i++) {"
11689 " sum += pixels[i] = pixels[i] = 256 + i;"
11690 "}"
11691 "sum;");
11692 CHECK_EQ(2076, result->Int32Value());
11693
11694 result = CompileRun("var sum = 0;"
11695 "for (var i = 0; i < 8; i++) {"
11696 " sum += pixels[i] = pixels[i] = i;"
11697 "}"
11698 "sum;");
11699 CHECK_EQ(28, result->Int32Value());
11700
11701 result = CompileRun("var sum = 0;"
11702 "for (var i = 0; i < 8; i++) {"
11703 " sum += pixels[i];"
11704 "}"
11705 "sum;");
11706 CHECK_EQ(28, result->Int32Value());
11707
11708 i::Handle<i::Smi> value(i::Smi::FromInt(2));
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011709 i::SetElement(jsobj, 1, value, i::kNonStrictMode);
John Reck59135872010-11-02 12:39:01 -070011710 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011711 *value.location() = i::Smi::FromInt(256);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011712 i::SetElement(jsobj, 1, value, i::kNonStrictMode);
John Reck59135872010-11-02 12:39:01 -070011713 CHECK_EQ(255,
11714 i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011715 *value.location() = i::Smi::FromInt(-1);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011716 i::SetElement(jsobj, 1, value, i::kNonStrictMode);
John Reck59135872010-11-02 12:39:01 -070011717 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011718
11719 result = CompileRun("for (var i = 0; i < 8; i++) {"
11720 " pixels[i] = (i * 65) - 109;"
11721 "}"
11722 "pixels[1] + pixels[6];");
11723 CHECK_EQ(255, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070011724 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
11725 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
11726 CHECK_EQ(21,
11727 i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
11728 CHECK_EQ(86,
11729 i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
11730 CHECK_EQ(151,
11731 i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
11732 CHECK_EQ(216,
11733 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
11734 CHECK_EQ(255,
11735 i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
11736 CHECK_EQ(255,
11737 i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011738 result = CompileRun("var sum = 0;"
11739 "for (var i = 0; i < 8; i++) {"
11740 " sum += pixels[i];"
11741 "}"
11742 "sum;");
11743 CHECK_EQ(984, result->Int32Value());
11744
11745 result = CompileRun("for (var i = 0; i < 8; i++) {"
11746 " pixels[i] = (i * 1.1);"
11747 "}"
11748 "pixels[1] + pixels[6];");
11749 CHECK_EQ(8, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070011750 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
11751 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
11752 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
11753 CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
11754 CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
11755 CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
11756 CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
11757 CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011758
11759 result = CompileRun("for (var i = 0; i < 8; i++) {"
11760 " pixels[7] = undefined;"
11761 "}"
11762 "pixels[7];");
11763 CHECK_EQ(0, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070011764 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011765
11766 result = CompileRun("for (var i = 0; i < 8; i++) {"
11767 " pixels[6] = '2.3';"
11768 "}"
11769 "pixels[6];");
11770 CHECK_EQ(2, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070011771 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011772
11773 result = CompileRun("for (var i = 0; i < 8; i++) {"
11774 " pixels[5] = NaN;"
11775 "}"
11776 "pixels[5];");
11777 CHECK_EQ(0, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070011778 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011779
11780 result = CompileRun("for (var i = 0; i < 8; i++) {"
11781 " pixels[8] = Infinity;"
11782 "}"
11783 "pixels[8];");
11784 CHECK_EQ(255, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070011785 CHECK_EQ(255,
11786 i::Smi::cast(jsobj->GetElement(8)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011787
11788 result = CompileRun("for (var i = 0; i < 8; i++) {"
11789 " pixels[9] = -Infinity;"
11790 "}"
11791 "pixels[9];");
11792 CHECK_EQ(0, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070011793 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011794
11795 result = CompileRun("pixels[3] = 33;"
11796 "delete pixels[3];"
11797 "pixels[3];");
11798 CHECK_EQ(33, result->Int32Value());
11799
11800 result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
11801 "pixels[2] = 12; pixels[3] = 13;"
11802 "pixels.__defineGetter__('2',"
11803 "function() { return 120; });"
11804 "pixels[2];");
11805 CHECK_EQ(12, result->Int32Value());
11806
11807 result = CompileRun("var js_array = new Array(40);"
11808 "js_array[0] = 77;"
11809 "js_array;");
11810 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
11811
11812 result = CompileRun("pixels[1] = 23;"
11813 "pixels.__proto__ = [];"
11814 "js_array.__proto__ = pixels;"
11815 "js_array.concat(pixels);");
11816 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
11817 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
11818
11819 result = CompileRun("pixels[1] = 23;");
11820 CHECK_EQ(23, result->Int32Value());
11821
Steve Blockd0582a62009-12-15 09:54:21 +000011822 // Test for index greater than 255. Regression test for:
11823 // http://code.google.com/p/chromium/issues/detail?id=26337.
11824 result = CompileRun("pixels[256] = 255;");
11825 CHECK_EQ(255, result->Int32Value());
11826 result = CompileRun("var i = 0;"
11827 "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
11828 "i");
11829 CHECK_EQ(255, result->Int32Value());
11830
Steve Block1e0659c2011-05-24 12:43:12 +010011831 // Make sure that pixel array ICs recognize when a non-pixel array
11832 // is passed to it.
11833 result = CompileRun("function pa_load(p) {"
11834 " var sum = 0;"
11835 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
11836 " return sum;"
11837 "}"
11838 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11839 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
11840 "just_ints = new Object();"
11841 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11842 "for (var i = 0; i < 10; ++i) {"
11843 " result = pa_load(just_ints);"
11844 "}"
11845 "result");
11846 CHECK_EQ(32640, result->Int32Value());
11847
11848 // Make sure that pixel array ICs recognize out-of-bound accesses.
11849 result = CompileRun("function pa_load(p, start) {"
11850 " var sum = 0;"
11851 " for (var j = start; j < 256; j++) { sum += p[j]; }"
11852 " return sum;"
11853 "}"
11854 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11855 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
11856 "for (var i = 0; i < 10; ++i) {"
11857 " result = pa_load(pixels,-10);"
11858 "}"
11859 "result");
11860 CHECK_EQ(0, result->Int32Value());
11861
11862 // Make sure that generic ICs properly handles a pixel array.
11863 result = CompileRun("function pa_load(p) {"
11864 " var sum = 0;"
11865 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
11866 " return sum;"
11867 "}"
11868 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11869 "just_ints = new Object();"
11870 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11871 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
11872 "for (var i = 0; i < 10; ++i) {"
11873 " result = pa_load(pixels);"
11874 "}"
11875 "result");
11876 CHECK_EQ(32640, result->Int32Value());
11877
11878 // Make sure that generic load ICs recognize out-of-bound accesses in
11879 // pixel arrays.
11880 result = CompileRun("function pa_load(p, start) {"
11881 " var sum = 0;"
11882 " for (var j = start; j < 256; j++) { sum += p[j]; }"
11883 " return sum;"
11884 "}"
11885 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11886 "just_ints = new Object();"
11887 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11888 "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
11889 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
11890 "for (var i = 0; i < 10; ++i) {"
11891 " result = pa_load(pixels,-10);"
11892 "}"
11893 "result");
11894 CHECK_EQ(0, result->Int32Value());
11895
11896 // Make sure that generic ICs properly handles other types than pixel
11897 // arrays (that the inlined fast pixel array test leaves the right information
11898 // in the right registers).
11899 result = CompileRun("function pa_load(p) {"
11900 " var sum = 0;"
11901 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
11902 " return sum;"
11903 "}"
11904 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11905 "just_ints = new Object();"
11906 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11907 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
11908 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
11909 "sparse_array = new Object();"
11910 "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
11911 "sparse_array[1000000] = 3;"
11912 "for (var i = 0; i < 10; ++i) {"
11913 " result = pa_load(sparse_array);"
11914 "}"
11915 "result");
11916 CHECK_EQ(32640, result->Int32Value());
11917
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011918 // Make sure that pixel array store ICs clamp values correctly.
11919 result = CompileRun("function pa_store(p) {"
11920 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
11921 "}"
11922 "pa_store(pixels);"
11923 "var sum = 0;"
11924 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
11925 "sum");
11926 CHECK_EQ(48896, result->Int32Value());
11927
11928 // Make sure that pixel array stores correctly handle accesses outside
11929 // of the pixel array..
11930 result = CompileRun("function pa_store(p,start) {"
11931 " for (var j = 0; j < 256; j++) {"
11932 " p[j+start] = j * 2;"
11933 " }"
11934 "}"
11935 "pa_store(pixels,0);"
11936 "pa_store(pixels,-128);"
11937 "var sum = 0;"
11938 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
11939 "sum");
11940 CHECK_EQ(65280, result->Int32Value());
11941
11942 // Make sure that the generic store stub correctly handle accesses outside
11943 // of the pixel array..
11944 result = CompileRun("function pa_store(p,start) {"
11945 " for (var j = 0; j < 256; j++) {"
11946 " p[j+start] = j * 2;"
11947 " }"
11948 "}"
11949 "pa_store(pixels,0);"
11950 "just_ints = new Object();"
11951 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11952 "pa_store(just_ints, 0);"
11953 "pa_store(pixels,-128);"
11954 "var sum = 0;"
11955 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
11956 "sum");
11957 CHECK_EQ(65280, result->Int32Value());
11958
11959 // Make sure that the generic keyed store stub clamps pixel array values
11960 // correctly.
11961 result = CompileRun("function pa_store(p) {"
11962 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
11963 "}"
11964 "pa_store(pixels);"
11965 "just_ints = new Object();"
11966 "pa_store(just_ints);"
11967 "pa_store(pixels);"
11968 "var sum = 0;"
11969 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
11970 "sum");
11971 CHECK_EQ(48896, result->Int32Value());
11972
11973 // Make sure that pixel array loads are optimized by crankshaft.
Steve Block1e0659c2011-05-24 12:43:12 +010011974 result = CompileRun("function pa_load(p) {"
11975 " var sum = 0;"
11976 " for (var i=0; i<256; ++i) {"
11977 " sum += p[i];"
11978 " }"
11979 " return sum; "
11980 "}"
11981 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
Steve Block44f0eee2011-05-26 01:26:41 +010011982 "for (var i = 0; i < 5000; ++i) {"
Steve Block1e0659c2011-05-24 12:43:12 +010011983 " result = pa_load(pixels);"
11984 "}"
11985 "result");
11986 CHECK_EQ(32640, result->Int32Value());
11987
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011988 // Make sure that pixel array stores are optimized by crankshaft.
11989 result = CompileRun("function pa_init(p) {"
11990 "for (var i = 0; i < 256; ++i) { p[i] = i; }"
11991 "}"
11992 "function pa_load(p) {"
11993 " var sum = 0;"
11994 " for (var i=0; i<256; ++i) {"
11995 " sum += p[i];"
11996 " }"
11997 " return sum; "
11998 "}"
Steve Block44f0eee2011-05-26 01:26:41 +010011999 "for (var i = 0; i < 5000; ++i) {"
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012000 " pa_init(pixels);"
12001 "}"
12002 "result = pa_load(pixels);"
12003 "result");
12004 CHECK_EQ(32640, result->Int32Value());
12005
Steve Blocka7e24c12009-10-30 11:49:00 +000012006 free(pixel_data);
12007}
12008
12009
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010012010THREADED_TEST(PixelArrayInfo) {
12011 v8::HandleScope scope;
12012 LocalContext context;
12013 for (int size = 0; size < 100; size += 10) {
12014 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
12015 v8::Handle<v8::Object> obj = v8::Object::New();
12016 obj->SetIndexedPropertiesToPixelData(pixel_data, size);
12017 CHECK(obj->HasIndexedPropertiesInPixelData());
12018 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
12019 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
12020 free(pixel_data);
12021 }
12022}
12023
12024
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012025static v8::Handle<Value> NotHandledIndexedPropertyGetter(
12026 uint32_t index,
12027 const AccessorInfo& info) {
12028 ApiTestFuzzer::Fuzz();
12029 return v8::Handle<Value>();
12030}
12031
12032
12033static v8::Handle<Value> NotHandledIndexedPropertySetter(
12034 uint32_t index,
12035 Local<Value> value,
12036 const AccessorInfo& info) {
12037 ApiTestFuzzer::Fuzz();
12038 return v8::Handle<Value>();
12039}
12040
12041
12042THREADED_TEST(PixelArrayWithInterceptor) {
12043 v8::HandleScope scope;
12044 LocalContext context;
12045 const int kElementCount = 260;
12046 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
Steve Block44f0eee2011-05-26 01:26:41 +010012047 i::Handle<i::ExternalPixelArray> pixels =
12048 i::Handle<i::ExternalPixelArray>::cast(
12049 FACTORY->NewExternalArray(kElementCount,
12050 v8::kExternalPixelArray,
12051 pixel_data));
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012052 for (int i = 0; i < kElementCount; i++) {
12053 pixels->set(i, i % 256);
12054 }
12055 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12056 templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
12057 NotHandledIndexedPropertySetter);
12058 v8::Handle<v8::Object> obj = templ->NewInstance();
12059 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
12060 context->Global()->Set(v8_str("pixels"), obj);
12061 v8::Handle<v8::Value> result = CompileRun("pixels[1]");
12062 CHECK_EQ(1, result->Int32Value());
12063 result = CompileRun("var sum = 0;"
12064 "for (var i = 0; i < 8; i++) {"
12065 " sum += pixels[i] = pixels[i] = -i;"
12066 "}"
12067 "sum;");
12068 CHECK_EQ(-28, result->Int32Value());
12069 result = CompileRun("pixels.hasOwnProperty('1')");
12070 CHECK(result->BooleanValue());
12071 free(pixel_data);
12072}
12073
12074
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010012075static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
12076 switch (array_type) {
12077 case v8::kExternalByteArray:
12078 case v8::kExternalUnsignedByteArray:
Steve Block44f0eee2011-05-26 01:26:41 +010012079 case v8::kExternalPixelArray:
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010012080 return 1;
12081 break;
12082 case v8::kExternalShortArray:
12083 case v8::kExternalUnsignedShortArray:
12084 return 2;
12085 break;
12086 case v8::kExternalIntArray:
12087 case v8::kExternalUnsignedIntArray:
12088 case v8::kExternalFloatArray:
12089 return 4;
12090 break;
Ben Murdoch257744e2011-11-30 15:57:28 +000012091 case v8::kExternalDoubleArray:
12092 return 8;
12093 break;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010012094 default:
12095 UNREACHABLE();
12096 return -1;
12097 }
12098 UNREACHABLE();
12099 return -1;
12100}
12101
12102
Steve Block3ce2e202009-11-05 08:53:23 +000012103template <class ExternalArrayClass, class ElementType>
12104static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
12105 int64_t low,
12106 int64_t high) {
12107 v8::HandleScope scope;
12108 LocalContext context;
12109 const int kElementCount = 40;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010012110 int element_size = ExternalArrayElementSize(array_type);
Steve Block3ce2e202009-11-05 08:53:23 +000012111 ElementType* array_data =
12112 static_cast<ElementType*>(malloc(kElementCount * element_size));
12113 i::Handle<ExternalArrayClass> array =
12114 i::Handle<ExternalArrayClass>::cast(
Steve Block44f0eee2011-05-26 01:26:41 +010012115 FACTORY->NewExternalArray(kElementCount, array_type, array_data));
12116 HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
Steve Block3ce2e202009-11-05 08:53:23 +000012117 for (int i = 0; i < kElementCount; i++) {
12118 array->set(i, static_cast<ElementType>(i));
12119 }
Steve Block44f0eee2011-05-26 01:26:41 +010012120 HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
Steve Block3ce2e202009-11-05 08:53:23 +000012121 for (int i = 0; i < kElementCount; i++) {
12122 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array->get(i)));
12123 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
12124 }
12125
12126 v8::Handle<v8::Object> obj = v8::Object::New();
12127 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
12128 // Set the elements to be the external array.
12129 obj->SetIndexedPropertiesToExternalArrayData(array_data,
12130 array_type,
12131 kElementCount);
John Reck59135872010-11-02 12:39:01 -070012132 CHECK_EQ(
12133 1, static_cast<int>(jsobj->GetElement(1)->ToObjectChecked()->Number()));
Steve Block3ce2e202009-11-05 08:53:23 +000012134 obj->Set(v8_str("field"), v8::Int32::New(1503));
12135 context->Global()->Set(v8_str("ext_array"), obj);
12136 v8::Handle<v8::Value> result = CompileRun("ext_array.field");
12137 CHECK_EQ(1503, result->Int32Value());
12138 result = CompileRun("ext_array[1]");
12139 CHECK_EQ(1, result->Int32Value());
12140
12141 // Check pass through of assigned smis
12142 result = CompileRun("var sum = 0;"
12143 "for (var i = 0; i < 8; i++) {"
12144 " sum += ext_array[i] = ext_array[i] = -i;"
12145 "}"
12146 "sum;");
12147 CHECK_EQ(-28, result->Int32Value());
12148
12149 // Check assigned smis
12150 result = CompileRun("for (var i = 0; i < 8; i++) {"
12151 " ext_array[i] = i;"
12152 "}"
12153 "var sum = 0;"
12154 "for (var i = 0; i < 8; i++) {"
12155 " sum += ext_array[i];"
12156 "}"
12157 "sum;");
12158 CHECK_EQ(28, result->Int32Value());
12159
12160 // Check assigned smis in reverse order
12161 result = CompileRun("for (var i = 8; --i >= 0; ) {"
12162 " ext_array[i] = i;"
12163 "}"
12164 "var sum = 0;"
12165 "for (var i = 0; i < 8; i++) {"
12166 " sum += ext_array[i];"
12167 "}"
12168 "sum;");
12169 CHECK_EQ(28, result->Int32Value());
12170
12171 // Check pass through of assigned HeapNumbers
12172 result = CompileRun("var sum = 0;"
12173 "for (var i = 0; i < 16; i+=2) {"
12174 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
12175 "}"
12176 "sum;");
12177 CHECK_EQ(-28, result->Int32Value());
12178
12179 // Check assigned HeapNumbers
12180 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
12181 " ext_array[i] = (i * 0.5);"
12182 "}"
12183 "var sum = 0;"
12184 "for (var i = 0; i < 16; i+=2) {"
12185 " sum += ext_array[i];"
12186 "}"
12187 "sum;");
12188 CHECK_EQ(28, result->Int32Value());
12189
12190 // Check assigned HeapNumbers in reverse order
12191 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
12192 " ext_array[i] = (i * 0.5);"
12193 "}"
12194 "var sum = 0;"
12195 "for (var i = 0; i < 16; i+=2) {"
12196 " sum += ext_array[i];"
12197 "}"
12198 "sum;");
12199 CHECK_EQ(28, result->Int32Value());
12200
12201 i::ScopedVector<char> test_buf(1024);
12202
12203 // Check legal boundary conditions.
12204 // The repeated loads and stores ensure the ICs are exercised.
12205 const char* boundary_program =
12206 "var res = 0;"
12207 "for (var i = 0; i < 16; i++) {"
12208 " ext_array[i] = %lld;"
12209 " if (i > 8) {"
12210 " res = ext_array[i];"
12211 " }"
12212 "}"
12213 "res;";
12214 i::OS::SNPrintF(test_buf,
12215 boundary_program,
12216 low);
12217 result = CompileRun(test_buf.start());
12218 CHECK_EQ(low, result->IntegerValue());
12219
12220 i::OS::SNPrintF(test_buf,
12221 boundary_program,
12222 high);
12223 result = CompileRun(test_buf.start());
12224 CHECK_EQ(high, result->IntegerValue());
12225
12226 // Check misprediction of type in IC.
12227 result = CompileRun("var tmp_array = ext_array;"
12228 "var sum = 0;"
12229 "for (var i = 0; i < 8; i++) {"
12230 " tmp_array[i] = i;"
12231 " sum += tmp_array[i];"
12232 " if (i == 4) {"
12233 " tmp_array = {};"
12234 " }"
12235 "}"
12236 "sum;");
Steve Block44f0eee2011-05-26 01:26:41 +010012237 HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
Steve Block3ce2e202009-11-05 08:53:23 +000012238 CHECK_EQ(28, result->Int32Value());
12239
12240 // Make sure out-of-range loads do not throw.
12241 i::OS::SNPrintF(test_buf,
12242 "var caught_exception = false;"
12243 "try {"
12244 " ext_array[%d];"
12245 "} catch (e) {"
12246 " caught_exception = true;"
12247 "}"
12248 "caught_exception;",
12249 kElementCount);
12250 result = CompileRun(test_buf.start());
12251 CHECK_EQ(false, result->BooleanValue());
12252
12253 // Make sure out-of-range stores do not throw.
12254 i::OS::SNPrintF(test_buf,
12255 "var caught_exception = false;"
12256 "try {"
12257 " ext_array[%d] = 1;"
12258 "} catch (e) {"
12259 " caught_exception = true;"
12260 "}"
12261 "caught_exception;",
12262 kElementCount);
12263 result = CompileRun(test_buf.start());
12264 CHECK_EQ(false, result->BooleanValue());
12265
12266 // Check other boundary conditions, values and operations.
12267 result = CompileRun("for (var i = 0; i < 8; i++) {"
12268 " ext_array[7] = undefined;"
12269 "}"
12270 "ext_array[7];");
12271 CHECK_EQ(0, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070012272 CHECK_EQ(
12273 0, static_cast<int>(jsobj->GetElement(7)->ToObjectChecked()->Number()));
Steve Block3ce2e202009-11-05 08:53:23 +000012274
12275 result = CompileRun("for (var i = 0; i < 8; i++) {"
12276 " ext_array[6] = '2.3';"
12277 "}"
12278 "ext_array[6];");
12279 CHECK_EQ(2, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070012280 CHECK_EQ(
12281 2, static_cast<int>(jsobj->GetElement(6)->ToObjectChecked()->Number()));
Steve Block3ce2e202009-11-05 08:53:23 +000012282
Ben Murdoch257744e2011-11-30 15:57:28 +000012283 if (array_type != v8::kExternalFloatArray &&
12284 array_type != v8::kExternalDoubleArray) {
Steve Block3ce2e202009-11-05 08:53:23 +000012285 // Though the specification doesn't state it, be explicit about
12286 // converting NaNs and +/-Infinity to zero.
12287 result = CompileRun("for (var i = 0; i < 8; i++) {"
12288 " ext_array[i] = 5;"
12289 "}"
12290 "for (var i = 0; i < 8; i++) {"
12291 " ext_array[i] = NaN;"
12292 "}"
12293 "ext_array[5];");
12294 CHECK_EQ(0, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070012295 CHECK_EQ(0,
12296 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
Steve Block3ce2e202009-11-05 08:53:23 +000012297
12298 result = CompileRun("for (var i = 0; i < 8; i++) {"
12299 " ext_array[i] = 5;"
12300 "}"
12301 "for (var i = 0; i < 8; i++) {"
12302 " ext_array[i] = Infinity;"
12303 "}"
12304 "ext_array[5];");
Steve Block44f0eee2011-05-26 01:26:41 +010012305 int expected_value =
12306 (array_type == v8::kExternalPixelArray) ? 255 : 0;
12307 CHECK_EQ(expected_value, result->Int32Value());
12308 CHECK_EQ(expected_value,
John Reck59135872010-11-02 12:39:01 -070012309 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
Steve Block3ce2e202009-11-05 08:53:23 +000012310
12311 result = CompileRun("for (var i = 0; i < 8; i++) {"
12312 " ext_array[i] = 5;"
12313 "}"
12314 "for (var i = 0; i < 8; i++) {"
12315 " ext_array[i] = -Infinity;"
12316 "}"
12317 "ext_array[5];");
12318 CHECK_EQ(0, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070012319 CHECK_EQ(0,
12320 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
Steve Block1e0659c2011-05-24 12:43:12 +010012321
12322 // Check truncation behavior of integral arrays.
12323 const char* unsigned_data =
12324 "var source_data = [0.6, 10.6];"
12325 "var expected_results = [0, 10];";
12326 const char* signed_data =
12327 "var source_data = [0.6, 10.6, -0.6, -10.6];"
12328 "var expected_results = [0, 10, 0, -10];";
Steve Block44f0eee2011-05-26 01:26:41 +010012329 const char* pixel_data =
12330 "var source_data = [0.6, 10.6];"
12331 "var expected_results = [1, 11];";
Steve Block1e0659c2011-05-24 12:43:12 +010012332 bool is_unsigned =
12333 (array_type == v8::kExternalUnsignedByteArray ||
12334 array_type == v8::kExternalUnsignedShortArray ||
12335 array_type == v8::kExternalUnsignedIntArray);
Steve Block44f0eee2011-05-26 01:26:41 +010012336 bool is_pixel_data = array_type == v8::kExternalPixelArray;
Steve Block1e0659c2011-05-24 12:43:12 +010012337
12338 i::OS::SNPrintF(test_buf,
12339 "%s"
12340 "var all_passed = true;"
12341 "for (var i = 0; i < source_data.length; i++) {"
12342 " for (var j = 0; j < 8; j++) {"
12343 " ext_array[j] = source_data[i];"
12344 " }"
12345 " all_passed = all_passed &&"
12346 " (ext_array[5] == expected_results[i]);"
12347 "}"
12348 "all_passed;",
Steve Block44f0eee2011-05-26 01:26:41 +010012349 (is_unsigned ?
12350 unsigned_data :
12351 (is_pixel_data ? pixel_data : signed_data)));
Steve Block1e0659c2011-05-24 12:43:12 +010012352 result = CompileRun(test_buf.start());
12353 CHECK_EQ(true, result->BooleanValue());
Steve Block3ce2e202009-11-05 08:53:23 +000012354 }
12355
Ben Murdoch8b112d22011-06-08 16:22:53 +010012356 for (int i = 0; i < kElementCount; i++) {
12357 array->set(i, static_cast<ElementType>(i));
12358 }
12359 // Test complex assignments
12360 result = CompileRun("function ee_op_test_complex_func(sum) {"
12361 " for (var i = 0; i < 40; ++i) {"
12362 " sum += (ext_array[i] += 1);"
12363 " sum += (ext_array[i] -= 1);"
12364 " } "
12365 " return sum;"
12366 "}"
12367 "sum=0;"
12368 "for (var i=0;i<10000;++i) {"
12369 " sum=ee_op_test_complex_func(sum);"
12370 "}"
12371 "sum;");
12372 CHECK_EQ(16000000, result->Int32Value());
12373
12374 // Test count operations
12375 result = CompileRun("function ee_op_test_count_func(sum) {"
12376 " for (var i = 0; i < 40; ++i) {"
12377 " sum += (++ext_array[i]);"
12378 " sum += (--ext_array[i]);"
12379 " } "
12380 " return sum;"
12381 "}"
12382 "sum=0;"
12383 "for (var i=0;i<10000;++i) {"
12384 " sum=ee_op_test_count_func(sum);"
12385 "}"
12386 "sum;");
12387 CHECK_EQ(16000000, result->Int32Value());
12388
Steve Block3ce2e202009-11-05 08:53:23 +000012389 result = CompileRun("ext_array[3] = 33;"
12390 "delete ext_array[3];"
12391 "ext_array[3];");
12392 CHECK_EQ(33, result->Int32Value());
12393
12394 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
12395 "ext_array[2] = 12; ext_array[3] = 13;"
12396 "ext_array.__defineGetter__('2',"
12397 "function() { return 120; });"
12398 "ext_array[2];");
12399 CHECK_EQ(12, result->Int32Value());
12400
12401 result = CompileRun("var js_array = new Array(40);"
12402 "js_array[0] = 77;"
12403 "js_array;");
12404 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
12405
12406 result = CompileRun("ext_array[1] = 23;"
12407 "ext_array.__proto__ = [];"
12408 "js_array.__proto__ = ext_array;"
12409 "js_array.concat(ext_array);");
12410 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
12411 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
12412
12413 result = CompileRun("ext_array[1] = 23;");
12414 CHECK_EQ(23, result->Int32Value());
12415
Steve Blockd0582a62009-12-15 09:54:21 +000012416 // Test more complex manipulations which cause eax to contain values
12417 // that won't be completely overwritten by loads from the arrays.
12418 // This catches bugs in the instructions used for the KeyedLoadIC
12419 // for byte and word types.
12420 {
12421 const int kXSize = 300;
12422 const int kYSize = 300;
12423 const int kLargeElementCount = kXSize * kYSize * 4;
12424 ElementType* large_array_data =
12425 static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
12426 i::Handle<ExternalArrayClass> large_array =
12427 i::Handle<ExternalArrayClass>::cast(
Steve Block44f0eee2011-05-26 01:26:41 +010012428 FACTORY->NewExternalArray(kLargeElementCount,
Steve Blockd0582a62009-12-15 09:54:21 +000012429 array_type,
12430 array_data));
12431 v8::Handle<v8::Object> large_obj = v8::Object::New();
12432 // Set the elements to be the external array.
12433 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
12434 array_type,
12435 kLargeElementCount);
12436 context->Global()->Set(v8_str("large_array"), large_obj);
12437 // Initialize contents of a few rows.
12438 for (int x = 0; x < 300; x++) {
12439 int row = 0;
12440 int offset = row * 300 * 4;
12441 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
12442 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
12443 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
12444 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
12445 row = 150;
12446 offset = row * 300 * 4;
12447 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
12448 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
12449 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
12450 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
12451 row = 298;
12452 offset = row * 300 * 4;
12453 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
12454 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
12455 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
12456 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
12457 }
12458 // The goal of the code below is to make "offset" large enough
12459 // that the computation of the index (which goes into eax) has
12460 // high bits set which will not be overwritten by a byte or short
12461 // load.
12462 result = CompileRun("var failed = false;"
12463 "var offset = 0;"
12464 "for (var i = 0; i < 300; i++) {"
12465 " if (large_array[4 * i] != 127 ||"
12466 " large_array[4 * i + 1] != 0 ||"
12467 " large_array[4 * i + 2] != 0 ||"
12468 " large_array[4 * i + 3] != 127) {"
12469 " failed = true;"
12470 " }"
12471 "}"
12472 "offset = 150 * 300 * 4;"
12473 "for (var i = 0; i < 300; i++) {"
12474 " if (large_array[offset + 4 * i] != 127 ||"
12475 " large_array[offset + 4 * i + 1] != 0 ||"
12476 " large_array[offset + 4 * i + 2] != 0 ||"
12477 " large_array[offset + 4 * i + 3] != 127) {"
12478 " failed = true;"
12479 " }"
12480 "}"
12481 "offset = 298 * 300 * 4;"
12482 "for (var i = 0; i < 300; i++) {"
12483 " if (large_array[offset + 4 * i] != 127 ||"
12484 " large_array[offset + 4 * i + 1] != 0 ||"
12485 " large_array[offset + 4 * i + 2] != 0 ||"
12486 " large_array[offset + 4 * i + 3] != 127) {"
12487 " failed = true;"
12488 " }"
12489 "}"
12490 "!failed;");
12491 CHECK_EQ(true, result->BooleanValue());
12492 free(large_array_data);
12493 }
12494
Steve Block44f0eee2011-05-26 01:26:41 +010012495 // The "" property descriptor is overloaded to store information about
12496 // the external array. Ensure that setting and accessing the "" property
12497 // works (it should overwrite the information cached about the external
12498 // array in the DescriptorArray) in various situations.
12499 result = CompileRun("ext_array[''] = 23; ext_array['']");
12500 CHECK_EQ(23, result->Int32Value());
12501
12502 // Property "" set after the external array is associated with the object.
12503 {
12504 v8::Handle<v8::Object> obj2 = v8::Object::New();
12505 obj2->Set(v8_str("ee_test_field"), v8::Int32::New(256));
12506 obj2->Set(v8_str(""), v8::Int32::New(1503));
12507 // Set the elements to be the external array.
12508 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
12509 array_type,
12510 kElementCount);
12511 context->Global()->Set(v8_str("ext_array"), obj2);
12512 result = CompileRun("ext_array['']");
12513 CHECK_EQ(1503, result->Int32Value());
12514 }
12515
12516 // Property "" set after the external array is associated with the object.
12517 {
12518 v8::Handle<v8::Object> obj2 = v8::Object::New();
12519 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
12520 // Set the elements to be the external array.
12521 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
12522 array_type,
12523 kElementCount);
12524 obj2->Set(v8_str(""), v8::Int32::New(1503));
12525 context->Global()->Set(v8_str("ext_array"), obj2);
12526 result = CompileRun("ext_array['']");
12527 CHECK_EQ(1503, result->Int32Value());
12528 }
12529
12530 // Should reuse the map from previous test.
12531 {
12532 v8::Handle<v8::Object> obj2 = v8::Object::New();
12533 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
12534 // Set the elements to be the external array. Should re-use the map
12535 // from previous test.
12536 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
12537 array_type,
12538 kElementCount);
12539 context->Global()->Set(v8_str("ext_array"), obj2);
12540 result = CompileRun("ext_array['']");
12541 }
12542
12543 // Property "" is a constant function that shouldn't not be interfered with
12544 // when an external array is set.
12545 {
12546 v8::Handle<v8::Object> obj2 = v8::Object::New();
12547 // Start
12548 obj2->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
12549
12550 // Add a constant function to an object.
12551 context->Global()->Set(v8_str("ext_array"), obj2);
12552 result = CompileRun("ext_array[''] = function() {return 1503;};"
12553 "ext_array['']();");
12554
12555 // Add an external array transition to the same map that
12556 // has the constant transition.
12557 v8::Handle<v8::Object> obj3 = v8::Object::New();
12558 obj3->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
12559 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
12560 array_type,
12561 kElementCount);
12562 context->Global()->Set(v8_str("ext_array"), obj3);
12563 }
12564
12565 // If a external array transition is in the map, it should get clobbered
12566 // by a constant function.
12567 {
12568 // Add an external array transition.
12569 v8::Handle<v8::Object> obj3 = v8::Object::New();
12570 obj3->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
12571 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
12572 array_type,
12573 kElementCount);
12574
12575 // Add a constant function to the same map that just got an external array
12576 // transition.
12577 v8::Handle<v8::Object> obj2 = v8::Object::New();
12578 obj2->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
12579 context->Global()->Set(v8_str("ext_array"), obj2);
12580 result = CompileRun("ext_array[''] = function() {return 1503;};"
12581 "ext_array['']();");
12582 }
12583
Steve Block3ce2e202009-11-05 08:53:23 +000012584 free(array_data);
12585}
12586
12587
12588THREADED_TEST(ExternalByteArray) {
Steve Block8defd9f2010-07-08 12:39:36 +010012589 ExternalArrayTestHelper<i::ExternalByteArray, int8_t>(
Steve Block3ce2e202009-11-05 08:53:23 +000012590 v8::kExternalByteArray,
12591 -128,
12592 127);
12593}
12594
12595
12596THREADED_TEST(ExternalUnsignedByteArray) {
Steve Block8defd9f2010-07-08 12:39:36 +010012597 ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>(
Steve Block3ce2e202009-11-05 08:53:23 +000012598 v8::kExternalUnsignedByteArray,
12599 0,
12600 255);
12601}
12602
12603
Steve Block44f0eee2011-05-26 01:26:41 +010012604THREADED_TEST(ExternalPixelArray) {
12605 ExternalArrayTestHelper<i::ExternalPixelArray, uint8_t>(
12606 v8::kExternalPixelArray,
12607 0,
12608 255);
12609}
12610
12611
Steve Block3ce2e202009-11-05 08:53:23 +000012612THREADED_TEST(ExternalShortArray) {
Steve Block8defd9f2010-07-08 12:39:36 +010012613 ExternalArrayTestHelper<i::ExternalShortArray, int16_t>(
Steve Block3ce2e202009-11-05 08:53:23 +000012614 v8::kExternalShortArray,
12615 -32768,
12616 32767);
12617}
12618
12619
12620THREADED_TEST(ExternalUnsignedShortArray) {
Steve Block8defd9f2010-07-08 12:39:36 +010012621 ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>(
Steve Block3ce2e202009-11-05 08:53:23 +000012622 v8::kExternalUnsignedShortArray,
12623 0,
12624 65535);
12625}
12626
12627
12628THREADED_TEST(ExternalIntArray) {
Steve Block8defd9f2010-07-08 12:39:36 +010012629 ExternalArrayTestHelper<i::ExternalIntArray, int32_t>(
Steve Block3ce2e202009-11-05 08:53:23 +000012630 v8::kExternalIntArray,
12631 INT_MIN, // -2147483648
12632 INT_MAX); // 2147483647
12633}
12634
12635
12636THREADED_TEST(ExternalUnsignedIntArray) {
Steve Block8defd9f2010-07-08 12:39:36 +010012637 ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>(
Steve Block3ce2e202009-11-05 08:53:23 +000012638 v8::kExternalUnsignedIntArray,
12639 0,
12640 UINT_MAX); // 4294967295
12641}
12642
12643
12644THREADED_TEST(ExternalFloatArray) {
Steve Block8defd9f2010-07-08 12:39:36 +010012645 ExternalArrayTestHelper<i::ExternalFloatArray, float>(
Steve Block3ce2e202009-11-05 08:53:23 +000012646 v8::kExternalFloatArray,
12647 -500,
12648 500);
12649}
12650
12651
Ben Murdoch257744e2011-11-30 15:57:28 +000012652THREADED_TEST(ExternalDoubleArray) {
12653 ExternalArrayTestHelper<i::ExternalDoubleArray, double>(
12654 v8::kExternalDoubleArray,
12655 -500,
12656 500);
12657}
12658
12659
Steve Block3ce2e202009-11-05 08:53:23 +000012660THREADED_TEST(ExternalArrays) {
12661 TestExternalByteArray();
12662 TestExternalUnsignedByteArray();
12663 TestExternalShortArray();
12664 TestExternalUnsignedShortArray();
12665 TestExternalIntArray();
12666 TestExternalUnsignedIntArray();
12667 TestExternalFloatArray();
12668}
12669
12670
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010012671void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
12672 v8::HandleScope scope;
12673 LocalContext context;
12674 for (int size = 0; size < 100; size += 10) {
12675 int element_size = ExternalArrayElementSize(array_type);
12676 void* external_data = malloc(size * element_size);
12677 v8::Handle<v8::Object> obj = v8::Object::New();
12678 obj->SetIndexedPropertiesToExternalArrayData(
12679 external_data, array_type, size);
12680 CHECK(obj->HasIndexedPropertiesInExternalArrayData());
12681 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
12682 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
12683 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
12684 free(external_data);
12685 }
12686}
12687
12688
12689THREADED_TEST(ExternalArrayInfo) {
12690 ExternalArrayInfoTestHelper(v8::kExternalByteArray);
12691 ExternalArrayInfoTestHelper(v8::kExternalUnsignedByteArray);
12692 ExternalArrayInfoTestHelper(v8::kExternalShortArray);
12693 ExternalArrayInfoTestHelper(v8::kExternalUnsignedShortArray);
12694 ExternalArrayInfoTestHelper(v8::kExternalIntArray);
12695 ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray);
12696 ExternalArrayInfoTestHelper(v8::kExternalFloatArray);
Ben Murdoch257744e2011-11-30 15:57:28 +000012697 ExternalArrayInfoTestHelper(v8::kExternalDoubleArray);
Steve Block44f0eee2011-05-26 01:26:41 +010012698 ExternalArrayInfoTestHelper(v8::kExternalPixelArray);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010012699}
12700
12701
Steve Blocka7e24c12009-10-30 11:49:00 +000012702THREADED_TEST(ScriptContextDependence) {
12703 v8::HandleScope scope;
12704 LocalContext c1;
12705 const char *source = "foo";
12706 v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
12707 v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
12708 c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
12709 CHECK_EQ(dep->Run()->Int32Value(), 100);
12710 CHECK_EQ(indep->Run()->Int32Value(), 100);
12711 LocalContext c2;
12712 c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
12713 CHECK_EQ(dep->Run()->Int32Value(), 100);
12714 CHECK_EQ(indep->Run()->Int32Value(), 101);
12715}
12716
12717
12718THREADED_TEST(StackTrace) {
12719 v8::HandleScope scope;
12720 LocalContext context;
12721 v8::TryCatch try_catch;
12722 const char *source = "function foo() { FAIL.FAIL; }; foo();";
12723 v8::Handle<v8::String> src = v8::String::New(source);
12724 v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
12725 v8::Script::New(src, origin)->Run();
12726 CHECK(try_catch.HasCaught());
12727 v8::String::Utf8Value stack(try_catch.StackTrace());
12728 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
12729}
12730
12731
Kristian Monsen25f61362010-05-21 11:50:48 +010012732// Checks that a StackFrame has certain expected values.
12733void checkStackFrame(const char* expected_script_name,
12734 const char* expected_func_name, int expected_line_number,
12735 int expected_column, bool is_eval, bool is_constructor,
12736 v8::Handle<v8::StackFrame> frame) {
12737 v8::HandleScope scope;
12738 v8::String::Utf8Value func_name(frame->GetFunctionName());
12739 v8::String::Utf8Value script_name(frame->GetScriptName());
12740 if (*script_name == NULL) {
12741 // The situation where there is no associated script, like for evals.
12742 CHECK(expected_script_name == NULL);
12743 } else {
12744 CHECK(strstr(*script_name, expected_script_name) != NULL);
12745 }
12746 CHECK(strstr(*func_name, expected_func_name) != NULL);
12747 CHECK_EQ(expected_line_number, frame->GetLineNumber());
12748 CHECK_EQ(expected_column, frame->GetColumn());
12749 CHECK_EQ(is_eval, frame->IsEval());
12750 CHECK_EQ(is_constructor, frame->IsConstructor());
12751}
12752
12753
12754v8::Handle<Value> AnalyzeStackInNativeCode(const v8::Arguments& args) {
12755 v8::HandleScope scope;
12756 const char* origin = "capture-stack-trace-test";
12757 const int kOverviewTest = 1;
12758 const int kDetailedTest = 2;
12759
12760 ASSERT(args.Length() == 1);
12761
12762 int testGroup = args[0]->Int32Value();
12763 if (testGroup == kOverviewTest) {
12764 v8::Handle<v8::StackTrace> stackTrace =
12765 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
12766 CHECK_EQ(4, stackTrace->GetFrameCount());
12767 checkStackFrame(origin, "bar", 2, 10, false, false,
12768 stackTrace->GetFrame(0));
12769 checkStackFrame(origin, "foo", 6, 3, false, false,
12770 stackTrace->GetFrame(1));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012771 // This is the source string inside the eval which has the call to foo.
12772 checkStackFrame(NULL, "", 1, 5, false, false,
Kristian Monsen25f61362010-05-21 11:50:48 +010012773 stackTrace->GetFrame(2));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012774 // The last frame is an anonymous function which has the initial eval call.
Kristian Monsen25f61362010-05-21 11:50:48 +010012775 checkStackFrame(origin, "", 8, 7, false, false,
12776 stackTrace->GetFrame(3));
12777
12778 CHECK(stackTrace->AsArray()->IsArray());
12779 } else if (testGroup == kDetailedTest) {
12780 v8::Handle<v8::StackTrace> stackTrace =
12781 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
12782 CHECK_EQ(4, stackTrace->GetFrameCount());
12783 checkStackFrame(origin, "bat", 4, 22, false, false,
12784 stackTrace->GetFrame(0));
12785 checkStackFrame(origin, "baz", 8, 3, false, true,
12786 stackTrace->GetFrame(1));
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010012787#ifdef ENABLE_DEBUGGER_SUPPORT
12788 bool is_eval = true;
12789#else // ENABLE_DEBUGGER_SUPPORT
12790 bool is_eval = false;
12791#endif // ENABLE_DEBUGGER_SUPPORT
12792
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012793 // This is the source string inside the eval which has the call to baz.
12794 checkStackFrame(NULL, "", 1, 5, is_eval, false,
Kristian Monsen25f61362010-05-21 11:50:48 +010012795 stackTrace->GetFrame(2));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012796 // The last frame is an anonymous function which has the initial eval call.
Kristian Monsen25f61362010-05-21 11:50:48 +010012797 checkStackFrame(origin, "", 10, 1, false, false,
12798 stackTrace->GetFrame(3));
12799
12800 CHECK(stackTrace->AsArray()->IsArray());
12801 }
12802 return v8::Undefined();
12803}
12804
12805
12806// Tests the C++ StackTrace API.
Ben Murdochb0fe1622011-05-05 13:52:32 +010012807// TODO(3074796): Reenable this as a THREADED_TEST once it passes.
12808// THREADED_TEST(CaptureStackTrace) {
12809TEST(CaptureStackTrace) {
Kristian Monsen25f61362010-05-21 11:50:48 +010012810 v8::HandleScope scope;
12811 v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
12812 Local<ObjectTemplate> templ = ObjectTemplate::New();
12813 templ->Set(v8_str("AnalyzeStackInNativeCode"),
12814 v8::FunctionTemplate::New(AnalyzeStackInNativeCode));
12815 LocalContext context(0, templ);
12816
12817 // Test getting OVERVIEW information. Should ignore information that is not
12818 // script name, function name, line number, and column offset.
12819 const char *overview_source =
12820 "function bar() {\n"
12821 " var y; AnalyzeStackInNativeCode(1);\n"
12822 "}\n"
12823 "function foo() {\n"
12824 "\n"
12825 " bar();\n"
12826 "}\n"
12827 "var x;eval('new foo();');";
12828 v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
12829 v8::Handle<Value> overview_result =
12830 v8::Script::New(overview_src, origin)->Run();
12831 ASSERT(!overview_result.IsEmpty());
12832 ASSERT(overview_result->IsObject());
12833
12834 // Test getting DETAILED information.
12835 const char *detailed_source =
12836 "function bat() {AnalyzeStackInNativeCode(2);\n"
12837 "}\n"
12838 "\n"
12839 "function baz() {\n"
12840 " bat();\n"
12841 "}\n"
12842 "eval('new baz();');";
12843 v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
12844 // Make the script using a non-zero line and column offset.
12845 v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
12846 v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
12847 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
12848 v8::Handle<v8::Script> detailed_script(
12849 v8::Script::New(detailed_src, &detailed_origin));
12850 v8::Handle<Value> detailed_result = detailed_script->Run();
12851 ASSERT(!detailed_result.IsEmpty());
12852 ASSERT(detailed_result->IsObject());
12853}
12854
12855
Ben Murdoch3bec4d22010-07-22 14:51:16 +010012856static void StackTraceForUncaughtExceptionListener(
12857 v8::Handle<v8::Message> message,
12858 v8::Handle<Value>) {
12859 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
12860 CHECK_EQ(2, stack_trace->GetFrameCount());
12861 checkStackFrame("origin", "foo", 2, 3, false, false,
12862 stack_trace->GetFrame(0));
12863 checkStackFrame("origin", "bar", 5, 3, false, false,
12864 stack_trace->GetFrame(1));
12865}
12866
12867TEST(CaptureStackTraceForUncaughtException) {
12868 report_count = 0;
12869 v8::HandleScope scope;
12870 LocalContext env;
12871 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
12872 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
12873
12874 Script::Compile(v8_str("function foo() {\n"
12875 " throw 1;\n"
12876 "};\n"
12877 "function bar() {\n"
12878 " foo();\n"
12879 "};"),
12880 v8_str("origin"))->Run();
12881 v8::Local<v8::Object> global = env->Global();
12882 Local<Value> trouble = global->Get(v8_str("bar"));
12883 CHECK(trouble->IsFunction());
12884 Function::Cast(*trouble)->Call(global, 0, NULL);
12885 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
12886 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
12887}
12888
12889
Steve Block1e0659c2011-05-24 12:43:12 +010012890TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
12891 v8::HandleScope scope;
12892 LocalContext env;
12893 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
12894 1024,
12895 v8::StackTrace::kDetailed);
12896
12897 CompileRun(
12898 "var setters = ['column', 'lineNumber', 'scriptName',\n"
12899 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
12900 " 'isConstructor'];\n"
12901 "for (var i = 0; i < setters.length; i++) {\n"
12902 " var prop = setters[i];\n"
12903 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
12904 "}\n");
12905 CompileRun("throw 'exception';");
12906 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
12907}
12908
12909
Ben Murdochf87a2032010-10-22 12:50:53 +010012910v8::Handle<Value> AnalyzeStackOfEvalWithSourceURL(const v8::Arguments& args) {
12911 v8::HandleScope scope;
12912 v8::Handle<v8::StackTrace> stackTrace =
12913 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
12914 CHECK_EQ(5, stackTrace->GetFrameCount());
12915 v8::Handle<v8::String> url = v8_str("eval_url");
12916 for (int i = 0; i < 3; i++) {
12917 v8::Handle<v8::String> name =
12918 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
12919 CHECK(!name.IsEmpty());
12920 CHECK_EQ(url, name);
12921 }
12922 return v8::Undefined();
12923}
12924
12925
12926TEST(SourceURLInStackTrace) {
12927 v8::HandleScope scope;
12928 Local<ObjectTemplate> templ = ObjectTemplate::New();
12929 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
12930 v8::FunctionTemplate::New(AnalyzeStackOfEvalWithSourceURL));
12931 LocalContext context(0, templ);
12932
12933 const char *source =
12934 "function outer() {\n"
12935 "function bar() {\n"
12936 " AnalyzeStackOfEvalWithSourceURL();\n"
12937 "}\n"
12938 "function foo() {\n"
12939 "\n"
12940 " bar();\n"
12941 "}\n"
12942 "foo();\n"
12943 "}\n"
12944 "eval('(' + outer +')()//@ sourceURL=eval_url');";
12945 CHECK(CompileRun(source)->IsUndefined());
12946}
12947
12948
Steve Block3ce2e202009-11-05 08:53:23 +000012949// Test that idle notification can be handled and eventually returns true.
Steve Blocka7e24c12009-10-30 11:49:00 +000012950THREADED_TEST(IdleNotification) {
Steve Block3ce2e202009-11-05 08:53:23 +000012951 bool rv = false;
12952 for (int i = 0; i < 100; i++) {
12953 rv = v8::V8::IdleNotification();
12954 if (rv)
12955 break;
12956 }
12957 CHECK(rv == true);
Steve Blocka7e24c12009-10-30 11:49:00 +000012958}
12959
12960
12961static uint32_t* stack_limit;
12962
12963static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
Steve Block44f0eee2011-05-26 01:26:41 +010012964 stack_limit = reinterpret_cast<uint32_t*>(
12965 i::Isolate::Current()->stack_guard()->real_climit());
Steve Blocka7e24c12009-10-30 11:49:00 +000012966 return v8::Undefined();
12967}
12968
12969
12970// Uses the address of a local variable to determine the stack top now.
12971// Given a size, returns an address that is that far from the current
12972// top of stack.
12973static uint32_t* ComputeStackLimit(uint32_t size) {
12974 uint32_t* answer = &size - (size / sizeof(size));
12975 // If the size is very large and the stack is very near the bottom of
12976 // memory then the calculation above may wrap around and give an address
12977 // that is above the (downwards-growing) stack. In that case we return
12978 // a very low address.
12979 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
12980 return answer;
12981}
12982
12983
12984TEST(SetResourceConstraints) {
12985 static const int K = 1024;
12986 uint32_t* set_limit = ComputeStackLimit(128 * K);
12987
12988 // Set stack limit.
12989 v8::ResourceConstraints constraints;
12990 constraints.set_stack_limit(set_limit);
12991 CHECK(v8::SetResourceConstraints(&constraints));
12992
12993 // Execute a script.
12994 v8::HandleScope scope;
12995 LocalContext env;
12996 Local<v8::FunctionTemplate> fun_templ =
12997 v8::FunctionTemplate::New(GetStackLimitCallback);
12998 Local<Function> fun = fun_templ->GetFunction();
12999 env->Global()->Set(v8_str("get_stack_limit"), fun);
13000 CompileRun("get_stack_limit();");
13001
13002 CHECK(stack_limit == set_limit);
13003}
13004
13005
13006TEST(SetResourceConstraintsInThread) {
13007 uint32_t* set_limit;
13008 {
13009 v8::Locker locker;
13010 static const int K = 1024;
13011 set_limit = ComputeStackLimit(128 * K);
13012
13013 // Set stack limit.
13014 v8::ResourceConstraints constraints;
13015 constraints.set_stack_limit(set_limit);
13016 CHECK(v8::SetResourceConstraints(&constraints));
13017
13018 // Execute a script.
13019 v8::HandleScope scope;
13020 LocalContext env;
13021 Local<v8::FunctionTemplate> fun_templ =
13022 v8::FunctionTemplate::New(GetStackLimitCallback);
13023 Local<Function> fun = fun_templ->GetFunction();
13024 env->Global()->Set(v8_str("get_stack_limit"), fun);
13025 CompileRun("get_stack_limit();");
13026
13027 CHECK(stack_limit == set_limit);
13028 }
13029 {
13030 v8::Locker locker;
13031 CHECK(stack_limit == set_limit);
13032 }
13033}
Steve Block3ce2e202009-11-05 08:53:23 +000013034
13035
13036THREADED_TEST(GetHeapStatistics) {
13037 v8::HandleScope scope;
13038 LocalContext c1;
13039 v8::HeapStatistics heap_statistics;
Steve Blockd0582a62009-12-15 09:54:21 +000013040 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
13041 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
Steve Block3ce2e202009-11-05 08:53:23 +000013042 v8::V8::GetHeapStatistics(&heap_statistics);
Steve Blockd0582a62009-12-15 09:54:21 +000013043 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
13044 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
13045}
13046
13047
13048static double DoubleFromBits(uint64_t value) {
13049 double target;
Steve Blockd0582a62009-12-15 09:54:21 +000013050 memcpy(&target, &value, sizeof(target));
Steve Blockd0582a62009-12-15 09:54:21 +000013051 return target;
13052}
13053
13054
13055static uint64_t DoubleToBits(double value) {
13056 uint64_t target;
Steve Blockd0582a62009-12-15 09:54:21 +000013057 memcpy(&target, &value, sizeof(target));
Steve Blockd0582a62009-12-15 09:54:21 +000013058 return target;
13059}
13060
13061
13062static double DoubleToDateTime(double input) {
13063 double date_limit = 864e13;
13064 if (IsNaN(input) || input < -date_limit || input > date_limit) {
13065 return i::OS::nan_value();
13066 }
13067 return (input < 0) ? -(floor(-input)) : floor(input);
13068}
13069
13070// We don't have a consistent way to write 64-bit constants syntactically, so we
13071// split them into two 32-bit constants and combine them programmatically.
13072static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
13073 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
13074}
13075
13076
13077THREADED_TEST(QuietSignalingNaNs) {
13078 v8::HandleScope scope;
13079 LocalContext context;
13080 v8::TryCatch try_catch;
13081
13082 // Special double values.
13083 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
13084 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
13085 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
13086 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
13087 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
13088 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
13089 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
13090
13091 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
13092 // on either side of the epoch.
13093 double date_limit = 864e13;
13094
13095 double test_values[] = {
13096 snan,
13097 qnan,
13098 infinity,
13099 max_normal,
13100 date_limit + 1,
13101 date_limit,
13102 min_normal,
13103 max_denormal,
13104 min_denormal,
13105 0,
13106 -0,
13107 -min_denormal,
13108 -max_denormal,
13109 -min_normal,
13110 -date_limit,
13111 -date_limit - 1,
13112 -max_normal,
13113 -infinity,
13114 -qnan,
13115 -snan
13116 };
13117 int num_test_values = 20;
13118
13119 for (int i = 0; i < num_test_values; i++) {
13120 double test_value = test_values[i];
13121
13122 // Check that Number::New preserves non-NaNs and quiets SNaNs.
13123 v8::Handle<v8::Value> number = v8::Number::New(test_value);
13124 double stored_number = number->NumberValue();
13125 if (!IsNaN(test_value)) {
13126 CHECK_EQ(test_value, stored_number);
13127 } else {
13128 uint64_t stored_bits = DoubleToBits(stored_number);
13129 // Check if quiet nan (bits 51..62 all set).
13130 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
13131 }
13132
13133 // Check that Date::New preserves non-NaNs in the date range and
13134 // quiets SNaNs.
13135 v8::Handle<v8::Value> date = v8::Date::New(test_value);
13136 double expected_stored_date = DoubleToDateTime(test_value);
13137 double stored_date = date->NumberValue();
13138 if (!IsNaN(expected_stored_date)) {
13139 CHECK_EQ(expected_stored_date, stored_date);
13140 } else {
13141 uint64_t stored_bits = DoubleToBits(stored_date);
13142 // Check if quiet nan (bits 51..62 all set).
13143 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
13144 }
13145 }
13146}
13147
13148
13149static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
13150 v8::HandleScope scope;
13151 v8::TryCatch tc;
13152 v8::Handle<v8::String> str = args[0]->ToString();
13153 if (tc.HasCaught())
13154 return tc.ReThrow();
13155 return v8::Undefined();
13156}
13157
13158
13159// Test that an exception can be propagated down through a spaghetti
13160// stack using ReThrow.
13161THREADED_TEST(SpaghettiStackReThrow) {
13162 v8::HandleScope scope;
13163 LocalContext context;
13164 context->Global()->Set(
13165 v8::String::New("s"),
13166 v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
13167 v8::TryCatch try_catch;
13168 CompileRun(
13169 "var i = 0;"
13170 "var o = {"
13171 " toString: function () {"
13172 " if (i == 10) {"
13173 " throw 'Hey!';"
13174 " } else {"
13175 " i++;"
13176 " return s(o);"
13177 " }"
13178 " }"
13179 "};"
13180 "s(o);");
13181 CHECK(try_catch.HasCaught());
13182 v8::String::Utf8Value value(try_catch.Exception());
13183 CHECK_EQ(0, strcmp(*value, "Hey!"));
13184}
13185
13186
Steve Blockd0582a62009-12-15 09:54:21 +000013187TEST(Regress528) {
13188 v8::V8::Initialize();
13189
13190 v8::HandleScope scope;
13191 v8::Persistent<Context> context;
13192 v8::Persistent<Context> other_context;
13193 int gc_count;
13194
13195 // Create a context used to keep the code from aging in the compilation
13196 // cache.
13197 other_context = Context::New();
13198
13199 // Context-dependent context data creates reference from the compilation
13200 // cache to the global object.
13201 const char* source_simple = "1";
13202 context = Context::New();
13203 {
13204 v8::HandleScope scope;
13205
13206 context->Enter();
13207 Local<v8::String> obj = v8::String::New("");
13208 context->SetData(obj);
13209 CompileRun(source_simple);
13210 context->Exit();
13211 }
13212 context.Dispose();
13213 for (gc_count = 1; gc_count < 10; gc_count++) {
13214 other_context->Enter();
13215 CompileRun(source_simple);
13216 other_context->Exit();
Steve Block44f0eee2011-05-26 01:26:41 +010013217 HEAP->CollectAllGarbage(false);
Steve Blockd0582a62009-12-15 09:54:21 +000013218 if (GetGlobalObjectsCount() == 1) break;
13219 }
13220 CHECK_GE(2, gc_count);
13221 CHECK_EQ(1, GetGlobalObjectsCount());
13222
13223 // Eval in a function creates reference from the compilation cache to the
13224 // global object.
13225 const char* source_eval = "function f(){eval('1')}; f()";
13226 context = Context::New();
13227 {
13228 v8::HandleScope scope;
13229
13230 context->Enter();
13231 CompileRun(source_eval);
13232 context->Exit();
13233 }
13234 context.Dispose();
13235 for (gc_count = 1; gc_count < 10; gc_count++) {
13236 other_context->Enter();
13237 CompileRun(source_eval);
13238 other_context->Exit();
Steve Block44f0eee2011-05-26 01:26:41 +010013239 HEAP->CollectAllGarbage(false);
Steve Blockd0582a62009-12-15 09:54:21 +000013240 if (GetGlobalObjectsCount() == 1) break;
13241 }
13242 CHECK_GE(2, gc_count);
13243 CHECK_EQ(1, GetGlobalObjectsCount());
13244
13245 // Looking up the line number for an exception creates reference from the
13246 // compilation cache to the global object.
13247 const char* source_exception = "function f(){throw 1;} f()";
13248 context = Context::New();
13249 {
13250 v8::HandleScope scope;
13251
13252 context->Enter();
13253 v8::TryCatch try_catch;
13254 CompileRun(source_exception);
13255 CHECK(try_catch.HasCaught());
13256 v8::Handle<v8::Message> message = try_catch.Message();
13257 CHECK(!message.IsEmpty());
13258 CHECK_EQ(1, message->GetLineNumber());
13259 context->Exit();
13260 }
13261 context.Dispose();
13262 for (gc_count = 1; gc_count < 10; gc_count++) {
13263 other_context->Enter();
13264 CompileRun(source_exception);
13265 other_context->Exit();
Steve Block44f0eee2011-05-26 01:26:41 +010013266 HEAP->CollectAllGarbage(false);
Steve Blockd0582a62009-12-15 09:54:21 +000013267 if (GetGlobalObjectsCount() == 1) break;
13268 }
13269 CHECK_GE(2, gc_count);
13270 CHECK_EQ(1, GetGlobalObjectsCount());
13271
13272 other_context.Dispose();
Steve Block3ce2e202009-11-05 08:53:23 +000013273}
Andrei Popescu402d9372010-02-26 13:31:12 +000013274
13275
13276THREADED_TEST(ScriptOrigin) {
13277 v8::HandleScope scope;
13278 LocalContext env;
13279 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
13280 v8::Handle<v8::String> script = v8::String::New(
13281 "function f() {}\n\nfunction g() {}");
13282 v8::Script::Compile(script, &origin)->Run();
13283 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
13284 env->Global()->Get(v8::String::New("f")));
13285 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
13286 env->Global()->Get(v8::String::New("g")));
13287
13288 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
13289 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
13290 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
13291
13292 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
13293 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
13294 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
13295}
13296
13297
13298THREADED_TEST(ScriptLineNumber) {
13299 v8::HandleScope scope;
13300 LocalContext env;
13301 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
13302 v8::Handle<v8::String> script = v8::String::New(
13303 "function f() {}\n\nfunction g() {}");
13304 v8::Script::Compile(script, &origin)->Run();
13305 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
13306 env->Global()->Get(v8::String::New("f")));
13307 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
13308 env->Global()->Get(v8::String::New("g")));
13309 CHECK_EQ(0, f->GetScriptLineNumber());
13310 CHECK_EQ(2, g->GetScriptLineNumber());
13311}
13312
13313
13314static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
13315 const AccessorInfo& info) {
13316 return v8_num(42);
13317}
13318
13319
13320static void SetterWhichSetsYOnThisTo23(Local<String> name,
13321 Local<Value> value,
13322 const AccessorInfo& info) {
13323 info.This()->Set(v8_str("y"), v8_num(23));
13324}
13325
13326
Steve Block6ded16b2010-05-10 14:33:55 +010013327TEST(SetterOnConstructorPrototype) {
Andrei Popescu402d9372010-02-26 13:31:12 +000013328 v8::HandleScope scope;
13329 Local<ObjectTemplate> templ = ObjectTemplate::New();
13330 templ->SetAccessor(v8_str("x"),
13331 GetterWhichReturns42,
13332 SetterWhichSetsYOnThisTo23);
13333 LocalContext context;
13334 context->Global()->Set(v8_str("P"), templ->NewInstance());
13335 CompileRun("function C1() {"
13336 " this.x = 23;"
13337 "};"
13338 "C1.prototype = P;"
13339 "function C2() {"
13340 " this.x = 23"
13341 "};"
13342 "C2.prototype = { };"
13343 "C2.prototype.__proto__ = P;");
13344
13345 v8::Local<v8::Script> script;
13346 script = v8::Script::Compile(v8_str("new C1();"));
13347 for (int i = 0; i < 10; i++) {
13348 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13349 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
13350 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
13351 }
13352
13353 script = v8::Script::Compile(v8_str("new C2();"));
13354 for (int i = 0; i < 10; i++) {
13355 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
13356 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
13357 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
13358 }
13359}
13360
13361
13362static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
13363 Local<String> name, const AccessorInfo& info) {
13364 return v8_num(42);
13365}
13366
13367
13368static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
13369 Local<String> name, Local<Value> value, const AccessorInfo& info) {
13370 if (name->Equals(v8_str("x"))) {
13371 info.This()->Set(v8_str("y"), v8_num(23));
13372 }
13373 return v8::Handle<Value>();
13374}
13375
13376
13377THREADED_TEST(InterceptorOnConstructorPrototype) {
13378 v8::HandleScope scope;
13379 Local<ObjectTemplate> templ = ObjectTemplate::New();
13380 templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
13381 NamedPropertySetterWhichSetsYOnThisTo23);
13382 LocalContext context;
13383 context->Global()->Set(v8_str("P"), templ->NewInstance());
13384 CompileRun("function C1() {"
13385 " this.x = 23;"
13386 "};"
13387 "C1.prototype = P;"
13388 "function C2() {"
13389 " this.x = 23"
13390 "};"
13391 "C2.prototype = { };"
13392 "C2.prototype.__proto__ = P;");
13393
13394 v8::Local<v8::Script> script;
13395 script = v8::Script::Compile(v8_str("new C1();"));
13396 for (int i = 0; i < 10; i++) {
13397 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13398 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
13399 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
13400 }
13401
13402 script = v8::Script::Compile(v8_str("new C2();"));
13403 for (int i = 0; i < 10; i++) {
13404 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
13405 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
13406 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
13407 }
13408}
Steve Block6ded16b2010-05-10 14:33:55 +010013409
13410
13411TEST(Bug618) {
13412 const char* source = "function C1() {"
13413 " this.x = 23;"
13414 "};"
13415 "C1.prototype = P;";
13416
13417 v8::HandleScope scope;
13418 LocalContext context;
13419 v8::Local<v8::Script> script;
13420
13421 // Use a simple object as prototype.
13422 v8::Local<v8::Object> prototype = v8::Object::New();
13423 prototype->Set(v8_str("y"), v8_num(42));
13424 context->Global()->Set(v8_str("P"), prototype);
13425
13426 // This compile will add the code to the compilation cache.
13427 CompileRun(source);
13428
13429 script = v8::Script::Compile(v8_str("new C1();"));
Kristian Monsen0d5e1162010-09-30 15:31:59 +010013430 // Allow enough iterations for the inobject slack tracking logic
13431 // to finalize instance size and install the fast construct stub.
13432 for (int i = 0; i < 256; i++) {
Steve Block6ded16b2010-05-10 14:33:55 +010013433 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13434 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
13435 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
13436 }
13437
13438 // Use an API object with accessors as prototype.
13439 Local<ObjectTemplate> templ = ObjectTemplate::New();
13440 templ->SetAccessor(v8_str("x"),
13441 GetterWhichReturns42,
13442 SetterWhichSetsYOnThisTo23);
13443 context->Global()->Set(v8_str("P"), templ->NewInstance());
13444
13445 // This compile will get the code from the compilation cache.
13446 CompileRun(source);
13447
13448 script = v8::Script::Compile(v8_str("new C1();"));
13449 for (int i = 0; i < 10; i++) {
13450 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13451 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
13452 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
13453 }
13454}
13455
13456int prologue_call_count = 0;
13457int epilogue_call_count = 0;
13458int prologue_call_count_second = 0;
13459int epilogue_call_count_second = 0;
13460
13461void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
13462 ++prologue_call_count;
13463}
13464
13465void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
13466 ++epilogue_call_count;
13467}
13468
13469void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
13470 ++prologue_call_count_second;
13471}
13472
13473void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
13474 ++epilogue_call_count_second;
13475}
13476
13477TEST(GCCallbacks) {
13478 LocalContext context;
13479
13480 v8::V8::AddGCPrologueCallback(PrologueCallback);
13481 v8::V8::AddGCEpilogueCallback(EpilogueCallback);
13482 CHECK_EQ(0, prologue_call_count);
13483 CHECK_EQ(0, epilogue_call_count);
Steve Block44f0eee2011-05-26 01:26:41 +010013484 HEAP->CollectAllGarbage(false);
Steve Block6ded16b2010-05-10 14:33:55 +010013485 CHECK_EQ(1, prologue_call_count);
13486 CHECK_EQ(1, epilogue_call_count);
13487 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
13488 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
Steve Block44f0eee2011-05-26 01:26:41 +010013489 HEAP->CollectAllGarbage(false);
Steve Block6ded16b2010-05-10 14:33:55 +010013490 CHECK_EQ(2, prologue_call_count);
13491 CHECK_EQ(2, epilogue_call_count);
13492 CHECK_EQ(1, prologue_call_count_second);
13493 CHECK_EQ(1, epilogue_call_count_second);
13494 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
13495 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
Steve Block44f0eee2011-05-26 01:26:41 +010013496 HEAP->CollectAllGarbage(false);
Steve Block6ded16b2010-05-10 14:33:55 +010013497 CHECK_EQ(2, prologue_call_count);
13498 CHECK_EQ(2, epilogue_call_count);
13499 CHECK_EQ(2, prologue_call_count_second);
13500 CHECK_EQ(2, epilogue_call_count_second);
13501 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
13502 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
Steve Block44f0eee2011-05-26 01:26:41 +010013503 HEAP->CollectAllGarbage(false);
Steve Block6ded16b2010-05-10 14:33:55 +010013504 CHECK_EQ(2, prologue_call_count);
13505 CHECK_EQ(2, epilogue_call_count);
13506 CHECK_EQ(2, prologue_call_count_second);
13507 CHECK_EQ(2, epilogue_call_count_second);
13508}
Kristian Monsen25f61362010-05-21 11:50:48 +010013509
13510
13511THREADED_TEST(AddToJSFunctionResultCache) {
13512 i::FLAG_allow_natives_syntax = true;
13513 v8::HandleScope scope;
13514
13515 LocalContext context;
13516
13517 const char* code =
13518 "(function() {"
13519 " var key0 = 'a';"
13520 " var key1 = 'b';"
13521 " var r0 = %_GetFromCache(0, key0);"
13522 " var r1 = %_GetFromCache(0, key1);"
13523 " var r0_ = %_GetFromCache(0, key0);"
13524 " if (r0 !== r0_)"
13525 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
13526 " var r1_ = %_GetFromCache(0, key1);"
13527 " if (r1 !== r1_)"
13528 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
13529 " return 'PASSED';"
13530 "})()";
Steve Block44f0eee2011-05-26 01:26:41 +010013531 HEAP->ClearJSFunctionResultCaches();
Kristian Monsen25f61362010-05-21 11:50:48 +010013532 ExpectString(code, "PASSED");
13533}
13534
13535
13536static const int k0CacheSize = 16;
13537
13538THREADED_TEST(FillJSFunctionResultCache) {
13539 i::FLAG_allow_natives_syntax = true;
13540 v8::HandleScope scope;
13541
13542 LocalContext context;
13543
13544 const char* code =
13545 "(function() {"
13546 " var k = 'a';"
13547 " var r = %_GetFromCache(0, k);"
13548 " for (var i = 0; i < 16; i++) {"
13549 " %_GetFromCache(0, 'a' + i);"
13550 " };"
13551 " if (r === %_GetFromCache(0, k))"
13552 " return 'FAILED: k0CacheSize is too small';"
13553 " return 'PASSED';"
13554 "})()";
Steve Block44f0eee2011-05-26 01:26:41 +010013555 HEAP->ClearJSFunctionResultCaches();
Kristian Monsen25f61362010-05-21 11:50:48 +010013556 ExpectString(code, "PASSED");
13557}
13558
13559
13560THREADED_TEST(RoundRobinGetFromCache) {
13561 i::FLAG_allow_natives_syntax = true;
13562 v8::HandleScope scope;
13563
13564 LocalContext context;
13565
13566 const char* code =
13567 "(function() {"
13568 " var keys = [];"
13569 " for (var i = 0; i < 16; i++) keys.push(i);"
13570 " var values = [];"
13571 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
13572 " for (var i = 0; i < 16; i++) {"
13573 " var v = %_GetFromCache(0, keys[i]);"
13574 " if (v !== values[i])"
13575 " return 'Wrong value for ' + "
13576 " keys[i] + ': ' + v + ' vs. ' + values[i];"
13577 " };"
13578 " return 'PASSED';"
13579 "})()";
Steve Block44f0eee2011-05-26 01:26:41 +010013580 HEAP->ClearJSFunctionResultCaches();
Kristian Monsen25f61362010-05-21 11:50:48 +010013581 ExpectString(code, "PASSED");
13582}
13583
13584
13585THREADED_TEST(ReverseGetFromCache) {
13586 i::FLAG_allow_natives_syntax = true;
13587 v8::HandleScope scope;
13588
13589 LocalContext context;
13590
13591 const char* code =
13592 "(function() {"
13593 " var keys = [];"
13594 " for (var i = 0; i < 16; i++) keys.push(i);"
13595 " var values = [];"
13596 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
13597 " for (var i = 15; i >= 16; i--) {"
13598 " var v = %_GetFromCache(0, keys[i]);"
13599 " if (v !== values[i])"
13600 " return 'Wrong value for ' + "
13601 " keys[i] + ': ' + v + ' vs. ' + values[i];"
13602 " };"
13603 " return 'PASSED';"
13604 "})()";
Steve Block44f0eee2011-05-26 01:26:41 +010013605 HEAP->ClearJSFunctionResultCaches();
Kristian Monsen25f61362010-05-21 11:50:48 +010013606 ExpectString(code, "PASSED");
13607}
13608
13609
13610THREADED_TEST(TestEviction) {
13611 i::FLAG_allow_natives_syntax = true;
13612 v8::HandleScope scope;
13613
13614 LocalContext context;
13615
13616 const char* code =
13617 "(function() {"
13618 " for (var i = 0; i < 2*16; i++) {"
13619 " %_GetFromCache(0, 'a' + i);"
13620 " };"
13621 " return 'PASSED';"
13622 "})()";
Steve Block44f0eee2011-05-26 01:26:41 +010013623 HEAP->ClearJSFunctionResultCaches();
Kristian Monsen25f61362010-05-21 11:50:48 +010013624 ExpectString(code, "PASSED");
13625}
Steve Block8defd9f2010-07-08 12:39:36 +010013626
13627
13628THREADED_TEST(TwoByteStringInAsciiCons) {
13629 // See Chromium issue 47824.
13630 v8::HandleScope scope;
13631
13632 LocalContext context;
13633 const char* init_code =
13634 "var str1 = 'abelspendabel';"
13635 "var str2 = str1 + str1 + str1;"
13636 "str2;";
13637 Local<Value> result = CompileRun(init_code);
13638
13639 CHECK(result->IsString());
13640 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
13641 int length = string->length();
13642 CHECK(string->IsAsciiRepresentation());
13643
13644 FlattenString(string);
13645 i::Handle<i::String> flat_string = FlattenGetString(string);
13646
13647 CHECK(string->IsAsciiRepresentation());
13648 CHECK(flat_string->IsAsciiRepresentation());
13649
13650 // Create external resource.
13651 uint16_t* uc16_buffer = new uint16_t[length + 1];
13652
13653 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
13654 uc16_buffer[length] = 0;
13655
13656 TestResource resource(uc16_buffer);
13657
13658 flat_string->MakeExternal(&resource);
13659
13660 CHECK(flat_string->IsTwoByteRepresentation());
13661
13662 // At this point, we should have a Cons string which is flat and ASCII,
13663 // with a first half that is a two-byte string (although it only contains
13664 // ASCII characters). This is a valid sequence of steps, and it can happen
13665 // in real pages.
13666
13667 CHECK(string->IsAsciiRepresentation());
13668 i::ConsString* cons = i::ConsString::cast(*string);
13669 CHECK_EQ(0, cons->second()->length());
13670 CHECK(cons->first()->IsTwoByteRepresentation());
13671
13672 // Check that some string operations work.
13673
13674 // Atom RegExp.
13675 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
13676 CHECK_EQ(6, reresult->Int32Value());
13677
13678 // Nonatom RegExp.
13679 reresult = CompileRun("str2.match(/abe./g).length;");
13680 CHECK_EQ(6, reresult->Int32Value());
13681
13682 reresult = CompileRun("str2.search(/bel/g);");
13683 CHECK_EQ(1, reresult->Int32Value());
13684
13685 reresult = CompileRun("str2.search(/be./g);");
13686 CHECK_EQ(1, reresult->Int32Value());
13687
13688 ExpectTrue("/bel/g.test(str2);");
13689
13690 ExpectTrue("/be./g.test(str2);");
13691
13692 reresult = CompileRun("/bel/g.exec(str2);");
13693 CHECK(!reresult->IsNull());
13694
13695 reresult = CompileRun("/be./g.exec(str2);");
13696 CHECK(!reresult->IsNull());
13697
13698 ExpectString("str2.substring(2, 10);", "elspenda");
13699
13700 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
13701
13702 ExpectString("str2.charAt(2);", "e");
13703
13704 reresult = CompileRun("str2.charCodeAt(2);");
13705 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
13706}
Iain Merrick75681382010-08-19 15:07:18 +010013707
13708
13709// Failed access check callback that performs a GC on each invocation.
13710void FailedAccessCheckCallbackGC(Local<v8::Object> target,
13711 v8::AccessType type,
13712 Local<v8::Value> data) {
Steve Block44f0eee2011-05-26 01:26:41 +010013713 HEAP->CollectAllGarbage(true);
Iain Merrick75681382010-08-19 15:07:18 +010013714}
13715
13716
13717TEST(GCInFailedAccessCheckCallback) {
13718 // Install a failed access check callback that performs a GC on each
13719 // invocation. Then force the callback to be called from va
13720
13721 v8::V8::Initialize();
13722 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
13723
13724 v8::HandleScope scope;
13725
13726 // Create an ObjectTemplate for global objects and install access
13727 // check callbacks that will block access.
13728 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
13729 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
13730 IndexedGetAccessBlocker,
13731 v8::Handle<v8::Value>(),
13732 false);
13733
13734 // Create a context and set an x property on it's global object.
13735 LocalContext context0(NULL, global_template);
13736 context0->Global()->Set(v8_str("x"), v8_num(42));
13737 v8::Handle<v8::Object> global0 = context0->Global();
13738
13739 // Create a context with a different security token so that the
13740 // failed access check callback will be called on each access.
13741 LocalContext context1(NULL, global_template);
13742 context1->Global()->Set(v8_str("other"), global0);
13743
13744 // Get property with failed access check.
13745 ExpectUndefined("other.x");
13746
13747 // Get element with failed access check.
13748 ExpectUndefined("other[0]");
13749
13750 // Set property with failed access check.
13751 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
13752 CHECK(result->IsObject());
13753
13754 // Set element with failed access check.
13755 result = CompileRun("other[0] = new Object()");
13756 CHECK(result->IsObject());
13757
13758 // Get property attribute with failed access check.
13759 ExpectFalse("\'x\' in other");
13760
13761 // Get property attribute for element with failed access check.
13762 ExpectFalse("0 in other");
13763
13764 // Delete property.
13765 ExpectFalse("delete other.x");
13766
13767 // Delete element.
13768 CHECK_EQ(false, global0->Delete(0));
13769
13770 // DefineAccessor.
13771 CHECK_EQ(false,
13772 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
13773
13774 // Define JavaScript accessor.
13775 ExpectUndefined("Object.prototype.__defineGetter__.call("
13776 " other, \'x\', function() { return 42; })");
13777
13778 // LookupAccessor.
13779 ExpectUndefined("Object.prototype.__lookupGetter__.call("
13780 " other, \'x\')");
13781
13782 // HasLocalElement.
13783 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
13784
13785 CHECK_EQ(false, global0->HasRealIndexedProperty(0));
13786 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
13787 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
13788
13789 // Reset the failed access check callback so it does not influence
13790 // the other tests.
13791 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
13792}
Kristian Monsen0d5e1162010-09-30 15:31:59 +010013793
Steve Block44f0eee2011-05-26 01:26:41 +010013794TEST(DefaultIsolateGetCurrent) {
13795 CHECK(v8::Isolate::GetCurrent() != NULL);
13796 v8::Isolate* isolate = v8::Isolate::GetCurrent();
13797 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
13798 printf("*** %s\n", "DefaultIsolateGetCurrent success");
13799}
13800
13801TEST(IsolateNewDispose) {
13802 v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
13803 v8::Isolate* isolate = v8::Isolate::New();
13804 CHECK(isolate != NULL);
13805 CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
13806 CHECK(current_isolate != isolate);
13807 CHECK(current_isolate == v8::Isolate::GetCurrent());
13808
13809 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13810 last_location = last_message = NULL;
13811 isolate->Dispose();
13812 CHECK_EQ(last_location, NULL);
13813 CHECK_EQ(last_message, NULL);
13814}
13815
13816TEST(IsolateEnterExitDefault) {
13817 v8::HandleScope scope;
13818 LocalContext context;
13819 v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
13820 CHECK(current_isolate != NULL); // Default isolate.
13821 ExpectString("'hello'", "hello");
13822 current_isolate->Enter();
13823 ExpectString("'still working'", "still working");
13824 current_isolate->Exit();
13825 ExpectString("'still working 2'", "still working 2");
13826 current_isolate->Exit();
13827 // Default isolate is always, well, 'default current'.
13828 CHECK_EQ(v8::Isolate::GetCurrent(), current_isolate);
13829 // Still working since default isolate is auto-entering any thread
13830 // that has no isolate and attempts to execute V8 APIs.
13831 ExpectString("'still working 3'", "still working 3");
13832}
13833
13834TEST(DisposeDefaultIsolate) {
13835 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13836
13837 // Run some V8 code to trigger default isolate to become 'current'.
13838 v8::HandleScope scope;
13839 LocalContext context;
13840 ExpectString("'run some V8'", "run some V8");
13841
13842 v8::Isolate* isolate = v8::Isolate::GetCurrent();
13843 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
13844 last_location = last_message = NULL;
13845 isolate->Dispose();
13846 // It is not possible to dispose default isolate via Isolate API.
13847 CHECK_NE(last_location, NULL);
13848 CHECK_NE(last_message, NULL);
13849}
13850
13851TEST(RunDefaultAndAnotherIsolate) {
13852 v8::HandleScope scope;
13853 LocalContext context;
13854
13855 // Enter new isolate.
13856 v8::Isolate* isolate = v8::Isolate::New();
13857 CHECK(isolate);
13858 isolate->Enter();
13859 { // Need this block because subsequent Exit() will deallocate Heap,
13860 // so we need all scope objects to be deconstructed when it happens.
13861 v8::HandleScope scope_new;
13862 LocalContext context_new;
13863
13864 // Run something in new isolate.
13865 CompileRun("var foo = 153;");
13866 ExpectTrue("function f() { return foo == 153; }; f()");
13867 }
13868 isolate->Exit();
13869
13870 // This runs automatically in default isolate.
13871 // Variables in another isolate should be not available.
13872 ExpectTrue("function f() {"
13873 " try {"
13874 " foo;"
13875 " return false;"
13876 " } catch(e) {"
13877 " return true;"
13878 " }"
13879 "};"
13880 "var bar = 371;"
13881 "f()");
13882
13883 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13884 last_location = last_message = NULL;
13885 isolate->Dispose();
13886 CHECK_EQ(last_location, NULL);
13887 CHECK_EQ(last_message, NULL);
13888
13889 // Check that default isolate still runs.
13890 ExpectTrue("function f() { return bar == 371; }; f()");
13891}
13892
13893TEST(DisposeIsolateWhenInUse) {
13894 v8::Isolate* isolate = v8::Isolate::New();
13895 CHECK(isolate);
13896 isolate->Enter();
13897 v8::HandleScope scope;
13898 LocalContext context;
13899 // Run something in this isolate.
13900 ExpectTrue("true");
13901 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13902 last_location = last_message = NULL;
13903 // Still entered, should fail.
13904 isolate->Dispose();
13905 CHECK_NE(last_location, NULL);
13906 CHECK_NE(last_message, NULL);
13907}
13908
13909TEST(RunTwoIsolatesOnSingleThread) {
13910 // Run isolate 1.
13911 v8::Isolate* isolate1 = v8::Isolate::New();
13912 isolate1->Enter();
13913 v8::Persistent<v8::Context> context1 = v8::Context::New();
13914
13915 {
13916 v8::Context::Scope cscope(context1);
13917 v8::HandleScope scope;
13918 // Run something in new isolate.
13919 CompileRun("var foo = 'isolate 1';");
13920 ExpectString("function f() { return foo; }; f()", "isolate 1");
13921 }
13922
13923 // Run isolate 2.
13924 v8::Isolate* isolate2 = v8::Isolate::New();
13925 v8::Persistent<v8::Context> context2;
13926
13927 {
13928 v8::Isolate::Scope iscope(isolate2);
13929 context2 = v8::Context::New();
13930 v8::Context::Scope cscope(context2);
13931 v8::HandleScope scope;
13932
13933 // Run something in new isolate.
13934 CompileRun("var foo = 'isolate 2';");
13935 ExpectString("function f() { return foo; }; f()", "isolate 2");
13936 }
13937
13938 {
13939 v8::Context::Scope cscope(context1);
13940 v8::HandleScope scope;
13941 // Now again in isolate 1
13942 ExpectString("function f() { return foo; }; f()", "isolate 1");
13943 }
13944
13945 isolate1->Exit();
13946
13947 // Run some stuff in default isolate.
13948 v8::Persistent<v8::Context> context_default = v8::Context::New();
13949
13950 {
13951 v8::Context::Scope cscope(context_default);
13952 v8::HandleScope scope;
13953 // Variables in other isolates should be not available, verify there
13954 // is an exception.
13955 ExpectTrue("function f() {"
13956 " try {"
13957 " foo;"
13958 " return false;"
13959 " } catch(e) {"
13960 " return true;"
13961 " }"
13962 "};"
13963 "var isDefaultIsolate = true;"
13964 "f()");
13965 }
13966
13967 isolate1->Enter();
13968
13969 {
13970 v8::Isolate::Scope iscope(isolate2);
13971 v8::Context::Scope cscope(context2);
13972 v8::HandleScope scope;
13973 ExpectString("function f() { return foo; }; f()", "isolate 2");
13974 }
13975
13976 {
13977 v8::Context::Scope cscope(context1);
13978 v8::HandleScope scope;
13979 ExpectString("function f() { return foo; }; f()", "isolate 1");
13980 }
13981
13982 {
13983 v8::Isolate::Scope iscope(isolate2);
13984 context2.Dispose();
13985 }
13986
13987 context1.Dispose();
13988 isolate1->Exit();
13989
13990 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13991 last_location = last_message = NULL;
13992
13993 isolate1->Dispose();
13994 CHECK_EQ(last_location, NULL);
13995 CHECK_EQ(last_message, NULL);
13996
13997 isolate2->Dispose();
13998 CHECK_EQ(last_location, NULL);
13999 CHECK_EQ(last_message, NULL);
14000
14001 // Check that default isolate still runs.
14002 {
14003 v8::Context::Scope cscope(context_default);
14004 v8::HandleScope scope;
14005 ExpectTrue("function f() { return isDefaultIsolate; }; f()");
14006 }
14007}
14008
14009static int CalcFibonacci(v8::Isolate* isolate, int limit) {
14010 v8::Isolate::Scope isolate_scope(isolate);
14011 v8::HandleScope scope;
14012 LocalContext context;
14013 i::ScopedVector<char> code(1024);
14014 i::OS::SNPrintF(code, "function fib(n) {"
14015 " if (n <= 2) return 1;"
14016 " return fib(n-1) + fib(n-2);"
14017 "}"
14018 "fib(%d)", limit);
14019 Local<Value> value = CompileRun(code.start());
14020 CHECK(value->IsNumber());
14021 return static_cast<int>(value->NumberValue());
14022}
14023
14024class IsolateThread : public v8::internal::Thread {
14025 public:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014026 IsolateThread(v8::Isolate* isolate, int fib_limit)
14027 : Thread("IsolateThread"),
Steve Block44f0eee2011-05-26 01:26:41 +010014028 isolate_(isolate),
14029 fib_limit_(fib_limit),
14030 result_(0) { }
14031
14032 void Run() {
14033 result_ = CalcFibonacci(isolate_, fib_limit_);
14034 }
14035
14036 int result() { return result_; }
14037
14038 private:
14039 v8::Isolate* isolate_;
14040 int fib_limit_;
14041 int result_;
14042};
14043
14044TEST(MultipleIsolatesOnIndividualThreads) {
14045 v8::Isolate* isolate1 = v8::Isolate::New();
14046 v8::Isolate* isolate2 = v8::Isolate::New();
14047
14048 IsolateThread thread1(isolate1, 21);
14049 IsolateThread thread2(isolate2, 12);
14050
14051 // Compute some fibonacci numbers on 3 threads in 3 isolates.
14052 thread1.Start();
14053 thread2.Start();
14054
14055 int result1 = CalcFibonacci(v8::Isolate::GetCurrent(), 21);
14056 int result2 = CalcFibonacci(v8::Isolate::GetCurrent(), 12);
14057
14058 thread1.Join();
14059 thread2.Join();
14060
14061 // Compare results. The actual fibonacci numbers for 12 and 21 are taken
14062 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
14063 CHECK_EQ(result1, 10946);
14064 CHECK_EQ(result2, 144);
14065 CHECK_EQ(result1, thread1.result());
14066 CHECK_EQ(result2, thread2.result());
14067
14068 isolate1->Dispose();
14069 isolate2->Dispose();
14070}
14071
Ben Murdoch257744e2011-11-30 15:57:28 +000014072TEST(IsolateDifferentContexts) {
14073 v8::Isolate* isolate = v8::Isolate::New();
14074 Persistent<v8::Context> context;
14075 {
14076 v8::Isolate::Scope isolate_scope(isolate);
14077 v8::HandleScope handle_scope;
14078 context = v8::Context::New();
14079 v8::Context::Scope context_scope(context);
14080 Local<Value> v = CompileRun("2");
14081 CHECK(v->IsNumber());
14082 CHECK_EQ(2, static_cast<int>(v->NumberValue()));
14083 }
14084 {
14085 v8::Isolate::Scope isolate_scope(isolate);
14086 v8::HandleScope handle_scope;
14087 context = v8::Context::New();
14088 v8::Context::Scope context_scope(context);
14089 Local<Value> v = CompileRun("22");
14090 CHECK(v->IsNumber());
14091 CHECK_EQ(22, static_cast<int>(v->NumberValue()));
14092 }
14093}
Steve Block44f0eee2011-05-26 01:26:41 +010014094
14095class InitDefaultIsolateThread : public v8::internal::Thread {
14096 public:
14097 enum TestCase {
14098 IgnoreOOM,
14099 SetResourceConstraints,
14100 SetFatalHandler,
14101 SetCounterFunction,
14102 SetCreateHistogramFunction,
14103 SetAddHistogramSampleFunction
14104 };
14105
14106 explicit InitDefaultIsolateThread(TestCase testCase)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014107 : Thread("InitDefaultIsolateThread"),
Steve Block44f0eee2011-05-26 01:26:41 +010014108 testCase_(testCase),
14109 result_(false) { }
14110
14111 void Run() {
14112 switch (testCase_) {
14113 case IgnoreOOM:
14114 v8::V8::IgnoreOutOfMemoryException();
14115 break;
14116
14117 case SetResourceConstraints: {
14118 static const int K = 1024;
14119 v8::ResourceConstraints constraints;
14120 constraints.set_max_young_space_size(256 * K);
14121 constraints.set_max_old_space_size(4 * K * K);
14122 v8::SetResourceConstraints(&constraints);
14123 break;
14124 }
14125
14126 case SetFatalHandler:
14127 v8::V8::SetFatalErrorHandler(NULL);
14128 break;
14129
14130 case SetCounterFunction:
14131 v8::V8::SetCounterFunction(NULL);
14132 break;
14133
14134 case SetCreateHistogramFunction:
14135 v8::V8::SetCreateHistogramFunction(NULL);
14136 break;
14137
14138 case SetAddHistogramSampleFunction:
14139 v8::V8::SetAddHistogramSampleFunction(NULL);
14140 break;
14141 }
14142 result_ = true;
14143 }
14144
14145 bool result() { return result_; }
14146
14147 private:
14148 TestCase testCase_;
14149 bool result_;
14150};
14151
14152
14153static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
14154 InitDefaultIsolateThread thread(testCase);
14155 thread.Start();
14156 thread.Join();
14157 CHECK_EQ(thread.result(), true);
14158}
14159
14160TEST(InitializeDefaultIsolateOnSecondaryThread1) {
14161 InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM);
14162}
14163
14164TEST(InitializeDefaultIsolateOnSecondaryThread2) {
14165 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
14166}
14167
14168TEST(InitializeDefaultIsolateOnSecondaryThread3) {
14169 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
14170}
14171
14172TEST(InitializeDefaultIsolateOnSecondaryThread4) {
14173 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
14174}
14175
14176TEST(InitializeDefaultIsolateOnSecondaryThread5) {
14177 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
14178}
14179
14180TEST(InitializeDefaultIsolateOnSecondaryThread6) {
14181 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
14182}
14183
Kristian Monsen0d5e1162010-09-30 15:31:59 +010014184
14185TEST(StringCheckMultipleContexts) {
14186 const char* code =
14187 "(function() { return \"a\".charAt(0); })()";
14188
14189 {
14190 // Run the code twice in the first context to initialize the call IC.
14191 v8::HandleScope scope;
14192 LocalContext context1;
14193 ExpectString(code, "a");
14194 ExpectString(code, "a");
14195 }
14196
14197 {
14198 // Change the String.prototype in the second context and check
14199 // that the right function gets called.
14200 v8::HandleScope scope;
14201 LocalContext context2;
14202 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
14203 ExpectString(code, "not a");
14204 }
14205}
14206
14207
14208TEST(NumberCheckMultipleContexts) {
14209 const char* code =
14210 "(function() { return (42).toString(); })()";
14211
14212 {
14213 // Run the code twice in the first context to initialize the call IC.
14214 v8::HandleScope scope;
14215 LocalContext context1;
14216 ExpectString(code, "42");
14217 ExpectString(code, "42");
14218 }
14219
14220 {
14221 // Change the Number.prototype in the second context and check
14222 // that the right function gets called.
14223 v8::HandleScope scope;
14224 LocalContext context2;
14225 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
14226 ExpectString(code, "not 42");
14227 }
14228}
14229
14230
14231TEST(BooleanCheckMultipleContexts) {
14232 const char* code =
14233 "(function() { return true.toString(); })()";
14234
14235 {
14236 // Run the code twice in the first context to initialize the call IC.
14237 v8::HandleScope scope;
14238 LocalContext context1;
14239 ExpectString(code, "true");
14240 ExpectString(code, "true");
14241 }
14242
14243 {
14244 // Change the Boolean.prototype in the second context and check
14245 // that the right function gets called.
14246 v8::HandleScope scope;
14247 LocalContext context2;
14248 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
14249 ExpectString(code, "");
14250 }
14251}
Ben Murdochf87a2032010-10-22 12:50:53 +010014252
14253
14254TEST(DontDeleteCellLoadIC) {
14255 const char* function_code =
14256 "function readCell() { while (true) { return cell; } }";
14257
14258 {
14259 // Run the code twice in the first context to initialize the load
14260 // IC for a don't delete cell.
14261 v8::HandleScope scope;
14262 LocalContext context1;
14263 CompileRun("var cell = \"first\";");
14264 ExpectBoolean("delete cell", false);
14265 CompileRun(function_code);
14266 ExpectString("readCell()", "first");
14267 ExpectString("readCell()", "first");
14268 }
14269
14270 {
14271 // Use a deletable cell in the second context.
14272 v8::HandleScope scope;
14273 LocalContext context2;
14274 CompileRun("cell = \"second\";");
14275 CompileRun(function_code);
14276 ExpectString("readCell()", "second");
14277 ExpectBoolean("delete cell", true);
14278 ExpectString("(function() {"
14279 " try {"
14280 " return readCell();"
14281 " } catch(e) {"
14282 " return e.toString();"
14283 " }"
14284 "})()",
14285 "ReferenceError: cell is not defined");
14286 CompileRun("cell = \"new_second\";");
Steve Block44f0eee2011-05-26 01:26:41 +010014287 HEAP->CollectAllGarbage(true);
Ben Murdochf87a2032010-10-22 12:50:53 +010014288 ExpectString("readCell()", "new_second");
14289 ExpectString("readCell()", "new_second");
14290 }
14291}
14292
14293
14294TEST(DontDeleteCellLoadICForceDelete) {
14295 const char* function_code =
14296 "function readCell() { while (true) { return cell; } }";
14297
14298 // Run the code twice to initialize the load IC for a don't delete
14299 // cell.
14300 v8::HandleScope scope;
14301 LocalContext context;
14302 CompileRun("var cell = \"value\";");
14303 ExpectBoolean("delete cell", false);
14304 CompileRun(function_code);
14305 ExpectString("readCell()", "value");
14306 ExpectString("readCell()", "value");
14307
14308 // Delete the cell using the API and check the inlined code works
14309 // correctly.
14310 CHECK(context->Global()->ForceDelete(v8_str("cell")));
14311 ExpectString("(function() {"
14312 " try {"
14313 " return readCell();"
14314 " } catch(e) {"
14315 " return e.toString();"
14316 " }"
14317 "})()",
14318 "ReferenceError: cell is not defined");
14319}
14320
14321
14322TEST(DontDeleteCellLoadICAPI) {
14323 const char* function_code =
14324 "function readCell() { while (true) { return cell; } }";
14325
14326 // Run the code twice to initialize the load IC for a don't delete
14327 // cell created using the API.
14328 v8::HandleScope scope;
14329 LocalContext context;
14330 context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
14331 ExpectBoolean("delete cell", false);
14332 CompileRun(function_code);
14333 ExpectString("readCell()", "value");
14334 ExpectString("readCell()", "value");
14335
14336 // Delete the cell using the API and check the inlined code works
14337 // correctly.
14338 CHECK(context->Global()->ForceDelete(v8_str("cell")));
14339 ExpectString("(function() {"
14340 " try {"
14341 " return readCell();"
14342 " } catch(e) {"
14343 " return e.toString();"
14344 " }"
14345 "})()",
14346 "ReferenceError: cell is not defined");
14347}
14348
14349
Ben Murdochf87a2032010-10-22 12:50:53 +010014350TEST(RegExp) {
14351 v8::HandleScope scope;
14352 LocalContext context;
14353
14354 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
14355 CHECK(re->IsRegExp());
14356 CHECK(re->GetSource()->Equals(v8_str("foo")));
14357 CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
14358
14359 re = v8::RegExp::New(v8_str("bar"),
14360 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
14361 v8::RegExp::kGlobal));
14362 CHECK(re->IsRegExp());
14363 CHECK(re->GetSource()->Equals(v8_str("bar")));
14364 CHECK_EQ(static_cast<int>(re->GetFlags()),
14365 v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal);
14366
14367 re = v8::RegExp::New(v8_str("baz"),
14368 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
14369 v8::RegExp::kMultiline));
14370 CHECK(re->IsRegExp());
14371 CHECK(re->GetSource()->Equals(v8_str("baz")));
14372 CHECK_EQ(static_cast<int>(re->GetFlags()),
14373 v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline);
14374
14375 re = CompileRun("/quux/").As<v8::RegExp>();
14376 CHECK(re->IsRegExp());
14377 CHECK(re->GetSource()->Equals(v8_str("quux")));
14378 CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
14379
14380 re = CompileRun("/quux/gm").As<v8::RegExp>();
14381 CHECK(re->IsRegExp());
14382 CHECK(re->GetSource()->Equals(v8_str("quux")));
14383 CHECK_EQ(static_cast<int>(re->GetFlags()),
14384 v8::RegExp::kGlobal | v8::RegExp::kMultiline);
14385
14386 // Override the RegExp constructor and check the API constructor
14387 // still works.
14388 CompileRun("RegExp = function() {}");
14389
14390 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
14391 CHECK(re->IsRegExp());
14392 CHECK(re->GetSource()->Equals(v8_str("foobar")));
14393 CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
14394
14395 re = v8::RegExp::New(v8_str("foobarbaz"),
14396 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
14397 v8::RegExp::kMultiline));
14398 CHECK(re->IsRegExp());
14399 CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
14400 CHECK_EQ(static_cast<int>(re->GetFlags()),
14401 v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline);
14402
14403 context->Global()->Set(v8_str("re"), re);
14404 ExpectTrue("re.test('FoobarbaZ')");
14405
Ben Murdoch257744e2011-11-30 15:57:28 +000014406 // RegExps are objects on which you can set properties.
14407 re->Set(v8_str("property"), v8::Integer::New(32));
14408 v8::Handle<v8::Value> value = CompileRun("re.property");
14409 ASSERT_EQ(32, value->Int32Value());
14410
Ben Murdochf87a2032010-10-22 12:50:53 +010014411 v8::TryCatch try_catch;
14412 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
14413 CHECK(re.IsEmpty());
14414 CHECK(try_catch.HasCaught());
14415 context->Global()->Set(v8_str("ex"), try_catch.Exception());
14416 ExpectTrue("ex instanceof SyntaxError");
14417}
14418
14419
Steve Block1e0659c2011-05-24 12:43:12 +010014420THREADED_TEST(Equals) {
14421 v8::HandleScope handleScope;
14422 LocalContext localContext;
14423
14424 v8::Handle<v8::Object> globalProxy = localContext->Global();
14425 v8::Handle<Value> global = globalProxy->GetPrototype();
14426
14427 CHECK(global->StrictEquals(global));
14428 CHECK(!global->StrictEquals(globalProxy));
14429 CHECK(!globalProxy->StrictEquals(global));
14430 CHECK(globalProxy->StrictEquals(globalProxy));
14431
14432 CHECK(global->Equals(global));
14433 CHECK(!global->Equals(globalProxy));
14434 CHECK(!globalProxy->Equals(global));
14435 CHECK(globalProxy->Equals(globalProxy));
14436}
14437
14438
Ben Murdochf87a2032010-10-22 12:50:53 +010014439static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
14440 const v8::AccessorInfo& info ) {
14441 return v8_str("42!");
14442}
14443
14444
14445static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo& info) {
14446 v8::Handle<v8::Array> result = v8::Array::New();
14447 result->Set(0, v8_str("universalAnswer"));
14448 return result;
14449}
14450
14451
14452TEST(NamedEnumeratorAndForIn) {
14453 v8::HandleScope handle_scope;
14454 LocalContext context;
14455 v8::Context::Scope context_scope(context.local());
14456
14457 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New();
14458 tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
14459 context->Global()->Set(v8_str("o"), tmpl->NewInstance());
14460 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
14461 "var result = []; for (var k in o) result.push(k); result"));
14462 CHECK_EQ(1, result->Length());
14463 CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
14464}
Steve Block1e0659c2011-05-24 12:43:12 +010014465
14466
14467TEST(DefinePropertyPostDetach) {
14468 v8::HandleScope scope;
14469 LocalContext context;
14470 v8::Handle<v8::Object> proxy = context->Global();
14471 v8::Handle<v8::Function> define_property =
14472 CompileRun("(function() {"
14473 " Object.defineProperty("
14474 " this,"
14475 " 1,"
14476 " { configurable: true, enumerable: true, value: 3 });"
14477 "})").As<Function>();
14478 context->DetachGlobal();
14479 define_property->Call(proxy, 0, NULL);
14480}
Ben Murdoch8b112d22011-06-08 16:22:53 +010014481
14482
14483static void InstallContextId(v8::Handle<Context> context, int id) {
14484 Context::Scope scope(context);
14485 CompileRun("Object.prototype").As<Object>()->
14486 Set(v8_str("context_id"), v8::Integer::New(id));
14487}
14488
14489
14490static void CheckContextId(v8::Handle<Object> object, int expected) {
14491 CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
14492}
14493
14494
14495THREADED_TEST(CreationContext) {
14496 HandleScope handle_scope;
14497 Persistent<Context> context1 = Context::New();
14498 InstallContextId(context1, 1);
14499 Persistent<Context> context2 = Context::New();
14500 InstallContextId(context2, 2);
14501 Persistent<Context> context3 = Context::New();
14502 InstallContextId(context3, 3);
14503
14504 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New();
14505
14506 Local<Object> object1;
14507 Local<Function> func1;
14508 {
14509 Context::Scope scope(context1);
14510 object1 = Object::New();
14511 func1 = tmpl->GetFunction();
14512 }
14513
14514 Local<Object> object2;
14515 Local<Function> func2;
14516 {
14517 Context::Scope scope(context2);
14518 object2 = Object::New();
14519 func2 = tmpl->GetFunction();
14520 }
14521
14522 Local<Object> instance1;
14523 Local<Object> instance2;
14524
14525 {
14526 Context::Scope scope(context3);
14527 instance1 = func1->NewInstance();
14528 instance2 = func2->NewInstance();
14529 }
14530
14531 CHECK(object1->CreationContext() == context1);
14532 CheckContextId(object1, 1);
14533 CHECK(func1->CreationContext() == context1);
14534 CheckContextId(func1, 1);
14535 CHECK(instance1->CreationContext() == context1);
14536 CheckContextId(instance1, 1);
14537 CHECK(object2->CreationContext() == context2);
14538 CheckContextId(object2, 2);
14539 CHECK(func2->CreationContext() == context2);
14540 CheckContextId(func2, 2);
14541 CHECK(instance2->CreationContext() == context2);
14542 CheckContextId(instance2, 2);
14543
14544 {
14545 Context::Scope scope(context1);
14546 CHECK(object1->CreationContext() == context1);
14547 CheckContextId(object1, 1);
14548 CHECK(func1->CreationContext() == context1);
14549 CheckContextId(func1, 1);
14550 CHECK(instance1->CreationContext() == context1);
14551 CheckContextId(instance1, 1);
14552 CHECK(object2->CreationContext() == context2);
14553 CheckContextId(object2, 2);
14554 CHECK(func2->CreationContext() == context2);
14555 CheckContextId(func2, 2);
14556 CHECK(instance2->CreationContext() == context2);
14557 CheckContextId(instance2, 2);
14558 }
14559
14560 {
14561 Context::Scope scope(context2);
14562 CHECK(object1->CreationContext() == context1);
14563 CheckContextId(object1, 1);
14564 CHECK(func1->CreationContext() == context1);
14565 CheckContextId(func1, 1);
14566 CHECK(instance1->CreationContext() == context1);
14567 CheckContextId(instance1, 1);
14568 CHECK(object2->CreationContext() == context2);
14569 CheckContextId(object2, 2);
14570 CHECK(func2->CreationContext() == context2);
14571 CheckContextId(func2, 2);
14572 CHECK(instance2->CreationContext() == context2);
14573 CheckContextId(instance2, 2);
14574 }
14575
14576 context1.Dispose();
14577 context2.Dispose();
14578 context3.Dispose();
14579}
Ben Murdoch257744e2011-11-30 15:57:28 +000014580
14581
14582Handle<Value> HasOwnPropertyIndexedPropertyGetter(uint32_t index,
14583 const AccessorInfo& info) {
14584 if (index == 42) return v8_str("yes");
14585 return Handle<v8::Integer>();
14586}
14587
14588
14589Handle<Value> HasOwnPropertyNamedPropertyGetter(Local<String> property,
14590 const AccessorInfo& info) {
14591 if (property->Equals(v8_str("foo"))) return v8_str("yes");
14592 return Handle<Value>();
14593}
14594
14595
14596Handle<v8::Integer> HasOwnPropertyIndexedPropertyQuery(
14597 uint32_t index, const AccessorInfo& info) {
14598 if (index == 42) return v8_num(1).As<v8::Integer>();
14599 return Handle<v8::Integer>();
14600}
14601
14602
14603Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery(
14604 Local<String> property, const AccessorInfo& info) {
14605 if (property->Equals(v8_str("foo"))) return v8_num(1).As<v8::Integer>();
14606 return Handle<v8::Integer>();
14607}
14608
14609
14610Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery2(
14611 Local<String> property, const AccessorInfo& info) {
14612 if (property->Equals(v8_str("bar"))) return v8_num(1).As<v8::Integer>();
14613 return Handle<v8::Integer>();
14614}
14615
14616
14617Handle<Value> HasOwnPropertyAccessorGetter(Local<String> property,
14618 const AccessorInfo& info) {
14619 return v8_str("yes");
14620}
14621
14622
14623TEST(HasOwnProperty) {
14624 v8::HandleScope scope;
14625 LocalContext env;
14626 { // Check normal properties and defined getters.
14627 Handle<Value> value = CompileRun(
14628 "function Foo() {"
14629 " this.foo = 11;"
14630 " this.__defineGetter__('baz', function() { return 1; });"
14631 "};"
14632 "function Bar() { "
14633 " this.bar = 13;"
14634 " this.__defineGetter__('bla', function() { return 2; });"
14635 "};"
14636 "Bar.prototype = new Foo();"
14637 "new Bar();");
14638 CHECK(value->IsObject());
14639 Handle<Object> object = value->ToObject();
14640 CHECK(object->Has(v8_str("foo")));
14641 CHECK(!object->HasOwnProperty(v8_str("foo")));
14642 CHECK(object->HasOwnProperty(v8_str("bar")));
14643 CHECK(object->Has(v8_str("baz")));
14644 CHECK(!object->HasOwnProperty(v8_str("baz")));
14645 CHECK(object->HasOwnProperty(v8_str("bla")));
14646 }
14647 { // Check named getter interceptors.
14648 Handle<ObjectTemplate> templ = ObjectTemplate::New();
14649 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
14650 Handle<Object> instance = templ->NewInstance();
14651 CHECK(!instance->HasOwnProperty(v8_str("42")));
14652 CHECK(instance->HasOwnProperty(v8_str("foo")));
14653 CHECK(!instance->HasOwnProperty(v8_str("bar")));
14654 }
14655 { // Check indexed getter interceptors.
14656 Handle<ObjectTemplate> templ = ObjectTemplate::New();
14657 templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
14658 Handle<Object> instance = templ->NewInstance();
14659 CHECK(instance->HasOwnProperty(v8_str("42")));
14660 CHECK(!instance->HasOwnProperty(v8_str("43")));
14661 CHECK(!instance->HasOwnProperty(v8_str("foo")));
14662 }
14663 { // Check named query interceptors.
14664 Handle<ObjectTemplate> templ = ObjectTemplate::New();
14665 templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
14666 Handle<Object> instance = templ->NewInstance();
14667 CHECK(instance->HasOwnProperty(v8_str("foo")));
14668 CHECK(!instance->HasOwnProperty(v8_str("bar")));
14669 }
14670 { // Check indexed query interceptors.
14671 Handle<ObjectTemplate> templ = ObjectTemplate::New();
14672 templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
14673 Handle<Object> instance = templ->NewInstance();
14674 CHECK(instance->HasOwnProperty(v8_str("42")));
14675 CHECK(!instance->HasOwnProperty(v8_str("41")));
14676 }
14677 { // Check callbacks.
14678 Handle<ObjectTemplate> templ = ObjectTemplate::New();
14679 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
14680 Handle<Object> instance = templ->NewInstance();
14681 CHECK(instance->HasOwnProperty(v8_str("foo")));
14682 CHECK(!instance->HasOwnProperty(v8_str("bar")));
14683 }
14684 { // Check that query wins on disagreement.
14685 Handle<ObjectTemplate> templ = ObjectTemplate::New();
14686 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
14687 0,
14688 HasOwnPropertyNamedPropertyQuery2);
14689 Handle<Object> instance = templ->NewInstance();
14690 CHECK(!instance->HasOwnProperty(v8_str("foo")));
14691 CHECK(instance->HasOwnProperty(v8_str("bar")));
14692 }
14693}
14694
14695
14696void CheckCodeGenerationAllowed() {
14697 Handle<Value> result = CompileRun("eval('42')");
14698 CHECK_EQ(42, result->Int32Value());
14699 result = CompileRun("(function(e) { return e('42'); })(eval)");
14700 CHECK_EQ(42, result->Int32Value());
14701 result = CompileRun("var f = new Function('return 42'); f()");
14702 CHECK_EQ(42, result->Int32Value());
14703}
14704
14705
14706void CheckCodeGenerationDisallowed() {
14707 TryCatch try_catch;
14708
14709 Handle<Value> result = CompileRun("eval('42')");
14710 CHECK(result.IsEmpty());
14711 CHECK(try_catch.HasCaught());
14712 try_catch.Reset();
14713
14714 result = CompileRun("(function(e) { return e('42'); })(eval)");
14715 CHECK(result.IsEmpty());
14716 CHECK(try_catch.HasCaught());
14717 try_catch.Reset();
14718
14719 result = CompileRun("var f = new Function('return 42'); f()");
14720 CHECK(result.IsEmpty());
14721 CHECK(try_catch.HasCaught());
14722}
14723
14724
14725bool CodeGenerationAllowed(Local<Context> context) {
14726 ApiTestFuzzer::Fuzz();
14727 return true;
14728}
14729
14730
14731bool CodeGenerationDisallowed(Local<Context> context) {
14732 ApiTestFuzzer::Fuzz();
14733 return false;
14734}
14735
14736
14737THREADED_TEST(AllowCodeGenFromStrings) {
14738 v8::HandleScope scope;
14739 LocalContext context;
14740
14741 // eval and the Function constructor allowed by default.
14742 CheckCodeGenerationAllowed();
14743
14744 // Disallow eval and the Function constructor.
14745 context->AllowCodeGenerationFromStrings(false);
14746 CheckCodeGenerationDisallowed();
14747
14748 // Allow again.
14749 context->AllowCodeGenerationFromStrings(true);
14750 CheckCodeGenerationAllowed();
14751
14752 // Disallow but setting a global callback that will allow the calls.
14753 context->AllowCodeGenerationFromStrings(false);
14754 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
14755 CheckCodeGenerationAllowed();
14756
14757 // Set a callback that disallows the code generation.
14758 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
14759 CheckCodeGenerationDisallowed();
14760}
14761
14762
14763static v8::Handle<Value> NonObjectThis(const v8::Arguments& args) {
14764 return v8::Undefined();
14765}
14766
14767
14768THREADED_TEST(CallAPIFunctionOnNonObject) {
14769 v8::HandleScope scope;
14770 LocalContext context;
14771 Handle<FunctionTemplate> templ = v8::FunctionTemplate::New(NonObjectThis);
14772 Handle<Function> function = templ->GetFunction();
14773 context->Global()->Set(v8_str("f"), function);
14774 TryCatch try_catch;
14775 CompileRun("f.call(2)");
14776}
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014777
14778
14779// Regression test for issue 1470.
14780THREADED_TEST(ReadOnlyIndexedProperties) {
14781 v8::HandleScope scope;
14782 Local<ObjectTemplate> templ = ObjectTemplate::New();
14783
14784 LocalContext context;
14785 Local<v8::Object> obj = templ->NewInstance();
14786 context->Global()->Set(v8_str("obj"), obj);
14787 obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
14788 obj->Set(v8_str("1"), v8_str("foobar"));
14789 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
14790 obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
14791 obj->Set(v8_num(2), v8_str("foobar"));
14792 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
14793
14794 // Test non-smi case.
14795 obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
14796 obj->Set(v8_str("2000000000"), v8_str("foobar"));
14797 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
14798}
14799
14800
14801THREADED_TEST(Regress1516) {
14802 v8::HandleScope scope;
14803
14804 LocalContext context;
14805 { v8::HandleScope temp_scope;
14806 CompileRun("({'a': 0})");
14807 }
14808
14809 int elements;
14810 { i::MapCache* map_cache =
14811 i::MapCache::cast(i::Isolate::Current()->context()->map_cache());
14812 elements = map_cache->NumberOfElements();
14813 CHECK_LE(1, elements);
14814 }
14815
14816 i::Isolate::Current()->heap()->CollectAllGarbage(true);
14817 { i::Object* raw_map_cache = i::Isolate::Current()->context()->map_cache();
14818 if (raw_map_cache != i::Isolate::Current()->heap()->undefined_value()) {
14819 i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
14820 CHECK_GT(elements, map_cache->NumberOfElements());
14821 }
14822 }
14823}
14824
14825
14826static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
14827 Local<Value> name,
14828 v8::AccessType type,
14829 Local<Value> data) {
14830 // Only block read access to __proto__.
14831 if (type == v8::ACCESS_GET &&
14832 name->IsString() &&
14833 name->ToString()->Length() == 9 &&
14834 name->ToString()->Utf8Length() == 9) {
14835 char buffer[10];
14836 CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
14837 return strncmp(buffer, "__proto__", 9) != 0;
14838 }
14839
14840 return true;
14841}
14842
14843
14844THREADED_TEST(Regress93759) {
14845 HandleScope scope;
14846
14847 // Template for object with security check.
14848 Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New();
14849 // We don't do indexing, so any callback can be used for that.
14850 no_proto_template->SetAccessCheckCallbacks(
14851 BlockProtoNamedSecurityTestCallback,
14852 IndexedSecurityTestCallback);
14853
14854 // Templates for objects with hidden prototypes and possibly security check.
14855 Local<FunctionTemplate> hidden_proto_template = v8::FunctionTemplate::New();
14856 hidden_proto_template->SetHiddenPrototype(true);
14857
14858 Local<FunctionTemplate> protected_hidden_proto_template =
14859 v8::FunctionTemplate::New();
14860 protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
14861 BlockProtoNamedSecurityTestCallback,
14862 IndexedSecurityTestCallback);
14863 protected_hidden_proto_template->SetHiddenPrototype(true);
14864
14865 // Context for "foreign" objects used in test.
14866 Persistent<Context> context = v8::Context::New();
14867 context->Enter();
14868
14869 // Plain object, no security check.
14870 Local<Object> simple_object = Object::New();
14871
14872 // Object with explicit security check.
14873 Local<Object> protected_object =
14874 no_proto_template->NewInstance();
14875
14876 // JSGlobalProxy object, always have security check.
14877 Local<Object> proxy_object =
14878 context->Global();
14879
14880 // Global object, the prototype of proxy_object. No security checks.
14881 Local<Object> global_object =
14882 proxy_object->GetPrototype()->ToObject();
14883
14884 // Hidden prototype without security check.
14885 Local<Object> hidden_prototype =
14886 hidden_proto_template->GetFunction()->NewInstance();
14887 Local<Object> object_with_hidden =
14888 Object::New();
14889 object_with_hidden->SetPrototype(hidden_prototype);
14890
14891 // Hidden prototype with security check on the hidden prototype.
14892 Local<Object> protected_hidden_prototype =
14893 protected_hidden_proto_template->GetFunction()->NewInstance();
14894 Local<Object> object_with_protected_hidden =
14895 Object::New();
14896 object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
14897
14898 context->Exit();
14899
14900 // Template for object for second context. Values to test are put on it as
14901 // properties.
14902 Local<ObjectTemplate> global_template = ObjectTemplate::New();
14903 global_template->Set(v8_str("simple"), simple_object);
14904 global_template->Set(v8_str("protected"), protected_object);
14905 global_template->Set(v8_str("global"), global_object);
14906 global_template->Set(v8_str("proxy"), proxy_object);
14907 global_template->Set(v8_str("hidden"), object_with_hidden);
14908 global_template->Set(v8_str("phidden"), object_with_protected_hidden);
14909
14910 LocalContext context2(NULL, global_template);
14911
14912 Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
14913 CHECK(result1->Equals(simple_object->GetPrototype()));
14914
14915 Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
14916 CHECK(result2->Equals(Undefined()));
14917
14918 Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
14919 CHECK(result3->Equals(global_object->GetPrototype()));
14920
14921 Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
14922 CHECK(result4->Equals(Undefined()));
14923
14924 Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
14925 CHECK(result5->Equals(
14926 object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
14927
14928 Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
14929 CHECK(result6->Equals(Undefined()));
14930
14931 context.Dispose();
14932}