blob: 3d40a730a1ddd643702aff248eab12f34a7915e8 [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 Blocka7e24c12009-10-30 11:49:00 +000075
Leon Clarked91b9f72010-01-27 17:25:45 +000076static void ExpectString(const char* code, const char* expected) {
77 Local<Value> result = CompileRun(code);
78 CHECK(result->IsString());
79 String::AsciiValue ascii(result);
80 CHECK_EQ(expected, *ascii);
81}
82
83
84static void ExpectBoolean(const char* code, bool expected) {
85 Local<Value> result = CompileRun(code);
86 CHECK(result->IsBoolean());
87 CHECK_EQ(expected, result->BooleanValue());
88}
89
90
Leon Clarkef7060e22010-06-03 12:02:55 +010091static void ExpectTrue(const char* code) {
92 ExpectBoolean(code, true);
93}
94
95
Iain Merrick75681382010-08-19 15:07:18 +010096static void ExpectFalse(const char* code) {
97 ExpectBoolean(code, false);
98}
99
100
Leon Clarked91b9f72010-01-27 17:25:45 +0000101static void ExpectObject(const char* code, Local<Value> expected) {
102 Local<Value> result = CompileRun(code);
103 CHECK(result->Equals(expected));
104}
105
106
Iain Merrick75681382010-08-19 15:07:18 +0100107static void ExpectUndefined(const char* code) {
108 Local<Value> result = CompileRun(code);
109 CHECK(result->IsUndefined());
110}
111
112
Steve Blocka7e24c12009-10-30 11:49:00 +0000113static int signature_callback_count;
114static v8::Handle<Value> IncrementingSignatureCallback(
115 const v8::Arguments& args) {
116 ApiTestFuzzer::Fuzz();
117 signature_callback_count++;
118 v8::Handle<v8::Array> result = v8::Array::New(args.Length());
119 for (int i = 0; i < args.Length(); i++)
120 result->Set(v8::Integer::New(i), args[i]);
121 return result;
122}
123
124
125static v8::Handle<Value> SignatureCallback(const v8::Arguments& args) {
126 ApiTestFuzzer::Fuzz();
127 v8::Handle<v8::Array> result = v8::Array::New(args.Length());
128 for (int i = 0; i < args.Length(); i++) {
129 result->Set(v8::Integer::New(i), args[i]);
130 }
131 return result;
132}
133
134
135THREADED_TEST(Handles) {
136 v8::HandleScope scope;
137 Local<Context> local_env;
138 {
139 LocalContext env;
140 local_env = env.local();
141 }
142
143 // Local context should still be live.
144 CHECK(!local_env.IsEmpty());
145 local_env->Enter();
146
147 v8::Handle<v8::Primitive> undef = v8::Undefined();
148 CHECK(!undef.IsEmpty());
149 CHECK(undef->IsUndefined());
150
151 const char* c_source = "1 + 2 + 3";
152 Local<String> source = String::New(c_source);
153 Local<Script> script = Script::Compile(source);
154 CHECK_EQ(6, script->Run()->Int32Value());
155
156 local_env->Exit();
157}
158
159
Steve Blocka7e24c12009-10-30 11:49:00 +0000160THREADED_TEST(ReceiverSignature) {
161 v8::HandleScope scope;
162 LocalContext env;
163 v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
164 v8::Handle<v8::Signature> sig = v8::Signature::New(fun);
165 fun->PrototypeTemplate()->Set(
166 v8_str("m"),
167 v8::FunctionTemplate::New(IncrementingSignatureCallback,
168 v8::Handle<Value>(),
169 sig));
170 env->Global()->Set(v8_str("Fun"), fun->GetFunction());
171 signature_callback_count = 0;
172 CompileRun(
173 "var o = new Fun();"
174 "o.m();");
175 CHECK_EQ(1, signature_callback_count);
176 v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New();
177 sub_fun->Inherit(fun);
178 env->Global()->Set(v8_str("SubFun"), sub_fun->GetFunction());
179 CompileRun(
180 "var o = new SubFun();"
181 "o.m();");
182 CHECK_EQ(2, signature_callback_count);
183
184 v8::TryCatch try_catch;
185 CompileRun(
186 "var o = { };"
187 "o.m = Fun.prototype.m;"
188 "o.m();");
189 CHECK_EQ(2, signature_callback_count);
190 CHECK(try_catch.HasCaught());
191 try_catch.Reset();
192 v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New();
193 sub_fun->Inherit(fun);
194 env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
195 CompileRun(
196 "var o = new UnrelFun();"
197 "o.m = Fun.prototype.m;"
198 "o.m();");
199 CHECK_EQ(2, signature_callback_count);
200 CHECK(try_catch.HasCaught());
201}
202
203
Steve Blocka7e24c12009-10-30 11:49:00 +0000204THREADED_TEST(ArgumentSignature) {
205 v8::HandleScope scope;
206 LocalContext env;
207 v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New();
208 cons->SetClassName(v8_str("Cons"));
209 v8::Handle<v8::Signature> sig =
210 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 1, &cons);
211 v8::Handle<v8::FunctionTemplate> fun =
212 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig);
213 env->Global()->Set(v8_str("Cons"), cons->GetFunction());
214 env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
215
216 v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
217 CHECK(value1->IsTrue());
218
219 v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
220 CHECK(value2->IsTrue());
221
222 v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
223 CHECK(value3->IsTrue());
224
225 v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New();
226 cons1->SetClassName(v8_str("Cons1"));
227 v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New();
228 cons2->SetClassName(v8_str("Cons2"));
229 v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New();
230 cons3->SetClassName(v8_str("Cons3"));
231
232 v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
233 v8::Handle<v8::Signature> wsig =
234 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 3, args);
235 v8::Handle<v8::FunctionTemplate> fun2 =
236 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig);
237
238 env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
239 env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
240 env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
241 env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
242 v8::Handle<Value> value4 = CompileRun(
243 "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
244 "'[object Cons1],[object Cons2],[object Cons3]'");
245 CHECK(value4->IsTrue());
246
247 v8::Handle<Value> value5 = CompileRun(
248 "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
249 CHECK(value5->IsTrue());
250
251 v8::Handle<Value> value6 = CompileRun(
252 "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
253 CHECK(value6->IsTrue());
254
255 v8::Handle<Value> value7 = CompileRun(
256 "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
257 "'[object Cons1],[object Cons2],[object Cons3],d';");
258 CHECK(value7->IsTrue());
259
260 v8::Handle<Value> value8 = CompileRun(
261 "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
262 CHECK(value8->IsTrue());
263}
264
265
266THREADED_TEST(HulIgennem) {
267 v8::HandleScope scope;
268 LocalContext env;
269 v8::Handle<v8::Primitive> undef = v8::Undefined();
270 Local<String> undef_str = undef->ToString();
271 char* value = i::NewArray<char>(undef_str->Length() + 1);
272 undef_str->WriteAscii(value);
273 CHECK_EQ(0, strcmp(value, "undefined"));
274 i::DeleteArray(value);
275}
276
277
278THREADED_TEST(Access) {
279 v8::HandleScope scope;
280 LocalContext env;
281 Local<v8::Object> obj = v8::Object::New();
282 Local<Value> foo_before = obj->Get(v8_str("foo"));
283 CHECK(foo_before->IsUndefined());
284 Local<String> bar_str = v8_str("bar");
285 obj->Set(v8_str("foo"), bar_str);
286 Local<Value> foo_after = obj->Get(v8_str("foo"));
287 CHECK(!foo_after->IsUndefined());
288 CHECK(foo_after->IsString());
289 CHECK_EQ(bar_str, foo_after);
290}
291
292
Steve Block6ded16b2010-05-10 14:33:55 +0100293THREADED_TEST(AccessElement) {
294 v8::HandleScope scope;
295 LocalContext env;
296 Local<v8::Object> obj = v8::Object::New();
297 Local<Value> before = obj->Get(1);
298 CHECK(before->IsUndefined());
299 Local<String> bar_str = v8_str("bar");
300 obj->Set(1, bar_str);
301 Local<Value> after = obj->Get(1);
302 CHECK(!after->IsUndefined());
303 CHECK(after->IsString());
304 CHECK_EQ(bar_str, after);
305
306 Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
307 CHECK_EQ(v8_str("a"), value->Get(0));
308 CHECK_EQ(v8_str("b"), value->Get(1));
309}
310
311
Steve Blocka7e24c12009-10-30 11:49:00 +0000312THREADED_TEST(Script) {
313 v8::HandleScope scope;
314 LocalContext env;
315 const char* c_source = "1 + 2 + 3";
316 Local<String> source = String::New(c_source);
317 Local<Script> script = Script::Compile(source);
318 CHECK_EQ(6, script->Run()->Int32Value());
319}
320
321
322static uint16_t* AsciiToTwoByteString(const char* source) {
Steve Blockd0582a62009-12-15 09:54:21 +0000323 int array_length = i::StrLength(source) + 1;
Steve Blocka7e24c12009-10-30 11:49:00 +0000324 uint16_t* converted = i::NewArray<uint16_t>(array_length);
Steve Blockd0582a62009-12-15 09:54:21 +0000325 for (int i = 0; i < array_length; i++) converted[i] = source[i];
Steve Blocka7e24c12009-10-30 11:49:00 +0000326 return converted;
327}
328
329
330class TestResource: public String::ExternalStringResource {
331 public:
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000332 explicit TestResource(uint16_t* data, int* counter = NULL)
333 : data_(data), length_(0), counter_(counter) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000334 while (data[length_]) ++length_;
335 }
336
337 ~TestResource() {
338 i::DeleteArray(data_);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000339 if (counter_ != NULL) ++*counter_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000340 }
341
342 const uint16_t* data() const {
343 return data_;
344 }
345
346 size_t length() const {
347 return length_;
348 }
349 private:
350 uint16_t* data_;
351 size_t length_;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000352 int* counter_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000353};
354
355
Steve Blocka7e24c12009-10-30 11:49:00 +0000356class TestAsciiResource: public String::ExternalAsciiStringResource {
357 public:
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000358 explicit TestAsciiResource(const char* data, int* counter = NULL)
359 : data_(data), length_(strlen(data)), counter_(counter) { }
Steve Blocka7e24c12009-10-30 11:49:00 +0000360
361 ~TestAsciiResource() {
362 i::DeleteArray(data_);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000363 if (counter_ != NULL) ++*counter_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000364 }
365
366 const char* data() const {
367 return data_;
368 }
369
370 size_t length() const {
371 return length_;
372 }
373 private:
374 const char* data_;
375 size_t length_;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000376 int* counter_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000377};
378
379
Steve Blocka7e24c12009-10-30 11:49:00 +0000380THREADED_TEST(ScriptUsingStringResource) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000381 int dispose_count = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +0000382 const char* c_source = "1 + 2 * 3";
383 uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
384 {
385 v8::HandleScope scope;
386 LocalContext env;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000387 TestResource* resource = new TestResource(two_byte_source, &dispose_count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000388 Local<String> source = String::NewExternal(resource);
389 Local<Script> script = Script::Compile(source);
390 Local<Value> value = script->Run();
391 CHECK(value->IsNumber());
392 CHECK_EQ(7, value->Int32Value());
393 CHECK(source->IsExternal());
394 CHECK_EQ(resource,
395 static_cast<TestResource*>(source->GetExternalStringResource()));
Steve Block44f0eee2011-05-26 01:26:41 +0100396 HEAP->CollectAllGarbage(false);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000397 CHECK_EQ(0, dispose_count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000398 }
Steve Block44f0eee2011-05-26 01:26:41 +0100399 v8::internal::Isolate::Current()->compilation_cache()->Clear();
400 HEAP->CollectAllGarbage(false);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000401 CHECK_EQ(1, dispose_count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000402}
403
404
405THREADED_TEST(ScriptUsingAsciiStringResource) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000406 int dispose_count = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +0000407 const char* c_source = "1 + 2 * 3";
408 {
409 v8::HandleScope scope;
410 LocalContext env;
411 Local<String> source =
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000412 String::NewExternal(new TestAsciiResource(i::StrDup(c_source),
413 &dispose_count));
Steve Blocka7e24c12009-10-30 11:49:00 +0000414 Local<Script> script = Script::Compile(source);
415 Local<Value> value = script->Run();
416 CHECK(value->IsNumber());
417 CHECK_EQ(7, value->Int32Value());
Steve Block44f0eee2011-05-26 01:26:41 +0100418 HEAP->CollectAllGarbage(false);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000419 CHECK_EQ(0, dispose_count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000420 }
Steve Block44f0eee2011-05-26 01:26:41 +0100421 i::Isolate::Current()->compilation_cache()->Clear();
422 HEAP->CollectAllGarbage(false);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000423 CHECK_EQ(1, dispose_count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000424}
425
426
427THREADED_TEST(ScriptMakingExternalString) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000428 int dispose_count = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +0000429 uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
430 {
431 v8::HandleScope scope;
432 LocalContext env;
433 Local<String> source = String::New(two_byte_source);
Andrei Popescu402d9372010-02-26 13:31:12 +0000434 // Trigger GCs so that the newly allocated string moves to old gen.
Steve Block44f0eee2011-05-26 01:26:41 +0100435 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
436 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000437 bool success = source->MakeExternal(new TestResource(two_byte_source,
438 &dispose_count));
Steve Blocka7e24c12009-10-30 11:49:00 +0000439 CHECK(success);
440 Local<Script> script = Script::Compile(source);
441 Local<Value> value = script->Run();
442 CHECK(value->IsNumber());
443 CHECK_EQ(7, value->Int32Value());
Steve Block44f0eee2011-05-26 01:26:41 +0100444 HEAP->CollectAllGarbage(false);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000445 CHECK_EQ(0, dispose_count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000446 }
Steve Block44f0eee2011-05-26 01:26:41 +0100447 i::Isolate::Current()->compilation_cache()->Clear();
448 HEAP->CollectAllGarbage(false);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000449 CHECK_EQ(1, dispose_count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000450}
451
452
453THREADED_TEST(ScriptMakingExternalAsciiString) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000454 int dispose_count = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +0000455 const char* c_source = "1 + 2 * 3";
456 {
457 v8::HandleScope scope;
458 LocalContext env;
459 Local<String> source = v8_str(c_source);
Andrei Popescu402d9372010-02-26 13:31:12 +0000460 // Trigger GCs so that the newly allocated string moves to old gen.
Steve Block44f0eee2011-05-26 01:26:41 +0100461 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
462 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
Steve Blocka7e24c12009-10-30 11:49:00 +0000463 bool success = source->MakeExternal(
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000464 new TestAsciiResource(i::StrDup(c_source), &dispose_count));
Steve Blocka7e24c12009-10-30 11:49:00 +0000465 CHECK(success);
466 Local<Script> script = Script::Compile(source);
467 Local<Value> value = script->Run();
468 CHECK(value->IsNumber());
469 CHECK_EQ(7, value->Int32Value());
Steve Block44f0eee2011-05-26 01:26:41 +0100470 HEAP->CollectAllGarbage(false);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000471 CHECK_EQ(0, dispose_count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000472 }
Steve Block44f0eee2011-05-26 01:26:41 +0100473 i::Isolate::Current()->compilation_cache()->Clear();
474 HEAP->CollectAllGarbage(false);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000475 CHECK_EQ(1, dispose_count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000476}
477
478
Andrei Popescu402d9372010-02-26 13:31:12 +0000479TEST(MakingExternalStringConditions) {
480 v8::HandleScope scope;
481 LocalContext env;
482
483 // Free some space in the new space so that we can check freshness.
Steve Block44f0eee2011-05-26 01:26:41 +0100484 HEAP->CollectGarbage(i::NEW_SPACE);
485 HEAP->CollectGarbage(i::NEW_SPACE);
Andrei Popescu402d9372010-02-26 13:31:12 +0000486
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100487 uint16_t* two_byte_string = AsciiToTwoByteString("small");
488 Local<String> small_string = String::New(two_byte_string);
489 i::DeleteArray(two_byte_string);
490
Andrei Popescu402d9372010-02-26 13:31:12 +0000491 // We should refuse to externalize newly created small string.
492 CHECK(!small_string->CanMakeExternal());
493 // Trigger GCs so that the newly allocated string moves to old gen.
Steve Block44f0eee2011-05-26 01:26:41 +0100494 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
495 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
Andrei Popescu402d9372010-02-26 13:31:12 +0000496 // Old space strings should be accepted.
497 CHECK(small_string->CanMakeExternal());
498
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100499 two_byte_string = AsciiToTwoByteString("small 2");
500 small_string = String::New(two_byte_string);
501 i::DeleteArray(two_byte_string);
502
Andrei Popescu402d9372010-02-26 13:31:12 +0000503 // We should refuse externalizing newly created small string.
504 CHECK(!small_string->CanMakeExternal());
505 for (int i = 0; i < 100; i++) {
506 String::Value value(small_string);
507 }
508 // Frequently used strings should be accepted.
509 CHECK(small_string->CanMakeExternal());
510
511 const int buf_size = 10 * 1024;
512 char* buf = i::NewArray<char>(buf_size);
513 memset(buf, 'a', buf_size);
514 buf[buf_size - 1] = '\0';
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100515
516 two_byte_string = AsciiToTwoByteString(buf);
517 Local<String> large_string = String::New(two_byte_string);
Andrei Popescu402d9372010-02-26 13:31:12 +0000518 i::DeleteArray(buf);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100519 i::DeleteArray(two_byte_string);
Andrei Popescu402d9372010-02-26 13:31:12 +0000520 // Large strings should be immediately accepted.
521 CHECK(large_string->CanMakeExternal());
522}
523
524
525TEST(MakingExternalAsciiStringConditions) {
526 v8::HandleScope scope;
527 LocalContext env;
528
529 // Free some space in the new space so that we can check freshness.
Steve Block44f0eee2011-05-26 01:26:41 +0100530 HEAP->CollectGarbage(i::NEW_SPACE);
531 HEAP->CollectGarbage(i::NEW_SPACE);
Andrei Popescu402d9372010-02-26 13:31:12 +0000532
533 Local<String> small_string = String::New("small");
534 // We should refuse to externalize newly created small string.
535 CHECK(!small_string->CanMakeExternal());
536 // Trigger GCs so that the newly allocated string moves to old gen.
Steve Block44f0eee2011-05-26 01:26:41 +0100537 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
538 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
Andrei Popescu402d9372010-02-26 13:31:12 +0000539 // Old space strings should be accepted.
540 CHECK(small_string->CanMakeExternal());
541
542 small_string = String::New("small 2");
543 // We should refuse externalizing newly created small string.
544 CHECK(!small_string->CanMakeExternal());
545 for (int i = 0; i < 100; i++) {
546 String::Value value(small_string);
547 }
548 // Frequently used strings should be accepted.
549 CHECK(small_string->CanMakeExternal());
550
551 const int buf_size = 10 * 1024;
552 char* buf = i::NewArray<char>(buf_size);
553 memset(buf, 'a', buf_size);
554 buf[buf_size - 1] = '\0';
555 Local<String> large_string = String::New(buf);
556 i::DeleteArray(buf);
557 // Large strings should be immediately accepted.
558 CHECK(large_string->CanMakeExternal());
559}
560
561
Steve Blocka7e24c12009-10-30 11:49:00 +0000562THREADED_TEST(UsingExternalString) {
563 {
564 v8::HandleScope scope;
565 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
566 Local<String> string =
567 String::NewExternal(new TestResource(two_byte_string));
568 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
569 // Trigger GCs so that the newly allocated string moves to old gen.
Steve Block44f0eee2011-05-26 01:26:41 +0100570 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
571 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
572 i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
Steve Blocka7e24c12009-10-30 11:49:00 +0000573 CHECK(isymbol->IsSymbol());
574 }
Steve Block44f0eee2011-05-26 01:26:41 +0100575 HEAP->CollectAllGarbage(false);
576 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000577}
578
579
580THREADED_TEST(UsingExternalAsciiString) {
581 {
582 v8::HandleScope scope;
583 const char* one_byte_string = "test string";
584 Local<String> string = String::NewExternal(
585 new TestAsciiResource(i::StrDup(one_byte_string)));
586 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
587 // Trigger GCs so that the newly allocated string moves to old gen.
Steve Block44f0eee2011-05-26 01:26:41 +0100588 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
589 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
590 i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
Steve Blocka7e24c12009-10-30 11:49:00 +0000591 CHECK(isymbol->IsSymbol());
592 }
Steve Block44f0eee2011-05-26 01:26:41 +0100593 HEAP->CollectAllGarbage(false);
594 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000595}
596
597
Leon Clarkee46be812010-01-19 14:06:41 +0000598THREADED_TEST(ScavengeExternalString) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000599 int dispose_count = 0;
Steve Block6ded16b2010-05-10 14:33:55 +0100600 bool in_new_space = false;
Leon Clarkee46be812010-01-19 14:06:41 +0000601 {
602 v8::HandleScope scope;
603 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
604 Local<String> string =
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000605 String::NewExternal(new TestResource(two_byte_string,
606 &dispose_count));
Leon Clarkee46be812010-01-19 14:06:41 +0000607 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
Steve Block44f0eee2011-05-26 01:26:41 +0100608 HEAP->CollectGarbage(i::NEW_SPACE);
609 in_new_space = HEAP->InNewSpace(*istring);
610 CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000611 CHECK_EQ(0, dispose_count);
Leon Clarkee46be812010-01-19 14:06:41 +0000612 }
Steve Block44f0eee2011-05-26 01:26:41 +0100613 HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000614 CHECK_EQ(1, dispose_count);
Leon Clarkee46be812010-01-19 14:06:41 +0000615}
616
617
618THREADED_TEST(ScavengeExternalAsciiString) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000619 int dispose_count = 0;
Steve Block6ded16b2010-05-10 14:33:55 +0100620 bool in_new_space = false;
Leon Clarkee46be812010-01-19 14:06:41 +0000621 {
622 v8::HandleScope scope;
623 const char* one_byte_string = "test string";
624 Local<String> string = String::NewExternal(
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000625 new TestAsciiResource(i::StrDup(one_byte_string), &dispose_count));
Leon Clarkee46be812010-01-19 14:06:41 +0000626 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
Steve Block44f0eee2011-05-26 01:26:41 +0100627 HEAP->CollectGarbage(i::NEW_SPACE);
628 in_new_space = HEAP->InNewSpace(*istring);
629 CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000630 CHECK_EQ(0, dispose_count);
Leon Clarkee46be812010-01-19 14:06:41 +0000631 }
Steve Block44f0eee2011-05-26 01:26:41 +0100632 HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000633 CHECK_EQ(1, dispose_count);
Leon Clarkee46be812010-01-19 14:06:41 +0000634}
635
636
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100637class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
638 public:
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000639 // Only used by non-threaded tests, so it can use static fields.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100640 static int dispose_calls;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000641 static int dispose_count;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100642
643 TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000644 : TestAsciiResource(data, &dispose_count),
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100645 dispose_(dispose) { }
646
647 void Dispose() {
648 ++dispose_calls;
649 if (dispose_) delete this;
650 }
651 private:
652 bool dispose_;
653};
654
655
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000656int TestAsciiResourceWithDisposeControl::dispose_count = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100657int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
658
659
660TEST(ExternalStringWithDisposeHandling) {
661 const char* c_source = "1 + 2 * 3";
662
663 // Use a stack allocated external string resource allocated object.
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000664 TestAsciiResourceWithDisposeControl::dispose_count = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100665 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
666 TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
667 {
668 v8::HandleScope scope;
669 LocalContext env;
670 Local<String> source = String::NewExternal(&res_stack);
671 Local<Script> script = Script::Compile(source);
672 Local<Value> value = script->Run();
673 CHECK(value->IsNumber());
674 CHECK_EQ(7, value->Int32Value());
Steve Block44f0eee2011-05-26 01:26:41 +0100675 HEAP->CollectAllGarbage(false);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000676 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100677 }
Steve Block44f0eee2011-05-26 01:26:41 +0100678 i::Isolate::Current()->compilation_cache()->Clear();
679 HEAP->CollectAllGarbage(false);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100680 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000681 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100682
683 // Use a heap allocated external string resource allocated object.
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000684 TestAsciiResourceWithDisposeControl::dispose_count = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100685 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
686 TestAsciiResource* res_heap =
687 new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
688 {
689 v8::HandleScope scope;
690 LocalContext env;
691 Local<String> source = String::NewExternal(res_heap);
692 Local<Script> script = Script::Compile(source);
693 Local<Value> value = script->Run();
694 CHECK(value->IsNumber());
695 CHECK_EQ(7, value->Int32Value());
Steve Block44f0eee2011-05-26 01:26:41 +0100696 HEAP->CollectAllGarbage(false);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000697 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100698 }
Steve Block44f0eee2011-05-26 01:26:41 +0100699 i::Isolate::Current()->compilation_cache()->Clear();
700 HEAP->CollectAllGarbage(false);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100701 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000702 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100703}
704
705
Steve Block3ce2e202009-11-05 08:53:23 +0000706THREADED_TEST(StringConcat) {
707 {
708 v8::HandleScope scope;
709 LocalContext env;
710 const char* one_byte_string_1 = "function a_times_t";
711 const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
712 const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
713 const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
714 const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
715 const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
716 const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
717 Local<String> left = v8_str(one_byte_string_1);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100718
719 uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
720 Local<String> right = String::New(two_byte_source);
721 i::DeleteArray(two_byte_source);
722
Steve Block3ce2e202009-11-05 08:53:23 +0000723 Local<String> source = String::Concat(left, right);
724 right = String::NewExternal(
725 new TestAsciiResource(i::StrDup(one_byte_extern_1)));
726 source = String::Concat(source, right);
727 right = String::NewExternal(
728 new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
729 source = String::Concat(source, right);
730 right = v8_str(one_byte_string_2);
731 source = String::Concat(source, right);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100732
733 two_byte_source = AsciiToTwoByteString(two_byte_string_2);
734 right = String::New(two_byte_source);
735 i::DeleteArray(two_byte_source);
736
Steve Block3ce2e202009-11-05 08:53:23 +0000737 source = String::Concat(source, right);
738 right = String::NewExternal(
739 new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
740 source = String::Concat(source, right);
741 Local<Script> script = Script::Compile(source);
742 Local<Value> value = script->Run();
743 CHECK(value->IsNumber());
744 CHECK_EQ(68, value->Int32Value());
745 }
Steve Block44f0eee2011-05-26 01:26:41 +0100746 i::Isolate::Current()->compilation_cache()->Clear();
747 HEAP->CollectAllGarbage(false);
748 HEAP->CollectAllGarbage(false);
Steve Block3ce2e202009-11-05 08:53:23 +0000749}
750
751
Steve Blocka7e24c12009-10-30 11:49:00 +0000752THREADED_TEST(GlobalProperties) {
753 v8::HandleScope scope;
754 LocalContext env;
755 v8::Handle<v8::Object> global = env->Global();
756 global->Set(v8_str("pi"), v8_num(3.1415926));
757 Local<Value> pi = global->Get(v8_str("pi"));
758 CHECK_EQ(3.1415926, pi->NumberValue());
759}
760
761
762static v8::Handle<Value> handle_call(const v8::Arguments& args) {
763 ApiTestFuzzer::Fuzz();
764 return v8_num(102);
765}
766
767
768static v8::Handle<Value> construct_call(const v8::Arguments& args) {
769 ApiTestFuzzer::Fuzz();
770 args.This()->Set(v8_str("x"), v8_num(1));
771 args.This()->Set(v8_str("y"), v8_num(2));
772 return args.This();
773}
774
Ben Murdochf87a2032010-10-22 12:50:53 +0100775static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
776 ApiTestFuzzer::Fuzz();
777 return v8_num(239);
778}
779
780
Steve Blocka7e24c12009-10-30 11:49:00 +0000781THREADED_TEST(FunctionTemplate) {
782 v8::HandleScope scope;
783 LocalContext env;
784 {
785 Local<v8::FunctionTemplate> fun_templ =
786 v8::FunctionTemplate::New(handle_call);
787 Local<Function> fun = fun_templ->GetFunction();
788 env->Global()->Set(v8_str("obj"), fun);
789 Local<Script> script = v8_compile("obj()");
790 CHECK_EQ(102, script->Run()->Int32Value());
791 }
792 // Use SetCallHandler to initialize a function template, should work like the
793 // previous one.
794 {
795 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
796 fun_templ->SetCallHandler(handle_call);
797 Local<Function> fun = fun_templ->GetFunction();
798 env->Global()->Set(v8_str("obj"), fun);
799 Local<Script> script = v8_compile("obj()");
800 CHECK_EQ(102, script->Run()->Int32Value());
801 }
802 // Test constructor calls.
803 {
804 Local<v8::FunctionTemplate> fun_templ =
805 v8::FunctionTemplate::New(construct_call);
806 fun_templ->SetClassName(v8_str("funky"));
Ben Murdochf87a2032010-10-22 12:50:53 +0100807 fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), Return239);
Steve Blocka7e24c12009-10-30 11:49:00 +0000808 Local<Function> fun = fun_templ->GetFunction();
809 env->Global()->Set(v8_str("obj"), fun);
810 Local<Script> script = v8_compile("var s = new obj(); s.x");
811 CHECK_EQ(1, script->Run()->Int32Value());
812
813 Local<Value> result = v8_compile("(new obj()).toString()")->Run();
814 CHECK_EQ(v8_str("[object funky]"), result);
Ben Murdochf87a2032010-10-22 12:50:53 +0100815
816 result = v8_compile("(new obj()).m")->Run();
817 CHECK_EQ(239, result->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +0000818 }
819}
820
821
Ben Murdochb8e0da22011-05-16 14:20:40 +0100822static void* expected_ptr;
823static v8::Handle<v8::Value> callback(const v8::Arguments& args) {
824 void* ptr = v8::External::Unwrap(args.Data());
825 CHECK_EQ(expected_ptr, ptr);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000826 return v8::True();
Ben Murdochb8e0da22011-05-16 14:20:40 +0100827}
828
829
830static void TestExternalPointerWrapping() {
831 v8::HandleScope scope;
832 LocalContext env;
833
834 v8::Handle<v8::Value> data = v8::External::Wrap(expected_ptr);
835
836 v8::Handle<v8::Object> obj = v8::Object::New();
837 obj->Set(v8_str("func"),
838 v8::FunctionTemplate::New(callback, data)->GetFunction());
839 env->Global()->Set(v8_str("obj"), obj);
840
841 CHECK(CompileRun(
842 "function foo() {\n"
843 " for (var i = 0; i < 13; i++) obj.func();\n"
844 "}\n"
845 "foo(), true")->BooleanValue());
846}
847
848
849THREADED_TEST(ExternalWrap) {
850 // Check heap allocated object.
851 int* ptr = new int;
852 expected_ptr = ptr;
853 TestExternalPointerWrapping();
854 delete ptr;
855
856 // Check stack allocated object.
857 int foo;
858 expected_ptr = &foo;
859 TestExternalPointerWrapping();
860
861 // Check not aligned addresses.
862 const int n = 100;
863 char* s = new char[n];
864 for (int i = 0; i < n; i++) {
865 expected_ptr = s + i;
866 TestExternalPointerWrapping();
867 }
868
869 delete[] s;
870
871 // Check several invalid addresses.
872 expected_ptr = reinterpret_cast<void*>(1);
873 TestExternalPointerWrapping();
874
875 expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
876 TestExternalPointerWrapping();
877
878 expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
879 TestExternalPointerWrapping();
880
881#if defined(V8_HOST_ARCH_X64)
Steve Block1e0659c2011-05-24 12:43:12 +0100882 // Check a value with a leading 1 bit in x64 Smi encoding.
883 expected_ptr = reinterpret_cast<void*>(0x400000000);
884 TestExternalPointerWrapping();
885
Ben Murdochb8e0da22011-05-16 14:20:40 +0100886 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
887 TestExternalPointerWrapping();
888
889 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
890 TestExternalPointerWrapping();
891#endif
892}
893
894
Steve Blocka7e24c12009-10-30 11:49:00 +0000895THREADED_TEST(FindInstanceInPrototypeChain) {
896 v8::HandleScope scope;
897 LocalContext env;
898
899 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
900 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
901 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
902 derived->Inherit(base);
903
904 Local<v8::Function> base_function = base->GetFunction();
905 Local<v8::Function> derived_function = derived->GetFunction();
906 Local<v8::Function> other_function = other->GetFunction();
907
908 Local<v8::Object> base_instance = base_function->NewInstance();
909 Local<v8::Object> derived_instance = derived_function->NewInstance();
910 Local<v8::Object> derived_instance2 = derived_function->NewInstance();
911 Local<v8::Object> other_instance = other_function->NewInstance();
912 derived_instance2->Set(v8_str("__proto__"), derived_instance);
913 other_instance->Set(v8_str("__proto__"), derived_instance2);
914
915 // base_instance is only an instance of base.
916 CHECK_EQ(base_instance,
917 base_instance->FindInstanceInPrototypeChain(base));
918 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
919 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
920
921 // derived_instance is an instance of base and derived.
922 CHECK_EQ(derived_instance,
923 derived_instance->FindInstanceInPrototypeChain(base));
924 CHECK_EQ(derived_instance,
925 derived_instance->FindInstanceInPrototypeChain(derived));
926 CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
927
928 // other_instance is an instance of other and its immediate
929 // prototype derived_instance2 is an instance of base and derived.
930 // Note, derived_instance is an instance of base and derived too,
931 // but it comes after derived_instance2 in the prototype chain of
932 // other_instance.
933 CHECK_EQ(derived_instance2,
934 other_instance->FindInstanceInPrototypeChain(base));
935 CHECK_EQ(derived_instance2,
936 other_instance->FindInstanceInPrototypeChain(derived));
937 CHECK_EQ(other_instance,
938 other_instance->FindInstanceInPrototypeChain(other));
939}
940
941
Steve Block3ce2e202009-11-05 08:53:23 +0000942THREADED_TEST(TinyInteger) {
943 v8::HandleScope scope;
944 LocalContext env;
945 int32_t value = 239;
946 Local<v8::Integer> value_obj = v8::Integer::New(value);
947 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
948}
949
950
951THREADED_TEST(BigSmiInteger) {
952 v8::HandleScope scope;
953 LocalContext env;
954 int32_t value = i::Smi::kMaxValue;
955 // We cannot add one to a Smi::kMaxValue without wrapping.
956 if (i::kSmiValueSize < 32) {
957 CHECK(i::Smi::IsValid(value));
958 CHECK(!i::Smi::IsValid(value + 1));
959 Local<v8::Integer> value_obj = v8::Integer::New(value);
960 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
961 }
962}
963
964
965THREADED_TEST(BigInteger) {
966 v8::HandleScope scope;
967 LocalContext env;
968 // We cannot add one to a Smi::kMaxValue without wrapping.
969 if (i::kSmiValueSize < 32) {
970 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
971 // The code will not be run in that case, due to the "if" guard.
972 int32_t value =
973 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
974 CHECK(value > i::Smi::kMaxValue);
975 CHECK(!i::Smi::IsValid(value));
976 Local<v8::Integer> value_obj = v8::Integer::New(value);
977 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
978 }
979}
980
981
982THREADED_TEST(TinyUnsignedInteger) {
983 v8::HandleScope scope;
984 LocalContext env;
985 uint32_t value = 239;
986 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
987 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
988}
989
990
991THREADED_TEST(BigUnsignedSmiInteger) {
992 v8::HandleScope scope;
993 LocalContext env;
994 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
995 CHECK(i::Smi::IsValid(value));
996 CHECK(!i::Smi::IsValid(value + 1));
997 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
998 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
999}
1000
1001
1002THREADED_TEST(BigUnsignedInteger) {
1003 v8::HandleScope scope;
1004 LocalContext env;
1005 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1006 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1007 CHECK(!i::Smi::IsValid(value));
1008 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1009 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1010}
1011
1012
1013THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1014 v8::HandleScope scope;
1015 LocalContext env;
1016 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1017 uint32_t value = INT32_MAX_AS_UINT + 1;
1018 CHECK(value > INT32_MAX_AS_UINT); // No overflow.
1019 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1020 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1021}
1022
1023
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001024THREADED_TEST(IsNativeError) {
1025 v8::HandleScope scope;
1026 LocalContext env;
1027 v8::Handle<Value> syntax_error = CompileRun(
1028 "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1029 CHECK(syntax_error->IsNativeError());
1030 v8::Handle<Value> not_error = CompileRun("{a:42}");
1031 CHECK(!not_error->IsNativeError());
1032 v8::Handle<Value> not_object = CompileRun("42");
1033 CHECK(!not_object->IsNativeError());
1034}
1035
1036
1037THREADED_TEST(StringObject) {
1038 v8::HandleScope scope;
1039 LocalContext env;
1040 v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1041 CHECK(boxed_string->IsStringObject());
1042 v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1043 CHECK(!unboxed_string->IsStringObject());
1044 v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1045 CHECK(!boxed_not_string->IsStringObject());
1046 v8::Handle<Value> not_object = CompileRun("0");
1047 CHECK(!not_object->IsStringObject());
1048 v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1049 CHECK(!as_boxed.IsEmpty());
1050 Local<v8::String> the_string = as_boxed->StringValue();
1051 CHECK(!the_string.IsEmpty());
1052 ExpectObject("\"test\"", the_string);
1053 v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1054 CHECK(new_boxed_string->IsStringObject());
1055 as_boxed = new_boxed_string.As<v8::StringObject>();
1056 the_string = as_boxed->StringValue();
1057 CHECK(!the_string.IsEmpty());
1058 ExpectObject("\"test\"", the_string);
1059}
1060
1061
1062THREADED_TEST(NumberObject) {
1063 v8::HandleScope scope;
1064 LocalContext env;
1065 v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1066 CHECK(boxed_number->IsNumberObject());
1067 v8::Handle<Value> unboxed_number = CompileRun("42");
1068 CHECK(!unboxed_number->IsNumberObject());
1069 v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1070 CHECK(!boxed_not_number->IsNumberObject());
1071 v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1072 CHECK(!as_boxed.IsEmpty());
1073 double the_number = as_boxed->NumberValue();
1074 CHECK_EQ(42.0, the_number);
1075 v8::Handle<v8::Value> new_boxed_number = v8::NumberObject::New(43);
1076 CHECK(new_boxed_number->IsNumberObject());
1077 as_boxed = new_boxed_number.As<v8::NumberObject>();
1078 the_number = as_boxed->NumberValue();
1079 CHECK_EQ(43.0, the_number);
1080}
1081
1082
1083THREADED_TEST(BooleanObject) {
1084 v8::HandleScope scope;
1085 LocalContext env;
1086 v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1087 CHECK(boxed_boolean->IsBooleanObject());
1088 v8::Handle<Value> unboxed_boolean = CompileRun("true");
1089 CHECK(!unboxed_boolean->IsBooleanObject());
1090 v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1091 CHECK(!boxed_not_boolean->IsBooleanObject());
1092 v8::Handle<v8::BooleanObject> as_boxed =
1093 boxed_boolean.As<v8::BooleanObject>();
1094 CHECK(!as_boxed.IsEmpty());
1095 bool the_boolean = as_boxed->BooleanValue();
1096 CHECK_EQ(true, the_boolean);
1097 v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1098 v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1099 CHECK(boxed_true->IsBooleanObject());
1100 CHECK(boxed_false->IsBooleanObject());
1101 as_boxed = boxed_true.As<v8::BooleanObject>();
1102 CHECK_EQ(true, as_boxed->BooleanValue());
1103 as_boxed = boxed_false.As<v8::BooleanObject>();
1104 CHECK_EQ(false, as_boxed->BooleanValue());
1105}
1106
1107
Steve Blocka7e24c12009-10-30 11:49:00 +00001108THREADED_TEST(Number) {
1109 v8::HandleScope scope;
1110 LocalContext env;
1111 double PI = 3.1415926;
1112 Local<v8::Number> pi_obj = v8::Number::New(PI);
1113 CHECK_EQ(PI, pi_obj->NumberValue());
1114}
1115
1116
1117THREADED_TEST(ToNumber) {
1118 v8::HandleScope scope;
1119 LocalContext env;
1120 Local<String> str = v8_str("3.1415926");
1121 CHECK_EQ(3.1415926, str->NumberValue());
1122 v8::Handle<v8::Boolean> t = v8::True();
1123 CHECK_EQ(1.0, t->NumberValue());
1124 v8::Handle<v8::Boolean> f = v8::False();
1125 CHECK_EQ(0.0, f->NumberValue());
1126}
1127
1128
1129THREADED_TEST(Date) {
1130 v8::HandleScope scope;
1131 LocalContext env;
1132 double PI = 3.1415926;
Ben Murdoch257744e2011-11-30 15:57:28 +00001133 Local<Value> date = v8::Date::New(PI);
1134 CHECK_EQ(3.0, date->NumberValue());
1135 date.As<v8::Date>()->Set(v8_str("property"), v8::Integer::New(42));
1136 CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00001137}
1138
1139
1140THREADED_TEST(Boolean) {
1141 v8::HandleScope scope;
1142 LocalContext env;
1143 v8::Handle<v8::Boolean> t = v8::True();
1144 CHECK(t->Value());
1145 v8::Handle<v8::Boolean> f = v8::False();
1146 CHECK(!f->Value());
1147 v8::Handle<v8::Primitive> u = v8::Undefined();
1148 CHECK(!u->BooleanValue());
1149 v8::Handle<v8::Primitive> n = v8::Null();
1150 CHECK(!n->BooleanValue());
1151 v8::Handle<String> str1 = v8_str("");
1152 CHECK(!str1->BooleanValue());
1153 v8::Handle<String> str2 = v8_str("x");
1154 CHECK(str2->BooleanValue());
1155 CHECK(!v8::Number::New(0)->BooleanValue());
1156 CHECK(v8::Number::New(-1)->BooleanValue());
1157 CHECK(v8::Number::New(1)->BooleanValue());
1158 CHECK(v8::Number::New(42)->BooleanValue());
1159 CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1160}
1161
1162
1163static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
1164 ApiTestFuzzer::Fuzz();
1165 return v8_num(13.4);
1166}
1167
1168
1169static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
1170 ApiTestFuzzer::Fuzz();
1171 return v8_num(876);
1172}
1173
1174
1175THREADED_TEST(GlobalPrototype) {
1176 v8::HandleScope scope;
1177 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
1178 func_templ->PrototypeTemplate()->Set(
1179 "dummy",
1180 v8::FunctionTemplate::New(DummyCallHandler));
1181 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1182 templ->Set("x", v8_num(200));
1183 templ->SetAccessor(v8_str("m"), GetM);
1184 LocalContext env(0, templ);
1185 v8::Handle<v8::Object> obj = env->Global();
1186 v8::Handle<Script> script = v8_compile("dummy()");
1187 v8::Handle<Value> result = script->Run();
1188 CHECK_EQ(13.4, result->NumberValue());
1189 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1190 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1191}
1192
1193
Steve Blocka7e24c12009-10-30 11:49:00 +00001194THREADED_TEST(ObjectTemplate) {
1195 v8::HandleScope scope;
1196 Local<ObjectTemplate> templ1 = ObjectTemplate::New();
1197 templ1->Set("x", v8_num(10));
1198 templ1->Set("y", v8_num(13));
1199 LocalContext env;
1200 Local<v8::Object> instance1 = templ1->NewInstance();
1201 env->Global()->Set(v8_str("p"), instance1);
1202 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1203 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1204 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
1205 fun->PrototypeTemplate()->Set("nirk", v8_num(123));
1206 Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1207 templ2->Set("a", v8_num(12));
1208 templ2->Set("b", templ1);
1209 Local<v8::Object> instance2 = templ2->NewInstance();
1210 env->Global()->Set(v8_str("q"), instance2);
1211 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1212 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1213 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1214 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1215}
1216
1217
1218static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
1219 ApiTestFuzzer::Fuzz();
1220 return v8_num(17.2);
1221}
1222
1223
1224static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
1225 ApiTestFuzzer::Fuzz();
1226 return v8_num(15.2);
1227}
1228
1229
1230THREADED_TEST(DescriptorInheritance) {
1231 v8::HandleScope scope;
1232 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
1233 super->PrototypeTemplate()->Set("flabby",
1234 v8::FunctionTemplate::New(GetFlabby));
1235 super->PrototypeTemplate()->Set("PI", v8_num(3.14));
1236
1237 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1238
1239 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
1240 base1->Inherit(super);
1241 base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
1242
1243 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
1244 base2->Inherit(super);
1245 base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
1246
1247 LocalContext env;
1248
1249 env->Global()->Set(v8_str("s"), super->GetFunction());
1250 env->Global()->Set(v8_str("base1"), base1->GetFunction());
1251 env->Global()->Set(v8_str("base2"), base2->GetFunction());
1252
1253 // Checks right __proto__ chain.
1254 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1255 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1256
1257 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1258
1259 // Instance accessor should not be visible on function object or its prototype
1260 CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1261 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1262 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1263
1264 env->Global()->Set(v8_str("obj"),
1265 base1->GetFunction()->NewInstance());
1266 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1267 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1268 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1269 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1270 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1271
1272 env->Global()->Set(v8_str("obj2"),
1273 base2->GetFunction()->NewInstance());
1274 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1275 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1276 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1277 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1278 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1279
1280 // base1 and base2 cannot cross reference to each's prototype
1281 CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1282 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1283}
1284
1285
1286int echo_named_call_count;
1287
1288
1289static v8::Handle<Value> EchoNamedProperty(Local<String> name,
1290 const AccessorInfo& info) {
1291 ApiTestFuzzer::Fuzz();
1292 CHECK_EQ(v8_str("data"), info.Data());
1293 echo_named_call_count++;
1294 return name;
1295}
1296
1297
1298THREADED_TEST(NamedPropertyHandlerGetter) {
1299 echo_named_call_count = 0;
1300 v8::HandleScope scope;
1301 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1302 templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
1303 0, 0, 0, 0,
1304 v8_str("data"));
1305 LocalContext env;
1306 env->Global()->Set(v8_str("obj"),
1307 templ->GetFunction()->NewInstance());
1308 CHECK_EQ(echo_named_call_count, 0);
1309 v8_compile("obj.x")->Run();
1310 CHECK_EQ(echo_named_call_count, 1);
1311 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
1312 v8::Handle<Value> str = CompileRun(code);
1313 String::AsciiValue value(str);
1314 CHECK_EQ(*value, "oddlepoddle");
1315 // Check default behavior
1316 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
1317 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
1318 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
1319}
1320
1321
1322int echo_indexed_call_count = 0;
1323
1324
1325static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
1326 const AccessorInfo& info) {
1327 ApiTestFuzzer::Fuzz();
1328 CHECK_EQ(v8_num(637), info.Data());
1329 echo_indexed_call_count++;
1330 return v8_num(index);
1331}
1332
1333
1334THREADED_TEST(IndexedPropertyHandlerGetter) {
1335 v8::HandleScope scope;
1336 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1337 templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
1338 0, 0, 0, 0,
1339 v8_num(637));
1340 LocalContext env;
1341 env->Global()->Set(v8_str("obj"),
1342 templ->GetFunction()->NewInstance());
1343 Local<Script> script = v8_compile("obj[900]");
1344 CHECK_EQ(script->Run()->Int32Value(), 900);
1345}
1346
1347
1348v8::Handle<v8::Object> bottom;
1349
1350static v8::Handle<Value> CheckThisIndexedPropertyHandler(
1351 uint32_t index,
1352 const AccessorInfo& info) {
1353 ApiTestFuzzer::Fuzz();
1354 CHECK(info.This()->Equals(bottom));
1355 return v8::Handle<Value>();
1356}
1357
1358static v8::Handle<Value> CheckThisNamedPropertyHandler(
1359 Local<String> name,
1360 const AccessorInfo& info) {
1361 ApiTestFuzzer::Fuzz();
1362 CHECK(info.This()->Equals(bottom));
1363 return v8::Handle<Value>();
1364}
1365
1366
1367v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
1368 Local<Value> value,
1369 const AccessorInfo& info) {
1370 ApiTestFuzzer::Fuzz();
1371 CHECK(info.This()->Equals(bottom));
1372 return v8::Handle<Value>();
1373}
1374
1375
1376v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
1377 Local<Value> value,
1378 const AccessorInfo& info) {
1379 ApiTestFuzzer::Fuzz();
1380 CHECK(info.This()->Equals(bottom));
1381 return v8::Handle<Value>();
1382}
1383
Iain Merrick75681382010-08-19 15:07:18 +01001384v8::Handle<v8::Integer> CheckThisIndexedPropertyQuery(
Steve Blocka7e24c12009-10-30 11:49:00 +00001385 uint32_t index,
1386 const AccessorInfo& info) {
1387 ApiTestFuzzer::Fuzz();
1388 CHECK(info.This()->Equals(bottom));
Iain Merrick75681382010-08-19 15:07:18 +01001389 return v8::Handle<v8::Integer>();
Steve Blocka7e24c12009-10-30 11:49:00 +00001390}
1391
1392
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001393v8::Handle<v8::Integer> CheckThisNamedPropertyQuery(Local<String> property,
Steve Blocka7e24c12009-10-30 11:49:00 +00001394 const AccessorInfo& info) {
1395 ApiTestFuzzer::Fuzz();
1396 CHECK(info.This()->Equals(bottom));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001397 return v8::Handle<v8::Integer>();
Steve Blocka7e24c12009-10-30 11:49:00 +00001398}
1399
1400
1401v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
1402 uint32_t index,
1403 const AccessorInfo& info) {
1404 ApiTestFuzzer::Fuzz();
1405 CHECK(info.This()->Equals(bottom));
1406 return v8::Handle<v8::Boolean>();
1407}
1408
1409
1410v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
1411 Local<String> property,
1412 const AccessorInfo& info) {
1413 ApiTestFuzzer::Fuzz();
1414 CHECK(info.This()->Equals(bottom));
1415 return v8::Handle<v8::Boolean>();
1416}
1417
1418
1419v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
1420 const AccessorInfo& info) {
1421 ApiTestFuzzer::Fuzz();
1422 CHECK(info.This()->Equals(bottom));
1423 return v8::Handle<v8::Array>();
1424}
1425
1426
1427v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
1428 const AccessorInfo& info) {
1429 ApiTestFuzzer::Fuzz();
1430 CHECK(info.This()->Equals(bottom));
1431 return v8::Handle<v8::Array>();
1432}
1433
1434
1435THREADED_TEST(PropertyHandlerInPrototype) {
1436 v8::HandleScope scope;
1437 LocalContext env;
1438
1439 // Set up a prototype chain with three interceptors.
1440 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1441 templ->InstanceTemplate()->SetIndexedPropertyHandler(
1442 CheckThisIndexedPropertyHandler,
1443 CheckThisIndexedPropertySetter,
1444 CheckThisIndexedPropertyQuery,
1445 CheckThisIndexedPropertyDeleter,
1446 CheckThisIndexedPropertyEnumerator);
1447
1448 templ->InstanceTemplate()->SetNamedPropertyHandler(
1449 CheckThisNamedPropertyHandler,
1450 CheckThisNamedPropertySetter,
1451 CheckThisNamedPropertyQuery,
1452 CheckThisNamedPropertyDeleter,
1453 CheckThisNamedPropertyEnumerator);
1454
1455 bottom = templ->GetFunction()->NewInstance();
1456 Local<v8::Object> top = templ->GetFunction()->NewInstance();
1457 Local<v8::Object> middle = templ->GetFunction()->NewInstance();
1458
1459 bottom->Set(v8_str("__proto__"), middle);
1460 middle->Set(v8_str("__proto__"), top);
1461 env->Global()->Set(v8_str("obj"), bottom);
1462
1463 // Indexed and named get.
1464 Script::Compile(v8_str("obj[0]"))->Run();
1465 Script::Compile(v8_str("obj.x"))->Run();
1466
1467 // Indexed and named set.
1468 Script::Compile(v8_str("obj[1] = 42"))->Run();
1469 Script::Compile(v8_str("obj.y = 42"))->Run();
1470
1471 // Indexed and named query.
1472 Script::Compile(v8_str("0 in obj"))->Run();
1473 Script::Compile(v8_str("'x' in obj"))->Run();
1474
1475 // Indexed and named deleter.
1476 Script::Compile(v8_str("delete obj[0]"))->Run();
1477 Script::Compile(v8_str("delete obj.x"))->Run();
1478
1479 // Enumerators.
1480 Script::Compile(v8_str("for (var p in obj) ;"))->Run();
1481}
1482
1483
1484static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
1485 const AccessorInfo& info) {
1486 ApiTestFuzzer::Fuzz();
1487 if (v8_str("pre")->Equals(key)) {
1488 return v8_str("PrePropertyHandler: pre");
1489 }
1490 return v8::Handle<String>();
1491}
1492
1493
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001494static v8::Handle<v8::Integer> PrePropertyHandlerQuery(Local<String> key,
1495 const AccessorInfo&) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001496 if (v8_str("pre")->Equals(key)) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001497 return v8::Integer::New(v8::None);
Steve Blocka7e24c12009-10-30 11:49:00 +00001498 }
1499
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001500 return v8::Handle<v8::Integer>(); // do not intercept the call
Steve Blocka7e24c12009-10-30 11:49:00 +00001501}
1502
1503
1504THREADED_TEST(PrePropertyHandler) {
1505 v8::HandleScope scope;
1506 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
1507 desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
1508 0,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001509 PrePropertyHandlerQuery);
Steve Blocka7e24c12009-10-30 11:49:00 +00001510 LocalContext env(NULL, desc->InstanceTemplate());
1511 Script::Compile(v8_str(
1512 "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
1513 v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
1514 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
1515 v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
1516 CHECK_EQ(v8_str("Object: on"), result_on);
1517 v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
1518 CHECK(result_post.IsEmpty());
1519}
1520
1521
1522THREADED_TEST(UndefinedIsNotEnumerable) {
1523 v8::HandleScope scope;
1524 LocalContext env;
1525 v8::Handle<Value> result = Script::Compile(v8_str(
1526 "this.propertyIsEnumerable(undefined)"))->Run();
1527 CHECK(result->IsFalse());
1528}
1529
1530
1531v8::Handle<Script> call_recursively_script;
Leon Clarke4515c472010-02-03 11:58:03 +00001532static const int kTargetRecursionDepth = 200; // near maximum
Steve Blocka7e24c12009-10-30 11:49:00 +00001533
1534
1535static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
1536 ApiTestFuzzer::Fuzz();
1537 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1538 if (depth == kTargetRecursionDepth) return v8::Undefined();
1539 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1540 return call_recursively_script->Run();
1541}
1542
1543
1544static v8::Handle<Value> CallFunctionRecursivelyCall(
1545 const v8::Arguments& args) {
1546 ApiTestFuzzer::Fuzz();
1547 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1548 if (depth == kTargetRecursionDepth) {
1549 printf("[depth = %d]\n", depth);
1550 return v8::Undefined();
1551 }
1552 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1553 v8::Handle<Value> function =
1554 args.This()->Get(v8_str("callFunctionRecursively"));
Steve Block6ded16b2010-05-10 14:33:55 +01001555 return function.As<Function>()->Call(args.This(), 0, NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001556}
1557
1558
1559THREADED_TEST(DeepCrossLanguageRecursion) {
1560 v8::HandleScope scope;
1561 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
1562 global->Set(v8_str("callScriptRecursively"),
1563 v8::FunctionTemplate::New(CallScriptRecursivelyCall));
1564 global->Set(v8_str("callFunctionRecursively"),
1565 v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
1566 LocalContext env(NULL, global);
1567
1568 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1569 call_recursively_script = v8_compile("callScriptRecursively()");
1570 v8::Handle<Value> result = call_recursively_script->Run();
1571 call_recursively_script = v8::Handle<Script>();
1572
1573 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1574 Script::Compile(v8_str("callFunctionRecursively()"))->Run();
1575}
1576
1577
1578static v8::Handle<Value>
1579 ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1580 ApiTestFuzzer::Fuzz();
1581 return v8::ThrowException(key);
1582}
1583
1584
1585static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
1586 Local<Value>,
1587 const AccessorInfo&) {
1588 v8::ThrowException(key);
1589 return v8::Undefined(); // not the same as v8::Handle<v8::Value>()
1590}
1591
1592
1593THREADED_TEST(CallbackExceptionRegression) {
1594 v8::HandleScope scope;
1595 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1596 obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
1597 ThrowingPropertyHandlerSet);
1598 LocalContext env;
1599 env->Global()->Set(v8_str("obj"), obj->NewInstance());
1600 v8::Handle<Value> otto = Script::Compile(v8_str(
1601 "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
1602 CHECK_EQ(v8_str("otto"), otto);
1603 v8::Handle<Value> netto = Script::Compile(v8_str(
1604 "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
1605 CHECK_EQ(v8_str("netto"), netto);
1606}
1607
1608
Steve Blocka7e24c12009-10-30 11:49:00 +00001609THREADED_TEST(FunctionPrototype) {
1610 v8::HandleScope scope;
1611 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
1612 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
1613 LocalContext env;
1614 env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
1615 Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
1616 CHECK_EQ(script->Run()->Int32Value(), 321);
1617}
1618
1619
1620THREADED_TEST(InternalFields) {
1621 v8::HandleScope scope;
1622 LocalContext env;
1623
1624 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1625 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1626 instance_templ->SetInternalFieldCount(1);
1627 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1628 CHECK_EQ(1, obj->InternalFieldCount());
1629 CHECK(obj->GetInternalField(0)->IsUndefined());
1630 obj->SetInternalField(0, v8_num(17));
1631 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
1632}
1633
1634
Steve Block6ded16b2010-05-10 14:33:55 +01001635THREADED_TEST(GlobalObjectInternalFields) {
1636 v8::HandleScope scope;
1637 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
1638 global_template->SetInternalFieldCount(1);
1639 LocalContext env(NULL, global_template);
1640 v8::Handle<v8::Object> global_proxy = env->Global();
1641 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
1642 CHECK_EQ(1, global->InternalFieldCount());
1643 CHECK(global->GetInternalField(0)->IsUndefined());
1644 global->SetInternalField(0, v8_num(17));
1645 CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
1646}
1647
1648
Steve Blocka7e24c12009-10-30 11:49:00 +00001649THREADED_TEST(InternalFieldsNativePointers) {
1650 v8::HandleScope scope;
1651 LocalContext env;
1652
1653 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1654 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1655 instance_templ->SetInternalFieldCount(1);
1656 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1657 CHECK_EQ(1, obj->InternalFieldCount());
1658 CHECK(obj->GetPointerFromInternalField(0) == NULL);
1659
1660 char* data = new char[100];
1661
1662 void* aligned = data;
Ben Murdochf87a2032010-10-22 12:50:53 +01001663 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
Steve Blocka7e24c12009-10-30 11:49:00 +00001664 void* unaligned = data + 1;
Ben Murdochf87a2032010-10-22 12:50:53 +01001665 CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
Steve Blocka7e24c12009-10-30 11:49:00 +00001666
1667 // Check reading and writing aligned pointers.
1668 obj->SetPointerInInternalField(0, aligned);
Steve Block44f0eee2011-05-26 01:26:41 +01001669 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +00001670 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1671
1672 // Check reading and writing unaligned pointers.
1673 obj->SetPointerInInternalField(0, unaligned);
Steve Block44f0eee2011-05-26 01:26:41 +01001674 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +00001675 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1676
1677 delete[] data;
1678}
1679
1680
Steve Block3ce2e202009-11-05 08:53:23 +00001681THREADED_TEST(InternalFieldsNativePointersAndExternal) {
1682 v8::HandleScope scope;
1683 LocalContext env;
1684
1685 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1686 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1687 instance_templ->SetInternalFieldCount(1);
1688 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1689 CHECK_EQ(1, obj->InternalFieldCount());
1690 CHECK(obj->GetPointerFromInternalField(0) == NULL);
1691
1692 char* data = new char[100];
1693
1694 void* aligned = data;
Ben Murdochf87a2032010-10-22 12:50:53 +01001695 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
Steve Block3ce2e202009-11-05 08:53:23 +00001696 void* unaligned = data + 1;
Ben Murdochf87a2032010-10-22 12:50:53 +01001697 CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
Steve Block3ce2e202009-11-05 08:53:23 +00001698
1699 obj->SetPointerInInternalField(0, aligned);
Steve Block44f0eee2011-05-26 01:26:41 +01001700 HEAP->CollectAllGarbage(false);
Steve Block3ce2e202009-11-05 08:53:23 +00001701 CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0)));
1702
1703 obj->SetPointerInInternalField(0, unaligned);
Steve Block44f0eee2011-05-26 01:26:41 +01001704 HEAP->CollectAllGarbage(false);
Steve Block3ce2e202009-11-05 08:53:23 +00001705 CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0)));
1706
1707 obj->SetInternalField(0, v8::External::Wrap(aligned));
Steve Block44f0eee2011-05-26 01:26:41 +01001708 HEAP->CollectAllGarbage(false);
Steve Block3ce2e202009-11-05 08:53:23 +00001709 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1710
1711 obj->SetInternalField(0, v8::External::Wrap(unaligned));
Steve Block44f0eee2011-05-26 01:26:41 +01001712 HEAP->CollectAllGarbage(false);
Steve Block3ce2e202009-11-05 08:53:23 +00001713 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1714
1715 delete[] data;
1716}
1717
1718
Steve Blocka7e24c12009-10-30 11:49:00 +00001719THREADED_TEST(IdentityHash) {
1720 v8::HandleScope scope;
1721 LocalContext env;
1722
1723 // Ensure that the test starts with an fresh heap to test whether the hash
1724 // code is based on the address.
Steve Block44f0eee2011-05-26 01:26:41 +01001725 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +00001726 Local<v8::Object> obj = v8::Object::New();
1727 int hash = obj->GetIdentityHash();
1728 int hash1 = obj->GetIdentityHash();
1729 CHECK_EQ(hash, hash1);
1730 int hash2 = v8::Object::New()->GetIdentityHash();
1731 // Since the identity hash is essentially a random number two consecutive
1732 // objects should not be assigned the same hash code. If the test below fails
1733 // the random number generator should be evaluated.
1734 CHECK_NE(hash, hash2);
Steve Block44f0eee2011-05-26 01:26:41 +01001735 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +00001736 int hash3 = v8::Object::New()->GetIdentityHash();
1737 // Make sure that the identity hash is not based on the initial address of
1738 // the object alone. If the test below fails the random number generator
1739 // should be evaluated.
1740 CHECK_NE(hash, hash3);
1741 int hash4 = obj->GetIdentityHash();
1742 CHECK_EQ(hash, hash4);
Steve Block1e0659c2011-05-24 12:43:12 +01001743
1744 // Check identity hashes behaviour in the presence of JS accessors.
1745 // Put a getter for 'v8::IdentityHash' on the Object's prototype:
1746 {
1747 CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
1748 Local<v8::Object> o1 = v8::Object::New();
1749 Local<v8::Object> o2 = v8::Object::New();
1750 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
1751 }
1752 {
1753 CompileRun(
1754 "function cnst() { return 42; };\n"
1755 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
1756 Local<v8::Object> o1 = v8::Object::New();
1757 Local<v8::Object> o2 = v8::Object::New();
1758 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
1759 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001760}
1761
1762
1763THREADED_TEST(HiddenProperties) {
1764 v8::HandleScope scope;
1765 LocalContext env;
1766
1767 v8::Local<v8::Object> obj = v8::Object::New();
1768 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1769 v8::Local<v8::String> empty = v8_str("");
1770 v8::Local<v8::String> prop_name = v8_str("prop_name");
1771
Steve Block44f0eee2011-05-26 01:26:41 +01001772 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +00001773
1774 // Make sure delete of a non-existent hidden value works
1775 CHECK(obj->DeleteHiddenValue(key));
1776
1777 CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
1778 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
1779 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
1780 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1781
Steve Block44f0eee2011-05-26 01:26:41 +01001782 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +00001783
1784 // Make sure we do not find the hidden property.
1785 CHECK(!obj->Has(empty));
1786 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1787 CHECK(obj->Get(empty)->IsUndefined());
1788 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1789 CHECK(obj->Set(empty, v8::Integer::New(2003)));
1790 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1791 CHECK_EQ(2003, obj->Get(empty)->Int32Value());
1792
Steve Block44f0eee2011-05-26 01:26:41 +01001793 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +00001794
1795 // Add another property and delete it afterwards to force the object in
1796 // slow case.
1797 CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
1798 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1799 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
1800 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1801 CHECK(obj->Delete(prop_name));
1802 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1803
Steve Block44f0eee2011-05-26 01:26:41 +01001804 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +00001805
1806 CHECK(obj->DeleteHiddenValue(key));
1807 CHECK(obj->GetHiddenValue(key).IsEmpty());
1808}
1809
1810
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001811THREADED_TEST(Regress97784) {
1812 // Regression test for crbug.com/97784
1813 // Messing with the Object.prototype should not have effect on
1814 // hidden properties.
1815 v8::HandleScope scope;
1816 LocalContext env;
1817
1818 v8::Local<v8::Object> obj = v8::Object::New();
1819 v8::Local<v8::String> key = v8_str("hidden");
1820
1821 CompileRun(
1822 "set_called = false;"
1823 "Object.defineProperty("
1824 " Object.prototype,"
1825 " 'hidden',"
1826 " {get: function() { return 45; },"
1827 " set: function() { set_called = true; }})");
1828
1829 CHECK(obj->GetHiddenValue(key).IsEmpty());
1830 // Make sure that the getter and setter from Object.prototype is not invoked.
1831 // If it did we would have full access to the hidden properties in
1832 // the accessor.
1833 CHECK(obj->SetHiddenValue(key, v8::Integer::New(42)));
1834 ExpectFalse("set_called");
1835 CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
1836}
1837
1838
Steve Blockd0582a62009-12-15 09:54:21 +00001839static bool interceptor_for_hidden_properties_called;
Steve Blocka7e24c12009-10-30 11:49:00 +00001840static v8::Handle<Value> InterceptorForHiddenProperties(
1841 Local<String> name, const AccessorInfo& info) {
Steve Blockd0582a62009-12-15 09:54:21 +00001842 interceptor_for_hidden_properties_called = true;
Steve Blocka7e24c12009-10-30 11:49:00 +00001843 return v8::Handle<Value>();
1844}
1845
1846
1847THREADED_TEST(HiddenPropertiesWithInterceptors) {
1848 v8::HandleScope scope;
1849 LocalContext context;
1850
Steve Blockd0582a62009-12-15 09:54:21 +00001851 interceptor_for_hidden_properties_called = false;
1852
Steve Blocka7e24c12009-10-30 11:49:00 +00001853 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1854
1855 // Associate an interceptor with an object and start setting hidden values.
1856 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
1857 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
1858 instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
1859 Local<v8::Function> function = fun_templ->GetFunction();
1860 Local<v8::Object> obj = function->NewInstance();
1861 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
1862 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
Steve Blockd0582a62009-12-15 09:54:21 +00001863 CHECK(!interceptor_for_hidden_properties_called);
Steve Blocka7e24c12009-10-30 11:49:00 +00001864}
1865
1866
1867THREADED_TEST(External) {
1868 v8::HandleScope scope;
1869 int x = 3;
1870 Local<v8::External> ext = v8::External::New(&x);
1871 LocalContext env;
1872 env->Global()->Set(v8_str("ext"), ext);
1873 Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
Steve Block6ded16b2010-05-10 14:33:55 +01001874 v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
Steve Blocka7e24c12009-10-30 11:49:00 +00001875 int* ptr = static_cast<int*>(reext->Value());
1876 CHECK_EQ(x, 3);
1877 *ptr = 10;
1878 CHECK_EQ(x, 10);
1879
1880 // Make sure unaligned pointers are wrapped properly.
1881 char* data = i::StrDup("0123456789");
1882 Local<v8::Value> zero = v8::External::Wrap(&data[0]);
1883 Local<v8::Value> one = v8::External::Wrap(&data[1]);
1884 Local<v8::Value> two = v8::External::Wrap(&data[2]);
1885 Local<v8::Value> three = v8::External::Wrap(&data[3]);
1886
1887 char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero));
1888 CHECK_EQ('0', *char_ptr);
1889 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one));
1890 CHECK_EQ('1', *char_ptr);
1891 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two));
1892 CHECK_EQ('2', *char_ptr);
1893 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three));
1894 CHECK_EQ('3', *char_ptr);
1895 i::DeleteArray(data);
1896}
1897
1898
1899THREADED_TEST(GlobalHandle) {
1900 v8::Persistent<String> global;
1901 {
1902 v8::HandleScope scope;
1903 Local<String> str = v8_str("str");
1904 global = v8::Persistent<String>::New(str);
1905 }
1906 CHECK_EQ(global->Length(), 3);
1907 global.Dispose();
1908}
1909
1910
Steve Block44f0eee2011-05-26 01:26:41 +01001911static int NumberOfWeakCalls = 0;
1912static void WeakPointerCallback(Persistent<Value> handle, void* id) {
1913 CHECK_EQ(reinterpret_cast<void*>(1234), id);
1914 NumberOfWeakCalls++;
1915 handle.Dispose();
1916}
1917
1918THREADED_TEST(ApiObjectGroups) {
1919 HandleScope scope;
1920 LocalContext env;
1921
1922 NumberOfWeakCalls = 0;
1923
1924 Persistent<Object> g1s1;
1925 Persistent<Object> g1s2;
1926 Persistent<Object> g1c1;
1927 Persistent<Object> g2s1;
1928 Persistent<Object> g2s2;
1929 Persistent<Object> g2c1;
1930
1931 {
1932 HandleScope scope;
1933 g1s1 = Persistent<Object>::New(Object::New());
1934 g1s2 = Persistent<Object>::New(Object::New());
1935 g1c1 = Persistent<Object>::New(Object::New());
1936 g1s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1937 g1s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1938 g1c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1939
1940 g2s1 = Persistent<Object>::New(Object::New());
1941 g2s2 = Persistent<Object>::New(Object::New());
1942 g2c1 = Persistent<Object>::New(Object::New());
1943 g2s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1944 g2s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1945 g2c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1946 }
1947
1948 Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
1949
1950 // Connect group 1 and 2, make a cycle.
1951 CHECK(g1s2->Set(0, g2s2));
1952 CHECK(g2s1->Set(0, g1s1));
1953
1954 {
1955 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
1956 Persistent<Value> g1_children[] = { g1c1 };
1957 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
1958 Persistent<Value> g2_children[] = { g2c1 };
1959 V8::AddObjectGroup(g1_objects, 2);
1960 V8::AddImplicitReferences(g1s1, g1_children, 1);
1961 V8::AddObjectGroup(g2_objects, 2);
1962 V8::AddImplicitReferences(g2s2, g2_children, 1);
1963 }
1964 // Do a full GC
1965 HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
1966
1967 // All object should be alive.
1968 CHECK_EQ(0, NumberOfWeakCalls);
1969
1970 // Weaken the root.
1971 root.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1972 // But make children strong roots---all the objects (except for children)
1973 // should be collectable now.
1974 g1c1.ClearWeak();
1975 g2c1.ClearWeak();
1976
1977 // Groups are deleted, rebuild groups.
1978 {
1979 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
1980 Persistent<Value> g1_children[] = { g1c1 };
1981 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
1982 Persistent<Value> g2_children[] = { g2c1 };
1983 V8::AddObjectGroup(g1_objects, 2);
1984 V8::AddImplicitReferences(g1s1, g1_children, 1);
1985 V8::AddObjectGroup(g2_objects, 2);
1986 V8::AddImplicitReferences(g2s2, g2_children, 1);
1987 }
1988
1989 HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
1990
1991 // All objects should be gone. 5 global handles in total.
1992 CHECK_EQ(5, NumberOfWeakCalls);
1993
1994 // And now make children weak again and collect them.
1995 g1c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1996 g2c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1997
1998 HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
1999 CHECK_EQ(7, NumberOfWeakCalls);
2000}
2001
2002
2003THREADED_TEST(ApiObjectGroupsCycle) {
2004 HandleScope scope;
2005 LocalContext env;
2006
2007 NumberOfWeakCalls = 0;
2008
2009 Persistent<Object> g1s1;
2010 Persistent<Object> g1s2;
2011 Persistent<Object> g2s1;
2012 Persistent<Object> g2s2;
2013 Persistent<Object> g3s1;
2014 Persistent<Object> g3s2;
2015
2016 {
2017 HandleScope scope;
2018 g1s1 = Persistent<Object>::New(Object::New());
2019 g1s2 = Persistent<Object>::New(Object::New());
2020 g1s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
2021 g1s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
2022
2023 g2s1 = Persistent<Object>::New(Object::New());
2024 g2s2 = Persistent<Object>::New(Object::New());
2025 g2s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
2026 g2s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
2027
2028 g3s1 = Persistent<Object>::New(Object::New());
2029 g3s2 = Persistent<Object>::New(Object::New());
2030 g3s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
2031 g3s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
2032 }
2033
2034 Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
2035
2036 // Connect groups. We're building the following cycle:
2037 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
2038 // groups.
2039 {
2040 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2041 Persistent<Value> g1_children[] = { g2s1 };
2042 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2043 Persistent<Value> g2_children[] = { g3s1 };
2044 Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2045 Persistent<Value> g3_children[] = { g1s1 };
2046 V8::AddObjectGroup(g1_objects, 2);
2047 V8::AddImplicitReferences(g1s1, g1_children, 1);
2048 V8::AddObjectGroup(g2_objects, 2);
2049 V8::AddImplicitReferences(g2s1, g2_children, 1);
2050 V8::AddObjectGroup(g3_objects, 2);
2051 V8::AddImplicitReferences(g3s1, g3_children, 1);
2052 }
2053 // Do a full GC
2054 HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
2055
2056 // All object should be alive.
2057 CHECK_EQ(0, NumberOfWeakCalls);
2058
2059 // Weaken the root.
2060 root.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
2061
2062 // Groups are deleted, rebuild groups.
2063 {
2064 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2065 Persistent<Value> g1_children[] = { g2s1 };
2066 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2067 Persistent<Value> g2_children[] = { g3s1 };
2068 Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2069 Persistent<Value> g3_children[] = { g1s1 };
2070 V8::AddObjectGroup(g1_objects, 2);
2071 V8::AddImplicitReferences(g1s1, g1_children, 1);
2072 V8::AddObjectGroup(g2_objects, 2);
2073 V8::AddImplicitReferences(g2s1, g2_children, 1);
2074 V8::AddObjectGroup(g3_objects, 2);
2075 V8::AddImplicitReferences(g3s1, g3_children, 1);
2076 }
2077
2078 HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
2079
2080 // All objects should be gone. 7 global handles in total.
2081 CHECK_EQ(7, NumberOfWeakCalls);
2082}
2083
2084
Steve Blocka7e24c12009-10-30 11:49:00 +00002085THREADED_TEST(ScriptException) {
2086 v8::HandleScope scope;
2087 LocalContext env;
2088 Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
2089 v8::TryCatch try_catch;
2090 Local<Value> result = script->Run();
2091 CHECK(result.IsEmpty());
2092 CHECK(try_catch.HasCaught());
2093 String::AsciiValue exception_value(try_catch.Exception());
2094 CHECK_EQ(*exception_value, "panama!");
2095}
2096
2097
2098bool message_received;
2099
2100
2101static void check_message(v8::Handle<v8::Message> message,
2102 v8::Handle<Value> data) {
2103 CHECK_EQ(5.76, data->NumberValue());
2104 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
2105 CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
2106 message_received = true;
2107}
2108
2109
2110THREADED_TEST(MessageHandlerData) {
2111 message_received = false;
2112 v8::HandleScope scope;
2113 CHECK(!message_received);
2114 v8::V8::AddMessageListener(check_message, v8_num(5.76));
2115 LocalContext context;
2116 v8::ScriptOrigin origin =
2117 v8::ScriptOrigin(v8_str("6.75"));
2118 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
2119 &origin);
2120 script->SetData(v8_str("7.56"));
2121 script->Run();
2122 CHECK(message_received);
2123 // clear out the message listener
2124 v8::V8::RemoveMessageListeners(check_message);
2125}
2126
2127
2128THREADED_TEST(GetSetProperty) {
2129 v8::HandleScope scope;
2130 LocalContext context;
2131 context->Global()->Set(v8_str("foo"), v8_num(14));
2132 context->Global()->Set(v8_str("12"), v8_num(92));
2133 context->Global()->Set(v8::Integer::New(16), v8_num(32));
2134 context->Global()->Set(v8_num(13), v8_num(56));
2135 Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
2136 CHECK_EQ(14, foo->Int32Value());
2137 Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
2138 CHECK_EQ(92, twelve->Int32Value());
2139 Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
2140 CHECK_EQ(32, sixteen->Int32Value());
2141 Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
2142 CHECK_EQ(56, thirteen->Int32Value());
2143 CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
2144 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
2145 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
2146 CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
2147 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
2148 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
2149 CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
2150 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
2151 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
2152}
2153
2154
2155THREADED_TEST(PropertyAttributes) {
2156 v8::HandleScope scope;
2157 LocalContext context;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002158 // none
2159 Local<String> prop = v8_str("none");
2160 context->Global()->Set(prop, v8_num(7));
2161 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
Steve Blocka7e24c12009-10-30 11:49:00 +00002162 // read-only
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002163 prop = v8_str("read_only");
Steve Blocka7e24c12009-10-30 11:49:00 +00002164 context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
2165 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002166 CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
Steve Blocka7e24c12009-10-30 11:49:00 +00002167 Script::Compile(v8_str("read_only = 9"))->Run();
2168 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2169 context->Global()->Set(prop, v8_num(10));
2170 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2171 // dont-delete
2172 prop = v8_str("dont_delete");
2173 context->Global()->Set(prop, v8_num(13), v8::DontDelete);
2174 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
2175 Script::Compile(v8_str("delete dont_delete"))->Run();
2176 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002177 CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
2178 // dont-enum
2179 prop = v8_str("dont_enum");
2180 context->Global()->Set(prop, v8_num(28), v8::DontEnum);
2181 CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
2182 // absent
2183 prop = v8_str("absent");
2184 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
2185 Local<Value> fake_prop = v8_num(1);
2186 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
2187 // exception
2188 TryCatch try_catch;
2189 Local<Value> exception =
2190 CompileRun("({ toString: function() { throw 'exception';} })");
2191 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
2192 CHECK(try_catch.HasCaught());
2193 String::AsciiValue exception_value(try_catch.Exception());
2194 CHECK_EQ("exception", *exception_value);
2195 try_catch.Reset();
Steve Blocka7e24c12009-10-30 11:49:00 +00002196}
2197
2198
2199THREADED_TEST(Array) {
2200 v8::HandleScope scope;
2201 LocalContext context;
2202 Local<v8::Array> array = v8::Array::New();
2203 CHECK_EQ(0, array->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01002204 CHECK(array->Get(0)->IsUndefined());
Steve Blocka7e24c12009-10-30 11:49:00 +00002205 CHECK(!array->Has(0));
Steve Block6ded16b2010-05-10 14:33:55 +01002206 CHECK(array->Get(100)->IsUndefined());
Steve Blocka7e24c12009-10-30 11:49:00 +00002207 CHECK(!array->Has(100));
Steve Block6ded16b2010-05-10 14:33:55 +01002208 array->Set(2, v8_num(7));
Steve Blocka7e24c12009-10-30 11:49:00 +00002209 CHECK_EQ(3, array->Length());
2210 CHECK(!array->Has(0));
2211 CHECK(!array->Has(1));
2212 CHECK(array->Has(2));
Steve Block6ded16b2010-05-10 14:33:55 +01002213 CHECK_EQ(7, array->Get(2)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00002214 Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
Steve Block6ded16b2010-05-10 14:33:55 +01002215 Local<v8::Array> arr = obj.As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00002216 CHECK_EQ(3, arr->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01002217 CHECK_EQ(1, arr->Get(0)->Int32Value());
2218 CHECK_EQ(2, arr->Get(1)->Int32Value());
2219 CHECK_EQ(3, arr->Get(2)->Int32Value());
Steve Block44f0eee2011-05-26 01:26:41 +01002220 array = v8::Array::New(27);
2221 CHECK_EQ(27, array->Length());
2222 array = v8::Array::New(-27);
2223 CHECK_EQ(0, array->Length());
Steve Blocka7e24c12009-10-30 11:49:00 +00002224}
2225
2226
2227v8::Handle<Value> HandleF(const v8::Arguments& args) {
2228 v8::HandleScope scope;
2229 ApiTestFuzzer::Fuzz();
2230 Local<v8::Array> result = v8::Array::New(args.Length());
2231 for (int i = 0; i < args.Length(); i++)
Steve Block6ded16b2010-05-10 14:33:55 +01002232 result->Set(i, args[i]);
Steve Blocka7e24c12009-10-30 11:49:00 +00002233 return scope.Close(result);
2234}
2235
2236
2237THREADED_TEST(Vector) {
2238 v8::HandleScope scope;
2239 Local<ObjectTemplate> global = ObjectTemplate::New();
2240 global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
2241 LocalContext context(0, global);
2242
2243 const char* fun = "f()";
Steve Block6ded16b2010-05-10 14:33:55 +01002244 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00002245 CHECK_EQ(0, a0->Length());
2246
2247 const char* fun2 = "f(11)";
Steve Block6ded16b2010-05-10 14:33:55 +01002248 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00002249 CHECK_EQ(1, a1->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01002250 CHECK_EQ(11, a1->Get(0)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00002251
2252 const char* fun3 = "f(12, 13)";
Steve Block6ded16b2010-05-10 14:33:55 +01002253 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00002254 CHECK_EQ(2, a2->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01002255 CHECK_EQ(12, a2->Get(0)->Int32Value());
2256 CHECK_EQ(13, a2->Get(1)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00002257
2258 const char* fun4 = "f(14, 15, 16)";
Steve Block6ded16b2010-05-10 14:33:55 +01002259 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00002260 CHECK_EQ(3, a3->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01002261 CHECK_EQ(14, a3->Get(0)->Int32Value());
2262 CHECK_EQ(15, a3->Get(1)->Int32Value());
2263 CHECK_EQ(16, a3->Get(2)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00002264
2265 const char* fun5 = "f(17, 18, 19, 20)";
Steve Block6ded16b2010-05-10 14:33:55 +01002266 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00002267 CHECK_EQ(4, a4->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01002268 CHECK_EQ(17, a4->Get(0)->Int32Value());
2269 CHECK_EQ(18, a4->Get(1)->Int32Value());
2270 CHECK_EQ(19, a4->Get(2)->Int32Value());
2271 CHECK_EQ(20, a4->Get(3)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00002272}
2273
2274
2275THREADED_TEST(FunctionCall) {
2276 v8::HandleScope scope;
2277 LocalContext context;
2278 CompileRun(
2279 "function Foo() {"
2280 " var result = [];"
2281 " for (var i = 0; i < arguments.length; i++) {"
2282 " result.push(arguments[i]);"
2283 " }"
2284 " return result;"
2285 "}");
2286 Local<Function> Foo =
2287 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2288
2289 v8::Handle<Value>* args0 = NULL;
2290 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
2291 CHECK_EQ(0, a0->Length());
2292
2293 v8::Handle<Value> args1[] = { v8_num(1.1) };
2294 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
2295 CHECK_EQ(1, a1->Length());
2296 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2297
2298 v8::Handle<Value> args2[] = { v8_num(2.2),
2299 v8_num(3.3) };
2300 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
2301 CHECK_EQ(2, a2->Length());
2302 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2303 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2304
2305 v8::Handle<Value> args3[] = { v8_num(4.4),
2306 v8_num(5.5),
2307 v8_num(6.6) };
2308 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
2309 CHECK_EQ(3, a3->Length());
2310 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2311 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2312 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2313
2314 v8::Handle<Value> args4[] = { v8_num(7.7),
2315 v8_num(8.8),
2316 v8_num(9.9),
2317 v8_num(10.11) };
2318 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
2319 CHECK_EQ(4, a4->Length());
2320 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2321 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2322 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2323 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2324}
2325
2326
2327static const char* js_code_causing_out_of_memory =
2328 "var a = new Array(); while(true) a.push(a);";
2329
2330
2331// These tests run for a long time and prevent us from running tests
2332// that come after them so they cannot run in parallel.
2333TEST(OutOfMemory) {
2334 // It's not possible to read a snapshot into a heap with different dimensions.
Steve Block8defd9f2010-07-08 12:39:36 +01002335 if (i::Snapshot::IsEnabled()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00002336 // Set heap limits.
2337 static const int K = 1024;
2338 v8::ResourceConstraints constraints;
2339 constraints.set_max_young_space_size(256 * K);
2340 constraints.set_max_old_space_size(4 * K * K);
2341 v8::SetResourceConstraints(&constraints);
2342
2343 // Execute a script that causes out of memory.
2344 v8::HandleScope scope;
2345 LocalContext context;
2346 v8::V8::IgnoreOutOfMemoryException();
2347 Local<Script> script =
2348 Script::Compile(String::New(js_code_causing_out_of_memory));
2349 Local<Value> result = script->Run();
2350
2351 // Check for out of memory state.
2352 CHECK(result.IsEmpty());
2353 CHECK(context->HasOutOfMemoryException());
2354}
2355
2356
2357v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
2358 ApiTestFuzzer::Fuzz();
2359
2360 v8::HandleScope scope;
2361 LocalContext context;
2362 Local<Script> script =
2363 Script::Compile(String::New(js_code_causing_out_of_memory));
2364 Local<Value> result = script->Run();
2365
2366 // Check for out of memory state.
2367 CHECK(result.IsEmpty());
2368 CHECK(context->HasOutOfMemoryException());
2369
2370 return result;
2371}
2372
2373
2374TEST(OutOfMemoryNested) {
2375 // It's not possible to read a snapshot into a heap with different dimensions.
Steve Block8defd9f2010-07-08 12:39:36 +01002376 if (i::Snapshot::IsEnabled()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00002377 // Set heap limits.
2378 static const int K = 1024;
2379 v8::ResourceConstraints constraints;
2380 constraints.set_max_young_space_size(256 * K);
2381 constraints.set_max_old_space_size(4 * K * K);
2382 v8::SetResourceConstraints(&constraints);
2383
2384 v8::HandleScope scope;
2385 Local<ObjectTemplate> templ = ObjectTemplate::New();
2386 templ->Set(v8_str("ProvokeOutOfMemory"),
2387 v8::FunctionTemplate::New(ProvokeOutOfMemory));
2388 LocalContext context(0, templ);
2389 v8::V8::IgnoreOutOfMemoryException();
2390 Local<Value> result = CompileRun(
2391 "var thrown = false;"
2392 "try {"
2393 " ProvokeOutOfMemory();"
2394 "} catch (e) {"
2395 " thrown = true;"
2396 "}");
2397 // Check for out of memory state.
2398 CHECK(result.IsEmpty());
2399 CHECK(context->HasOutOfMemoryException());
2400}
2401
2402
2403TEST(HugeConsStringOutOfMemory) {
2404 // It's not possible to read a snapshot into a heap with different dimensions.
Steve Block8defd9f2010-07-08 12:39:36 +01002405 if (i::Snapshot::IsEnabled()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00002406 // Set heap limits.
2407 static const int K = 1024;
2408 v8::ResourceConstraints constraints;
2409 constraints.set_max_young_space_size(256 * K);
2410 constraints.set_max_old_space_size(2 * K * K);
2411 v8::SetResourceConstraints(&constraints);
2412
2413 // Execute a script that causes out of memory.
2414 v8::V8::IgnoreOutOfMemoryException();
2415
Steve Block44f0eee2011-05-26 01:26:41 +01002416 v8::HandleScope scope;
2417 LocalContext context;
2418
Steve Blocka7e24c12009-10-30 11:49:00 +00002419 // Build huge string. This should fail with out of memory exception.
2420 Local<Value> result = CompileRun(
2421 "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
Steve Block3ce2e202009-11-05 08:53:23 +00002422 "for (var i = 0; i < 22; i++) { str = str + str; }");
Steve Blocka7e24c12009-10-30 11:49:00 +00002423
2424 // Check for out of memory state.
2425 CHECK(result.IsEmpty());
2426 CHECK(context->HasOutOfMemoryException());
2427}
2428
2429
2430THREADED_TEST(ConstructCall) {
2431 v8::HandleScope scope;
2432 LocalContext context;
2433 CompileRun(
2434 "function Foo() {"
2435 " var result = [];"
2436 " for (var i = 0; i < arguments.length; i++) {"
2437 " result.push(arguments[i]);"
2438 " }"
2439 " return result;"
2440 "}");
2441 Local<Function> Foo =
2442 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2443
2444 v8::Handle<Value>* args0 = NULL;
2445 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
2446 CHECK_EQ(0, a0->Length());
2447
2448 v8::Handle<Value> args1[] = { v8_num(1.1) };
2449 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
2450 CHECK_EQ(1, a1->Length());
2451 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2452
2453 v8::Handle<Value> args2[] = { v8_num(2.2),
2454 v8_num(3.3) };
2455 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
2456 CHECK_EQ(2, a2->Length());
2457 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2458 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2459
2460 v8::Handle<Value> args3[] = { v8_num(4.4),
2461 v8_num(5.5),
2462 v8_num(6.6) };
2463 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
2464 CHECK_EQ(3, a3->Length());
2465 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2466 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2467 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2468
2469 v8::Handle<Value> args4[] = { v8_num(7.7),
2470 v8_num(8.8),
2471 v8_num(9.9),
2472 v8_num(10.11) };
2473 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
2474 CHECK_EQ(4, a4->Length());
2475 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2476 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2477 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2478 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2479}
2480
2481
2482static void CheckUncle(v8::TryCatch* try_catch) {
2483 CHECK(try_catch->HasCaught());
2484 String::AsciiValue str_value(try_catch->Exception());
2485 CHECK_EQ(*str_value, "uncle?");
2486 try_catch->Reset();
2487}
2488
2489
Steve Block6ded16b2010-05-10 14:33:55 +01002490THREADED_TEST(ConversionNumber) {
2491 v8::HandleScope scope;
2492 LocalContext env;
2493 // Very large number.
2494 CompileRun("var obj = Math.pow(2,32) * 1237;");
2495 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2496 CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
2497 CHECK_EQ(0, obj->ToInt32()->Value());
2498 CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned.
2499 // Large number.
2500 CompileRun("var obj = -1234567890123;");
2501 obj = env->Global()->Get(v8_str("obj"));
2502 CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
2503 CHECK_EQ(-1912276171, obj->ToInt32()->Value());
2504 CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT
2505 // Small positive integer.
2506 CompileRun("var obj = 42;");
2507 obj = env->Global()->Get(v8_str("obj"));
2508 CHECK_EQ(42.0, obj->ToNumber()->Value());
2509 CHECK_EQ(42, obj->ToInt32()->Value());
2510 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
2511 // Negative integer.
2512 CompileRun("var obj = -37;");
2513 obj = env->Global()->Get(v8_str("obj"));
2514 CHECK_EQ(-37.0, obj->ToNumber()->Value());
2515 CHECK_EQ(-37, obj->ToInt32()->Value());
2516 CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT
2517 // Positive non-int32 integer.
2518 CompileRun("var obj = 0x81234567;");
2519 obj = env->Global()->Get(v8_str("obj"));
2520 CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
2521 CHECK_EQ(-2128394905, obj->ToInt32()->Value());
2522 CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT
2523 // Fraction.
2524 CompileRun("var obj = 42.3;");
2525 obj = env->Global()->Get(v8_str("obj"));
2526 CHECK_EQ(42.3, obj->ToNumber()->Value());
2527 CHECK_EQ(42, obj->ToInt32()->Value());
2528 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
2529 // Large negative fraction.
2530 CompileRun("var obj = -5726623061.75;");
2531 obj = env->Global()->Get(v8_str("obj"));
2532 CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
2533 CHECK_EQ(-1431655765, obj->ToInt32()->Value());
2534 CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT
2535}
2536
2537
2538THREADED_TEST(isNumberType) {
2539 v8::HandleScope scope;
2540 LocalContext env;
2541 // Very large number.
2542 CompileRun("var obj = Math.pow(2,32) * 1237;");
2543 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2544 CHECK(!obj->IsInt32());
2545 CHECK(!obj->IsUint32());
2546 // Large negative number.
2547 CompileRun("var obj = -1234567890123;");
2548 obj = env->Global()->Get(v8_str("obj"));
2549 CHECK(!obj->IsInt32());
2550 CHECK(!obj->IsUint32());
2551 // Small positive integer.
2552 CompileRun("var obj = 42;");
2553 obj = env->Global()->Get(v8_str("obj"));
2554 CHECK(obj->IsInt32());
2555 CHECK(obj->IsUint32());
2556 // Negative integer.
2557 CompileRun("var obj = -37;");
2558 obj = env->Global()->Get(v8_str("obj"));
2559 CHECK(obj->IsInt32());
2560 CHECK(!obj->IsUint32());
2561 // Positive non-int32 integer.
2562 CompileRun("var obj = 0x81234567;");
2563 obj = env->Global()->Get(v8_str("obj"));
2564 CHECK(!obj->IsInt32());
2565 CHECK(obj->IsUint32());
2566 // Fraction.
2567 CompileRun("var obj = 42.3;");
2568 obj = env->Global()->Get(v8_str("obj"));
2569 CHECK(!obj->IsInt32());
2570 CHECK(!obj->IsUint32());
2571 // Large negative fraction.
2572 CompileRun("var obj = -5726623061.75;");
2573 obj = env->Global()->Get(v8_str("obj"));
2574 CHECK(!obj->IsInt32());
2575 CHECK(!obj->IsUint32());
2576}
2577
2578
Steve Blocka7e24c12009-10-30 11:49:00 +00002579THREADED_TEST(ConversionException) {
2580 v8::HandleScope scope;
2581 LocalContext env;
2582 CompileRun(
2583 "function TestClass() { };"
2584 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
2585 "var obj = new TestClass();");
2586 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2587
2588 v8::TryCatch try_catch;
2589
2590 Local<Value> to_string_result = obj->ToString();
2591 CHECK(to_string_result.IsEmpty());
2592 CheckUncle(&try_catch);
2593
2594 Local<Value> to_number_result = obj->ToNumber();
2595 CHECK(to_number_result.IsEmpty());
2596 CheckUncle(&try_catch);
2597
2598 Local<Value> to_integer_result = obj->ToInteger();
2599 CHECK(to_integer_result.IsEmpty());
2600 CheckUncle(&try_catch);
2601
2602 Local<Value> to_uint32_result = obj->ToUint32();
2603 CHECK(to_uint32_result.IsEmpty());
2604 CheckUncle(&try_catch);
2605
2606 Local<Value> to_int32_result = obj->ToInt32();
2607 CHECK(to_int32_result.IsEmpty());
2608 CheckUncle(&try_catch);
2609
2610 Local<Value> to_object_result = v8::Undefined()->ToObject();
2611 CHECK(to_object_result.IsEmpty());
2612 CHECK(try_catch.HasCaught());
2613 try_catch.Reset();
2614
2615 int32_t int32_value = obj->Int32Value();
2616 CHECK_EQ(0, int32_value);
2617 CheckUncle(&try_catch);
2618
2619 uint32_t uint32_value = obj->Uint32Value();
2620 CHECK_EQ(0, uint32_value);
2621 CheckUncle(&try_catch);
2622
2623 double number_value = obj->NumberValue();
2624 CHECK_NE(0, IsNaN(number_value));
2625 CheckUncle(&try_catch);
2626
2627 int64_t integer_value = obj->IntegerValue();
2628 CHECK_EQ(0.0, static_cast<double>(integer_value));
2629 CheckUncle(&try_catch);
2630}
2631
2632
2633v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
2634 ApiTestFuzzer::Fuzz();
2635 return v8::ThrowException(v8_str("konto"));
2636}
2637
2638
2639v8::Handle<Value> CCatcher(const v8::Arguments& args) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002640 if (args.Length() < 1) return v8::False();
Steve Blocka7e24c12009-10-30 11:49:00 +00002641 v8::HandleScope scope;
2642 v8::TryCatch try_catch;
2643 Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
2644 CHECK(!try_catch.HasCaught() || result.IsEmpty());
2645 return v8::Boolean::New(try_catch.HasCaught());
2646}
2647
2648
2649THREADED_TEST(APICatch) {
2650 v8::HandleScope scope;
2651 Local<ObjectTemplate> templ = ObjectTemplate::New();
2652 templ->Set(v8_str("ThrowFromC"),
2653 v8::FunctionTemplate::New(ThrowFromC));
2654 LocalContext context(0, templ);
2655 CompileRun(
2656 "var thrown = false;"
2657 "try {"
2658 " ThrowFromC();"
2659 "} catch (e) {"
2660 " thrown = true;"
2661 "}");
2662 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
2663 CHECK(thrown->BooleanValue());
2664}
2665
2666
2667THREADED_TEST(APIThrowTryCatch) {
2668 v8::HandleScope scope;
2669 Local<ObjectTemplate> templ = ObjectTemplate::New();
2670 templ->Set(v8_str("ThrowFromC"),
2671 v8::FunctionTemplate::New(ThrowFromC));
2672 LocalContext context(0, templ);
2673 v8::TryCatch try_catch;
2674 CompileRun("ThrowFromC();");
2675 CHECK(try_catch.HasCaught());
2676}
2677
2678
2679// Test that a try-finally block doesn't shadow a try-catch block
2680// when setting up an external handler.
2681//
2682// BUG(271): Some of the exception propagation does not work on the
2683// ARM simulator because the simulator separates the C++ stack and the
2684// JS stack. This test therefore fails on the simulator. The test is
2685// not threaded to allow the threading tests to run on the simulator.
2686TEST(TryCatchInTryFinally) {
2687 v8::HandleScope scope;
2688 Local<ObjectTemplate> templ = ObjectTemplate::New();
2689 templ->Set(v8_str("CCatcher"),
2690 v8::FunctionTemplate::New(CCatcher));
2691 LocalContext context(0, templ);
2692 Local<Value> result = CompileRun("try {"
2693 " try {"
2694 " CCatcher('throw 7;');"
2695 " } finally {"
2696 " }"
2697 "} catch (e) {"
2698 "}");
2699 CHECK(result->IsTrue());
2700}
2701
2702
Ben Murdochb8e0da22011-05-16 14:20:40 +01002703static void check_reference_error_message(
2704 v8::Handle<v8::Message> message,
2705 v8::Handle<v8::Value> data) {
2706 const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
2707 CHECK(message->Get()->Equals(v8_str(reference_error)));
2708}
2709
2710
Steve Block1e0659c2011-05-24 12:43:12 +01002711static v8::Handle<Value> Fail(const v8::Arguments& args) {
2712 ApiTestFuzzer::Fuzz();
2713 CHECK(false);
2714 return v8::Undefined();
2715}
2716
2717
2718// Test that overwritten methods are not invoked on uncaught exception
2719// formatting. However, they are invoked when performing normal error
2720// string conversions.
Ben Murdochb8e0da22011-05-16 14:20:40 +01002721TEST(APIThrowMessageOverwrittenToString) {
2722 v8::HandleScope scope;
2723 v8::V8::AddMessageListener(check_reference_error_message);
Steve Block1e0659c2011-05-24 12:43:12 +01002724 Local<ObjectTemplate> templ = ObjectTemplate::New();
2725 templ->Set(v8_str("fail"), v8::FunctionTemplate::New(Fail));
2726 LocalContext context(NULL, templ);
2727 CompileRun("asdf;");
2728 CompileRun("var limit = {};"
2729 "limit.valueOf = fail;"
2730 "Error.stackTraceLimit = limit;");
2731 CompileRun("asdf");
2732 CompileRun("Array.prototype.pop = fail;");
2733 CompileRun("Object.prototype.hasOwnProperty = fail;");
2734 CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
2735 CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
2736 CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
Ben Murdochb8e0da22011-05-16 14:20:40 +01002737 CompileRun("ReferenceError.prototype.toString ="
2738 " function() { return 'Whoops' }");
2739 CompileRun("asdf;");
Steve Block1e0659c2011-05-24 12:43:12 +01002740 CompileRun("ReferenceError.prototype.constructor.name = void 0;");
2741 CompileRun("asdf;");
2742 CompileRun("ReferenceError.prototype.constructor = void 0;");
2743 CompileRun("asdf;");
2744 CompileRun("ReferenceError.prototype.__proto__ = new Object();");
2745 CompileRun("asdf;");
2746 CompileRun("ReferenceError.prototype = new Object();");
2747 CompileRun("asdf;");
Ben Murdochb8e0da22011-05-16 14:20:40 +01002748 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
2749 CHECK(string->Equals(v8_str("Whoops")));
Steve Block1e0659c2011-05-24 12:43:12 +01002750 CompileRun("ReferenceError.prototype.constructor = new Object();"
2751 "ReferenceError.prototype.constructor.name = 1;"
2752 "Number.prototype.toString = function() { return 'Whoops'; };"
2753 "ReferenceError.prototype.toString = Object.prototype.toString;");
2754 CompileRun("asdf;");
Ben Murdochb8e0da22011-05-16 14:20:40 +01002755 v8::V8::RemoveMessageListeners(check_message);
2756}
2757
2758
Steve Blocka7e24c12009-10-30 11:49:00 +00002759static void receive_message(v8::Handle<v8::Message> message,
2760 v8::Handle<v8::Value> data) {
2761 message->Get();
2762 message_received = true;
2763}
2764
2765
2766TEST(APIThrowMessage) {
2767 message_received = false;
2768 v8::HandleScope scope;
2769 v8::V8::AddMessageListener(receive_message);
2770 Local<ObjectTemplate> templ = ObjectTemplate::New();
2771 templ->Set(v8_str("ThrowFromC"),
2772 v8::FunctionTemplate::New(ThrowFromC));
2773 LocalContext context(0, templ);
2774 CompileRun("ThrowFromC();");
2775 CHECK(message_received);
2776 v8::V8::RemoveMessageListeners(check_message);
2777}
2778
2779
2780TEST(APIThrowMessageAndVerboseTryCatch) {
2781 message_received = false;
2782 v8::HandleScope scope;
2783 v8::V8::AddMessageListener(receive_message);
2784 Local<ObjectTemplate> templ = ObjectTemplate::New();
2785 templ->Set(v8_str("ThrowFromC"),
2786 v8::FunctionTemplate::New(ThrowFromC));
2787 LocalContext context(0, templ);
2788 v8::TryCatch try_catch;
2789 try_catch.SetVerbose(true);
2790 Local<Value> result = CompileRun("ThrowFromC();");
2791 CHECK(try_catch.HasCaught());
2792 CHECK(result.IsEmpty());
2793 CHECK(message_received);
2794 v8::V8::RemoveMessageListeners(check_message);
2795}
2796
2797
Ben Murdoch8b112d22011-06-08 16:22:53 +01002798TEST(APIStackOverflowAndVerboseTryCatch) {
2799 message_received = false;
2800 v8::HandleScope scope;
2801 v8::V8::AddMessageListener(receive_message);
2802 LocalContext context;
2803 v8::TryCatch try_catch;
2804 try_catch.SetVerbose(true);
2805 Local<Value> result = CompileRun("function foo() { foo(); } foo();");
2806 CHECK(try_catch.HasCaught());
2807 CHECK(result.IsEmpty());
2808 CHECK(message_received);
2809 v8::V8::RemoveMessageListeners(receive_message);
2810}
2811
2812
Steve Blocka7e24c12009-10-30 11:49:00 +00002813THREADED_TEST(ExternalScriptException) {
2814 v8::HandleScope scope;
2815 Local<ObjectTemplate> templ = ObjectTemplate::New();
2816 templ->Set(v8_str("ThrowFromC"),
2817 v8::FunctionTemplate::New(ThrowFromC));
2818 LocalContext context(0, templ);
2819
2820 v8::TryCatch try_catch;
2821 Local<Script> script
2822 = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
2823 Local<Value> result = script->Run();
2824 CHECK(result.IsEmpty());
2825 CHECK(try_catch.HasCaught());
2826 String::AsciiValue exception_value(try_catch.Exception());
2827 CHECK_EQ("konto", *exception_value);
2828}
2829
2830
2831
2832v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
2833 ApiTestFuzzer::Fuzz();
2834 CHECK_EQ(4, args.Length());
2835 int count = args[0]->Int32Value();
2836 int cInterval = args[2]->Int32Value();
2837 if (count == 0) {
2838 return v8::ThrowException(v8_str("FromC"));
2839 } else {
2840 Local<v8::Object> global = Context::GetCurrent()->Global();
2841 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
2842 v8::Handle<Value> argv[] = { v8_num(count - 1),
2843 args[1],
2844 args[2],
2845 args[3] };
2846 if (count % cInterval == 0) {
2847 v8::TryCatch try_catch;
Steve Block6ded16b2010-05-10 14:33:55 +01002848 Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
Steve Blocka7e24c12009-10-30 11:49:00 +00002849 int expected = args[3]->Int32Value();
2850 if (try_catch.HasCaught()) {
2851 CHECK_EQ(expected, count);
2852 CHECK(result.IsEmpty());
Steve Block44f0eee2011-05-26 01:26:41 +01002853 CHECK(!i::Isolate::Current()->has_scheduled_exception());
Steve Blocka7e24c12009-10-30 11:49:00 +00002854 } else {
2855 CHECK_NE(expected, count);
2856 }
2857 return result;
2858 } else {
Steve Block6ded16b2010-05-10 14:33:55 +01002859 return fun.As<Function>()->Call(global, 4, argv);
Steve Blocka7e24c12009-10-30 11:49:00 +00002860 }
2861 }
2862}
2863
2864
2865v8::Handle<Value> JSCheck(const v8::Arguments& args) {
2866 ApiTestFuzzer::Fuzz();
2867 CHECK_EQ(3, args.Length());
2868 bool equality = args[0]->BooleanValue();
2869 int count = args[1]->Int32Value();
2870 int expected = args[2]->Int32Value();
2871 if (equality) {
2872 CHECK_EQ(count, expected);
2873 } else {
2874 CHECK_NE(count, expected);
2875 }
2876 return v8::Undefined();
2877}
2878
2879
2880THREADED_TEST(EvalInTryFinally) {
2881 v8::HandleScope scope;
2882 LocalContext context;
2883 v8::TryCatch try_catch;
2884 CompileRun("(function() {"
2885 " try {"
2886 " eval('asldkf (*&^&*^');"
2887 " } finally {"
2888 " return;"
2889 " }"
2890 "})()");
2891 CHECK(!try_catch.HasCaught());
2892}
2893
2894
2895// This test works by making a stack of alternating JavaScript and C
2896// activations. These activations set up exception handlers with regular
2897// intervals, one interval for C activations and another for JavaScript
2898// activations. When enough activations have been created an exception is
2899// thrown and we check that the right activation catches the exception and that
2900// no other activations do. The right activation is always the topmost one with
2901// a handler, regardless of whether it is in JavaScript or C.
2902//
2903// The notation used to describe a test case looks like this:
2904//
2905// *JS[4] *C[3] @JS[2] C[1] JS[0]
2906//
2907// Each entry is an activation, either JS or C. The index is the count at that
2908// level. Stars identify activations with exception handlers, the @ identifies
2909// the exception handler that should catch the exception.
2910//
2911// BUG(271): Some of the exception propagation does not work on the
2912// ARM simulator because the simulator separates the C++ stack and the
2913// JS stack. This test therefore fails on the simulator. The test is
2914// not threaded to allow the threading tests to run on the simulator.
2915TEST(ExceptionOrder) {
2916 v8::HandleScope scope;
2917 Local<ObjectTemplate> templ = ObjectTemplate::New();
2918 templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
2919 templ->Set(v8_str("CThrowCountDown"),
2920 v8::FunctionTemplate::New(CThrowCountDown));
2921 LocalContext context(0, templ);
2922 CompileRun(
2923 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
2924 " if (count == 0) throw 'FromJS';"
2925 " if (count % jsInterval == 0) {"
2926 " try {"
2927 " var value = CThrowCountDown(count - 1,"
2928 " jsInterval,"
2929 " cInterval,"
2930 " expected);"
2931 " check(false, count, expected);"
2932 " return value;"
2933 " } catch (e) {"
2934 " check(true, count, expected);"
2935 " }"
2936 " } else {"
2937 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
2938 " }"
2939 "}");
2940 Local<Function> fun =
2941 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
2942
2943 const int argc = 4;
2944 // count jsInterval cInterval expected
2945
2946 // *JS[4] *C[3] @JS[2] C[1] JS[0]
2947 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
2948 fun->Call(fun, argc, a0);
2949
2950 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
2951 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
2952 fun->Call(fun, argc, a1);
2953
2954 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
2955 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
2956 fun->Call(fun, argc, a2);
2957
2958 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
2959 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
2960 fun->Call(fun, argc, a3);
2961
2962 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
2963 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
2964 fun->Call(fun, argc, a4);
2965
2966 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
2967 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
2968 fun->Call(fun, argc, a5);
2969}
2970
2971
2972v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
2973 ApiTestFuzzer::Fuzz();
2974 CHECK_EQ(1, args.Length());
2975 return v8::ThrowException(args[0]);
2976}
2977
2978
2979THREADED_TEST(ThrowValues) {
2980 v8::HandleScope scope;
2981 Local<ObjectTemplate> templ = ObjectTemplate::New();
2982 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
2983 LocalContext context(0, templ);
2984 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
2985 "function Run(obj) {"
2986 " try {"
2987 " Throw(obj);"
2988 " } catch (e) {"
2989 " return e;"
2990 " }"
2991 " return 'no exception';"
2992 "}"
2993 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
2994 CHECK_EQ(5, result->Length());
2995 CHECK(result->Get(v8::Integer::New(0))->IsString());
2996 CHECK(result->Get(v8::Integer::New(1))->IsNumber());
2997 CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
2998 CHECK(result->Get(v8::Integer::New(2))->IsNumber());
2999 CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
3000 CHECK(result->Get(v8::Integer::New(3))->IsNull());
3001 CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
3002}
3003
3004
3005THREADED_TEST(CatchZero) {
3006 v8::HandleScope scope;
3007 LocalContext context;
3008 v8::TryCatch try_catch;
3009 CHECK(!try_catch.HasCaught());
3010 Script::Compile(v8_str("throw 10"))->Run();
3011 CHECK(try_catch.HasCaught());
3012 CHECK_EQ(10, try_catch.Exception()->Int32Value());
3013 try_catch.Reset();
3014 CHECK(!try_catch.HasCaught());
3015 Script::Compile(v8_str("throw 0"))->Run();
3016 CHECK(try_catch.HasCaught());
3017 CHECK_EQ(0, try_catch.Exception()->Int32Value());
3018}
3019
3020
3021THREADED_TEST(CatchExceptionFromWith) {
3022 v8::HandleScope scope;
3023 LocalContext context;
3024 v8::TryCatch try_catch;
3025 CHECK(!try_catch.HasCaught());
3026 Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
3027 CHECK(try_catch.HasCaught());
3028}
3029
3030
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003031THREADED_TEST(TryCatchAndFinallyHidingException) {
3032 v8::HandleScope scope;
3033 LocalContext context;
3034 v8::TryCatch try_catch;
3035 CHECK(!try_catch.HasCaught());
3036 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
3037 CompileRun("f({toString: function() { throw 42; }});");
3038 CHECK(!try_catch.HasCaught());
3039}
3040
3041
3042v8::Handle<v8::Value> WithTryCatch(const v8::Arguments& args) {
3043 v8::TryCatch try_catch;
3044 return v8::Undefined();
3045}
3046
3047
3048THREADED_TEST(TryCatchAndFinally) {
3049 v8::HandleScope scope;
3050 LocalContext context;
3051 context->Global()->Set(
3052 v8_str("native_with_try_catch"),
3053 v8::FunctionTemplate::New(WithTryCatch)->GetFunction());
3054 v8::TryCatch try_catch;
3055 CHECK(!try_catch.HasCaught());
3056 CompileRun(
3057 "try {\n"
3058 " throw new Error('a');\n"
3059 "} finally {\n"
3060 " native_with_try_catch();\n"
3061 "}\n");
3062 CHECK(try_catch.HasCaught());
3063}
3064
3065
Steve Blocka7e24c12009-10-30 11:49:00 +00003066THREADED_TEST(Equality) {
3067 v8::HandleScope scope;
3068 LocalContext context;
3069 // Check that equality works at all before relying on CHECK_EQ
3070 CHECK(v8_str("a")->Equals(v8_str("a")));
3071 CHECK(!v8_str("a")->Equals(v8_str("b")));
3072
3073 CHECK_EQ(v8_str("a"), v8_str("a"));
3074 CHECK_NE(v8_str("a"), v8_str("b"));
3075 CHECK_EQ(v8_num(1), v8_num(1));
3076 CHECK_EQ(v8_num(1.00), v8_num(1));
3077 CHECK_NE(v8_num(1), v8_num(2));
3078
3079 // Assume String is not symbol.
3080 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
3081 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
3082 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
3083 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
3084 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
3085 CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
3086 Local<Value> not_a_number = v8_num(i::OS::nan_value());
3087 CHECK(!not_a_number->StrictEquals(not_a_number));
3088 CHECK(v8::False()->StrictEquals(v8::False()));
3089 CHECK(!v8::False()->StrictEquals(v8::Undefined()));
3090
3091 v8::Handle<v8::Object> obj = v8::Object::New();
3092 v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
3093 CHECK(alias->StrictEquals(obj));
3094 alias.Dispose();
3095}
3096
3097
3098THREADED_TEST(MultiRun) {
3099 v8::HandleScope scope;
3100 LocalContext context;
3101 Local<Script> script = Script::Compile(v8_str("x"));
3102 for (int i = 0; i < 10; i++)
3103 script->Run();
3104}
3105
3106
3107static v8::Handle<Value> GetXValue(Local<String> name,
3108 const AccessorInfo& info) {
3109 ApiTestFuzzer::Fuzz();
3110 CHECK_EQ(info.Data(), v8_str("donut"));
3111 CHECK_EQ(name, v8_str("x"));
3112 return name;
3113}
3114
3115
3116THREADED_TEST(SimplePropertyRead) {
3117 v8::HandleScope scope;
3118 Local<ObjectTemplate> templ = ObjectTemplate::New();
3119 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3120 LocalContext context;
3121 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3122 Local<Script> script = Script::Compile(v8_str("obj.x"));
3123 for (int i = 0; i < 10; i++) {
3124 Local<Value> result = script->Run();
3125 CHECK_EQ(result, v8_str("x"));
3126 }
3127}
3128
Andrei Popescu31002712010-02-23 13:46:05 +00003129THREADED_TEST(DefinePropertyOnAPIAccessor) {
3130 v8::HandleScope scope;
3131 Local<ObjectTemplate> templ = ObjectTemplate::New();
3132 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3133 LocalContext context;
3134 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3135
3136 // Uses getOwnPropertyDescriptor to check the configurable status
3137 Local<Script> script_desc
Leon Clarkef7060e22010-06-03 12:02:55 +01003138 = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
Andrei Popescu31002712010-02-23 13:46:05 +00003139 "obj, 'x');"
3140 "prop.configurable;"));
3141 Local<Value> result = script_desc->Run();
3142 CHECK_EQ(result->BooleanValue(), true);
3143
3144 // Redefine get - but still configurable
3145 Local<Script> script_define
3146 = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
3147 " configurable: true };"
3148 "Object.defineProperty(obj, 'x', desc);"
3149 "obj.x"));
3150 result = script_define->Run();
3151 CHECK_EQ(result, v8_num(42));
3152
3153 // Check that the accessor is still configurable
3154 result = script_desc->Run();
3155 CHECK_EQ(result->BooleanValue(), true);
3156
3157 // Redefine to a non-configurable
3158 script_define
3159 = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
3160 " configurable: false };"
3161 "Object.defineProperty(obj, 'x', desc);"
3162 "obj.x"));
3163 result = script_define->Run();
3164 CHECK_EQ(result, v8_num(43));
3165 result = script_desc->Run();
3166 CHECK_EQ(result->BooleanValue(), false);
3167
3168 // Make sure that it is not possible to redefine again
3169 v8::TryCatch try_catch;
3170 result = script_define->Run();
3171 CHECK(try_catch.HasCaught());
3172 String::AsciiValue exception_value(try_catch.Exception());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003173 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
Andrei Popescu31002712010-02-23 13:46:05 +00003174}
3175
3176THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
3177 v8::HandleScope scope;
3178 Local<ObjectTemplate> templ = ObjectTemplate::New();
3179 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3180 LocalContext context;
3181 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3182
3183 Local<Script> script_desc = Script::Compile(v8_str("var prop ="
3184 "Object.getOwnPropertyDescriptor( "
3185 "obj, 'x');"
3186 "prop.configurable;"));
3187 Local<Value> result = script_desc->Run();
3188 CHECK_EQ(result->BooleanValue(), true);
3189
3190 Local<Script> script_define =
3191 Script::Compile(v8_str("var desc = {get: function(){return 42; },"
3192 " configurable: true };"
3193 "Object.defineProperty(obj, 'x', desc);"
3194 "obj.x"));
3195 result = script_define->Run();
3196 CHECK_EQ(result, v8_num(42));
3197
3198
3199 result = script_desc->Run();
3200 CHECK_EQ(result->BooleanValue(), true);
3201
3202
3203 script_define =
3204 Script::Compile(v8_str("var desc = {get: function(){return 43; },"
3205 " configurable: false };"
3206 "Object.defineProperty(obj, 'x', desc);"
3207 "obj.x"));
3208 result = script_define->Run();
3209 CHECK_EQ(result, v8_num(43));
3210 result = script_desc->Run();
3211
3212 CHECK_EQ(result->BooleanValue(), false);
3213
3214 v8::TryCatch try_catch;
3215 result = script_define->Run();
3216 CHECK(try_catch.HasCaught());
3217 String::AsciiValue exception_value(try_catch.Exception());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003218 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
Andrei Popescu31002712010-02-23 13:46:05 +00003219}
3220
3221
Leon Clarkef7060e22010-06-03 12:02:55 +01003222static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
3223 char const* name) {
3224 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
3225}
Andrei Popescu31002712010-02-23 13:46:05 +00003226
3227
Leon Clarkef7060e22010-06-03 12:02:55 +01003228THREADED_TEST(DefineAPIAccessorOnObject) {
3229 v8::HandleScope scope;
3230 Local<ObjectTemplate> templ = ObjectTemplate::New();
3231 LocalContext context;
3232
3233 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3234 CompileRun("var obj2 = {};");
3235
3236 CHECK(CompileRun("obj1.x")->IsUndefined());
3237 CHECK(CompileRun("obj2.x")->IsUndefined());
3238
3239 CHECK(GetGlobalProperty(&context, "obj1")->
3240 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3241
3242 ExpectString("obj1.x", "x");
3243 CHECK(CompileRun("obj2.x")->IsUndefined());
3244
3245 CHECK(GetGlobalProperty(&context, "obj2")->
3246 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3247
3248 ExpectString("obj1.x", "x");
3249 ExpectString("obj2.x", "x");
3250
3251 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3252 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3253
3254 CompileRun("Object.defineProperty(obj1, 'x',"
3255 "{ get: function() { return 'y'; }, configurable: true })");
3256
3257 ExpectString("obj1.x", "y");
3258 ExpectString("obj2.x", "x");
3259
3260 CompileRun("Object.defineProperty(obj2, 'x',"
3261 "{ get: function() { return 'y'; }, configurable: true })");
3262
3263 ExpectString("obj1.x", "y");
3264 ExpectString("obj2.x", "y");
3265
3266 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3267 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3268
3269 CHECK(GetGlobalProperty(&context, "obj1")->
3270 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3271 CHECK(GetGlobalProperty(&context, "obj2")->
3272 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3273
3274 ExpectString("obj1.x", "x");
3275 ExpectString("obj2.x", "x");
3276
3277 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3278 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3279
3280 // Define getters/setters, but now make them not configurable.
3281 CompileRun("Object.defineProperty(obj1, 'x',"
3282 "{ get: function() { return 'z'; }, configurable: false })");
3283 CompileRun("Object.defineProperty(obj2, 'x',"
3284 "{ get: function() { return 'z'; }, configurable: false })");
3285
3286 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3287 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3288
3289 ExpectString("obj1.x", "z");
3290 ExpectString("obj2.x", "z");
3291
3292 CHECK(!GetGlobalProperty(&context, "obj1")->
3293 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3294 CHECK(!GetGlobalProperty(&context, "obj2")->
3295 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3296
3297 ExpectString("obj1.x", "z");
3298 ExpectString("obj2.x", "z");
3299}
3300
3301
3302THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
3303 v8::HandleScope scope;
3304 Local<ObjectTemplate> templ = ObjectTemplate::New();
3305 LocalContext context;
3306
3307 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3308 CompileRun("var obj2 = {};");
3309
3310 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3311 v8_str("x"),
3312 GetXValue, NULL,
3313 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3314 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3315 v8_str("x"),
3316 GetXValue, NULL,
3317 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3318
3319 ExpectString("obj1.x", "x");
3320 ExpectString("obj2.x", "x");
3321
3322 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3323 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3324
3325 CHECK(!GetGlobalProperty(&context, "obj1")->
3326 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3327 CHECK(!GetGlobalProperty(&context, "obj2")->
3328 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3329
3330 {
3331 v8::TryCatch try_catch;
3332 CompileRun("Object.defineProperty(obj1, 'x',"
3333 "{get: function() { return 'func'; }})");
3334 CHECK(try_catch.HasCaught());
3335 String::AsciiValue exception_value(try_catch.Exception());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003336 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
Leon Clarkef7060e22010-06-03 12:02:55 +01003337 }
3338 {
3339 v8::TryCatch try_catch;
3340 CompileRun("Object.defineProperty(obj2, 'x',"
3341 "{get: function() { return 'func'; }})");
3342 CHECK(try_catch.HasCaught());
3343 String::AsciiValue exception_value(try_catch.Exception());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003344 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
Leon Clarkef7060e22010-06-03 12:02:55 +01003345 }
3346}
3347
3348
3349static v8::Handle<Value> Get239Value(Local<String> name,
3350 const AccessorInfo& info) {
3351 ApiTestFuzzer::Fuzz();
3352 CHECK_EQ(info.Data(), v8_str("donut"));
3353 CHECK_EQ(name, v8_str("239"));
3354 return name;
3355}
3356
3357
3358THREADED_TEST(ElementAPIAccessor) {
3359 v8::HandleScope scope;
3360 Local<ObjectTemplate> templ = ObjectTemplate::New();
3361 LocalContext context;
3362
3363 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3364 CompileRun("var obj2 = {};");
3365
3366 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3367 v8_str("239"),
3368 Get239Value, NULL,
3369 v8_str("donut")));
3370 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3371 v8_str("239"),
3372 Get239Value, NULL,
3373 v8_str("donut")));
3374
3375 ExpectString("obj1[239]", "239");
3376 ExpectString("obj2[239]", "239");
3377 ExpectString("obj1['239']", "239");
3378 ExpectString("obj2['239']", "239");
3379}
3380
Steve Blocka7e24c12009-10-30 11:49:00 +00003381
3382v8::Persistent<Value> xValue;
3383
3384
3385static void SetXValue(Local<String> name,
3386 Local<Value> value,
3387 const AccessorInfo& info) {
3388 CHECK_EQ(value, v8_num(4));
3389 CHECK_EQ(info.Data(), v8_str("donut"));
3390 CHECK_EQ(name, v8_str("x"));
3391 CHECK(xValue.IsEmpty());
3392 xValue = v8::Persistent<Value>::New(value);
3393}
3394
3395
3396THREADED_TEST(SimplePropertyWrite) {
3397 v8::HandleScope scope;
3398 Local<ObjectTemplate> templ = ObjectTemplate::New();
3399 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
3400 LocalContext context;
3401 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3402 Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
3403 for (int i = 0; i < 10; i++) {
3404 CHECK(xValue.IsEmpty());
3405 script->Run();
3406 CHECK_EQ(v8_num(4), xValue);
3407 xValue.Dispose();
3408 xValue = v8::Persistent<Value>();
3409 }
3410}
3411
3412
3413static v8::Handle<Value> XPropertyGetter(Local<String> property,
3414 const AccessorInfo& info) {
3415 ApiTestFuzzer::Fuzz();
3416 CHECK(info.Data()->IsUndefined());
3417 return property;
3418}
3419
3420
3421THREADED_TEST(NamedInterceptorPropertyRead) {
3422 v8::HandleScope scope;
3423 Local<ObjectTemplate> templ = ObjectTemplate::New();
3424 templ->SetNamedPropertyHandler(XPropertyGetter);
3425 LocalContext context;
3426 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3427 Local<Script> script = Script::Compile(v8_str("obj.x"));
3428 for (int i = 0; i < 10; i++) {
3429 Local<Value> result = script->Run();
3430 CHECK_EQ(result, v8_str("x"));
3431 }
3432}
3433
3434
Steve Block6ded16b2010-05-10 14:33:55 +01003435THREADED_TEST(NamedInterceptorDictionaryIC) {
3436 v8::HandleScope scope;
3437 Local<ObjectTemplate> templ = ObjectTemplate::New();
3438 templ->SetNamedPropertyHandler(XPropertyGetter);
3439 LocalContext context;
3440 // Create an object with a named interceptor.
3441 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
3442 Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
3443 for (int i = 0; i < 10; i++) {
3444 Local<Value> result = script->Run();
3445 CHECK_EQ(result, v8_str("x"));
3446 }
3447 // Create a slow case object and a function accessing a property in
3448 // that slow case object (with dictionary probing in generated
3449 // code). Then force object with a named interceptor into slow-case,
3450 // pass it to the function, and check that the interceptor is called
3451 // instead of accessing the local property.
3452 Local<Value> result =
3453 CompileRun("function get_x(o) { return o.x; };"
3454 "var obj = { x : 42, y : 0 };"
3455 "delete obj.y;"
3456 "for (var i = 0; i < 10; i++) get_x(obj);"
3457 "interceptor_obj.x = 42;"
3458 "interceptor_obj.y = 10;"
3459 "delete interceptor_obj.y;"
3460 "get_x(interceptor_obj)");
3461 CHECK_EQ(result, v8_str("x"));
3462}
3463
3464
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003465THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
3466 v8::HandleScope scope;
3467
3468 v8::Persistent<Context> context1 = Context::New();
3469
3470 context1->Enter();
3471 Local<ObjectTemplate> templ = ObjectTemplate::New();
3472 templ->SetNamedPropertyHandler(XPropertyGetter);
3473 // Create an object with a named interceptor.
3474 v8::Local<v8::Object> object = templ->NewInstance();
3475 context1->Global()->Set(v8_str("interceptor_obj"), object);
3476
3477 // Force the object into the slow case.
3478 CompileRun("interceptor_obj.y = 0;"
3479 "delete interceptor_obj.y;");
3480 context1->Exit();
3481
3482 {
3483 // Introduce the object into a different context.
3484 // Repeat named loads to exercise ICs.
3485 LocalContext context2;
3486 context2->Global()->Set(v8_str("interceptor_obj"), object);
3487 Local<Value> result =
3488 CompileRun("function get_x(o) { return o.x; }"
3489 "interceptor_obj.x = 42;"
3490 "for (var i=0; i != 10; i++) {"
3491 " get_x(interceptor_obj);"
3492 "}"
3493 "get_x(interceptor_obj)");
3494 // Check that the interceptor was actually invoked.
3495 CHECK_EQ(result, v8_str("x"));
3496 }
3497
3498 // Return to the original context and force some object to the slow case
3499 // to cause the NormalizedMapCache to verify.
3500 context1->Enter();
3501 CompileRun("var obj = { x : 0 }; delete obj.x;");
3502 context1->Exit();
3503
3504 context1.Dispose();
3505}
3506
3507
Andrei Popescu402d9372010-02-26 13:31:12 +00003508static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
3509 const AccessorInfo& info) {
3510 // Set x on the prototype object and do not handle the get request.
3511 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
Steve Block6ded16b2010-05-10 14:33:55 +01003512 proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
Andrei Popescu402d9372010-02-26 13:31:12 +00003513 return v8::Handle<Value>();
3514}
3515
3516
3517// This is a regression test for http://crbug.com/20104. Map
3518// transitions should not interfere with post interceptor lookup.
3519THREADED_TEST(NamedInterceptorMapTransitionRead) {
3520 v8::HandleScope scope;
3521 Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
3522 Local<v8::ObjectTemplate> instance_template
3523 = function_template->InstanceTemplate();
3524 instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
3525 LocalContext context;
3526 context->Global()->Set(v8_str("F"), function_template->GetFunction());
3527 // Create an instance of F and introduce a map transition for x.
3528 CompileRun("var o = new F(); o.x = 23;");
3529 // Create an instance of F and invoke the getter. The result should be 23.
3530 Local<Value> result = CompileRun("o = new F(); o.x");
3531 CHECK_EQ(result->Int32Value(), 23);
3532}
3533
3534
Steve Blocka7e24c12009-10-30 11:49:00 +00003535static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
3536 const AccessorInfo& info) {
3537 ApiTestFuzzer::Fuzz();
3538 if (index == 37) {
3539 return v8::Handle<Value>(v8_num(625));
3540 }
3541 return v8::Handle<Value>();
3542}
3543
3544
3545static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
3546 Local<Value> value,
3547 const AccessorInfo& info) {
3548 ApiTestFuzzer::Fuzz();
3549 if (index == 39) {
3550 return value;
3551 }
3552 return v8::Handle<Value>();
3553}
3554
3555
3556THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
3557 v8::HandleScope scope;
3558 Local<ObjectTemplate> templ = ObjectTemplate::New();
3559 templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
3560 IndexedPropertySetter);
3561 LocalContext context;
3562 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3563 Local<Script> getter_script = Script::Compile(v8_str(
3564 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
3565 Local<Script> setter_script = Script::Compile(v8_str(
3566 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
3567 "obj[17] = 23;"
3568 "obj.foo;"));
3569 Local<Script> interceptor_setter_script = Script::Compile(v8_str(
3570 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
3571 "obj[39] = 47;"
3572 "obj.foo;")); // This setter should not run, due to the interceptor.
3573 Local<Script> interceptor_getter_script = Script::Compile(v8_str(
3574 "obj[37];"));
3575 Local<Value> result = getter_script->Run();
3576 CHECK_EQ(v8_num(5), result);
3577 result = setter_script->Run();
3578 CHECK_EQ(v8_num(23), result);
3579 result = interceptor_setter_script->Run();
3580 CHECK_EQ(v8_num(23), result);
3581 result = interceptor_getter_script->Run();
3582 CHECK_EQ(v8_num(625), result);
3583}
3584
3585
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003586static v8::Handle<Value> UnboxedDoubleIndexedPropertyGetter(
3587 uint32_t index,
3588 const AccessorInfo& info) {
3589 ApiTestFuzzer::Fuzz();
3590 if (index < 25) {
3591 return v8::Handle<Value>(v8_num(index));
3592 }
3593 return v8::Handle<Value>();
3594}
3595
3596
3597static v8::Handle<Value> UnboxedDoubleIndexedPropertySetter(
3598 uint32_t index,
3599 Local<Value> value,
3600 const AccessorInfo& info) {
3601 ApiTestFuzzer::Fuzz();
3602 if (index < 25) {
3603 return v8::Handle<Value>(v8_num(index));
3604 }
3605 return v8::Handle<Value>();
3606}
3607
3608
3609Handle<v8::Array> UnboxedDoubleIndexedPropertyEnumerator(
3610 const AccessorInfo& info) {
3611 // Force the list of returned keys to be stored in a FastDoubleArray.
3612 Local<Script> indexed_property_names_script = Script::Compile(v8_str(
3613 "keys = new Array(); keys[125000] = 1;"
3614 "for(i = 0; i < 80000; i++) { keys[i] = i; };"
3615 "keys.length = 25; keys;"));
3616 Local<Value> result = indexed_property_names_script->Run();
3617 return Local<v8::Array>(::v8::Array::Cast(*result));
3618}
3619
3620
3621// Make sure that the the interceptor code in the runtime properly handles
3622// merging property name lists for double-array-backed arrays.
3623THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
3624 v8::HandleScope scope;
3625 Local<ObjectTemplate> templ = ObjectTemplate::New();
3626 templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
3627 UnboxedDoubleIndexedPropertySetter,
3628 0,
3629 0,
3630 UnboxedDoubleIndexedPropertyEnumerator);
3631 LocalContext context;
3632 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3633 // When obj is created, force it to be Stored in a FastDoubleArray.
3634 Local<Script> create_unboxed_double_script = Script::Compile(v8_str(
3635 "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
3636 "key_count = 0; "
3637 "for (x in obj) {key_count++;};"
3638 "obj;"));
3639 Local<Value> result = create_unboxed_double_script->Run();
3640 CHECK(result->ToObject()->HasRealIndexedProperty(2000));
3641 Local<Script> key_count_check = Script::Compile(v8_str(
3642 "key_count;"));
3643 result = key_count_check->Run();
3644 CHECK_EQ(v8_num(40013), result);
3645}
3646
3647
3648Handle<v8::Array> NonStrictArgsIndexedPropertyEnumerator(
3649 const AccessorInfo& info) {
3650 // Force the list of returned keys to be stored in a Arguments object.
3651 Local<Script> indexed_property_names_script = Script::Compile(v8_str(
3652 "function f(w,x) {"
3653 " return arguments;"
3654 "}"
3655 "keys = f(0, 1, 2, 3);"
3656 "keys;"));
3657 Local<Value> result = indexed_property_names_script->Run();
3658 return Local<v8::Array>(static_cast<v8::Array*>(::v8::Object::Cast(*result)));
3659}
3660
3661
3662static v8::Handle<Value> NonStrictIndexedPropertyGetter(
3663 uint32_t index,
3664 const AccessorInfo& info) {
3665 ApiTestFuzzer::Fuzz();
3666 if (index < 4) {
3667 return v8::Handle<Value>(v8_num(index));
3668 }
3669 return v8::Handle<Value>();
3670}
3671
3672
3673// Make sure that the the interceptor code in the runtime properly handles
3674// merging property name lists for non-string arguments arrays.
3675THREADED_TEST(IndexedInterceptorNonStrictArgsWithIndexedAccessor) {
3676 v8::HandleScope scope;
3677 Local<ObjectTemplate> templ = ObjectTemplate::New();
3678 templ->SetIndexedPropertyHandler(NonStrictIndexedPropertyGetter,
3679 0,
3680 0,
3681 0,
3682 NonStrictArgsIndexedPropertyEnumerator);
3683 LocalContext context;
3684 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3685 Local<Script> create_args_script =
3686 Script::Compile(v8_str(
3687 "var key_count = 0;"
3688 "for (x in obj) {key_count++;} key_count;"));
3689 Local<Value> result = create_args_script->Run();
3690 CHECK_EQ(v8_num(4), result);
3691}
3692
3693
Leon Clarked91b9f72010-01-27 17:25:45 +00003694static v8::Handle<Value> IdentityIndexedPropertyGetter(
3695 uint32_t index,
3696 const AccessorInfo& info) {
Ben Murdochf87a2032010-10-22 12:50:53 +01003697 return v8::Integer::NewFromUnsigned(index);
Leon Clarked91b9f72010-01-27 17:25:45 +00003698}
3699
3700
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003701THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
3702 v8::HandleScope scope;
3703 Local<ObjectTemplate> templ = ObjectTemplate::New();
3704 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3705
3706 LocalContext context;
3707 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3708
3709 // Check fast object case.
3710 const char* fast_case_code =
3711 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
3712 ExpectString(fast_case_code, "0");
3713
3714 // Check slow case.
3715 const char* slow_case_code =
3716 "obj.x = 1; delete obj.x;"
3717 "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
3718 ExpectString(slow_case_code, "1");
3719}
3720
3721
Leon Clarked91b9f72010-01-27 17:25:45 +00003722THREADED_TEST(IndexedInterceptorWithNoSetter) {
3723 v8::HandleScope scope;
3724 Local<ObjectTemplate> templ = ObjectTemplate::New();
3725 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3726
3727 LocalContext context;
3728 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3729
3730 const char* code =
3731 "try {"
3732 " obj[0] = 239;"
3733 " for (var i = 0; i < 100; i++) {"
3734 " var v = obj[0];"
3735 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
3736 " }"
3737 " 'PASSED'"
3738 "} catch(e) {"
3739 " e"
3740 "}";
3741 ExpectString(code, "PASSED");
3742}
3743
3744
Andrei Popescu402d9372010-02-26 13:31:12 +00003745THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
3746 v8::HandleScope scope;
3747 Local<ObjectTemplate> templ = ObjectTemplate::New();
3748 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3749
3750 LocalContext context;
3751 Local<v8::Object> obj = templ->NewInstance();
3752 obj->TurnOnAccessCheck();
3753 context->Global()->Set(v8_str("obj"), obj);
3754
3755 const char* code =
3756 "try {"
3757 " for (var i = 0; i < 100; i++) {"
3758 " var v = obj[0];"
3759 " if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
3760 " }"
3761 " 'PASSED'"
3762 "} catch(e) {"
3763 " e"
3764 "}";
3765 ExpectString(code, "PASSED");
3766}
3767
3768
3769THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
3770 i::FLAG_allow_natives_syntax = true;
3771 v8::HandleScope scope;
3772 Local<ObjectTemplate> templ = ObjectTemplate::New();
3773 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3774
3775 LocalContext context;
3776 Local<v8::Object> obj = templ->NewInstance();
3777 context->Global()->Set(v8_str("obj"), obj);
3778
3779 const char* code =
3780 "try {"
3781 " for (var i = 0; i < 100; i++) {"
3782 " var expected = i;"
3783 " if (i == 5) {"
3784 " %EnableAccessChecks(obj);"
3785 " expected = undefined;"
3786 " }"
3787 " var v = obj[i];"
3788 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3789 " if (i == 5) %DisableAccessChecks(obj);"
3790 " }"
3791 " 'PASSED'"
3792 "} catch(e) {"
3793 " e"
3794 "}";
3795 ExpectString(code, "PASSED");
3796}
3797
3798
3799THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
3800 v8::HandleScope scope;
3801 Local<ObjectTemplate> templ = ObjectTemplate::New();
3802 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3803
3804 LocalContext context;
3805 Local<v8::Object> obj = templ->NewInstance();
3806 context->Global()->Set(v8_str("obj"), obj);
3807
3808 const char* code =
3809 "try {"
3810 " for (var i = 0; i < 100; i++) {"
3811 " var v = obj[i];"
3812 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
3813 " }"
3814 " 'PASSED'"
3815 "} catch(e) {"
3816 " e"
3817 "}";
3818 ExpectString(code, "PASSED");
3819}
3820
3821
Ben Murdochf87a2032010-10-22 12:50:53 +01003822THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
3823 v8::HandleScope scope;
3824 Local<ObjectTemplate> templ = ObjectTemplate::New();
3825 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3826
3827 LocalContext context;
3828 Local<v8::Object> obj = templ->NewInstance();
3829 context->Global()->Set(v8_str("obj"), obj);
3830
3831 const char* code =
3832 "try {"
3833 " for (var i = 0; i < 100; i++) {"
3834 " var expected = i;"
3835 " var key = i;"
3836 " if (i == 25) {"
3837 " key = -1;"
3838 " expected = undefined;"
3839 " }"
3840 " if (i == 50) {"
3841 " /* probe minimal Smi number on 32-bit platforms */"
3842 " key = -(1 << 30);"
3843 " expected = undefined;"
3844 " }"
3845 " if (i == 75) {"
3846 " /* probe minimal Smi number on 64-bit platforms */"
3847 " key = 1 << 31;"
3848 " expected = undefined;"
3849 " }"
3850 " var v = obj[key];"
3851 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3852 " }"
3853 " 'PASSED'"
3854 "} catch(e) {"
3855 " e"
3856 "}";
3857 ExpectString(code, "PASSED");
3858}
3859
3860
Andrei Popescu402d9372010-02-26 13:31:12 +00003861THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
3862 v8::HandleScope scope;
3863 Local<ObjectTemplate> templ = ObjectTemplate::New();
3864 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3865
3866 LocalContext context;
3867 Local<v8::Object> obj = templ->NewInstance();
3868 context->Global()->Set(v8_str("obj"), obj);
3869
3870 const char* code =
3871 "try {"
3872 " for (var i = 0; i < 100; i++) {"
3873 " var expected = i;"
Ben Murdochf87a2032010-10-22 12:50:53 +01003874 " var key = i;"
Andrei Popescu402d9372010-02-26 13:31:12 +00003875 " if (i == 50) {"
Ben Murdochf87a2032010-10-22 12:50:53 +01003876 " key = 'foobar';"
Andrei Popescu402d9372010-02-26 13:31:12 +00003877 " expected = undefined;"
3878 " }"
Ben Murdochf87a2032010-10-22 12:50:53 +01003879 " var v = obj[key];"
Andrei Popescu402d9372010-02-26 13:31:12 +00003880 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3881 " }"
3882 " 'PASSED'"
3883 "} catch(e) {"
3884 " e"
3885 "}";
3886 ExpectString(code, "PASSED");
3887}
3888
3889
3890THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
3891 v8::HandleScope scope;
3892 Local<ObjectTemplate> templ = ObjectTemplate::New();
3893 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3894
3895 LocalContext context;
3896 Local<v8::Object> obj = templ->NewInstance();
3897 context->Global()->Set(v8_str("obj"), obj);
3898
3899 const char* code =
3900 "var original = obj;"
3901 "try {"
3902 " for (var i = 0; i < 100; i++) {"
3903 " var expected = i;"
3904 " if (i == 50) {"
3905 " obj = {50: 'foobar'};"
3906 " expected = 'foobar';"
3907 " }"
3908 " var v = obj[i];"
3909 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3910 " if (i == 50) obj = original;"
3911 " }"
3912 " 'PASSED'"
3913 "} catch(e) {"
3914 " e"
3915 "}";
3916 ExpectString(code, "PASSED");
3917}
3918
3919
3920THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
3921 v8::HandleScope scope;
3922 Local<ObjectTemplate> templ = ObjectTemplate::New();
3923 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3924
3925 LocalContext context;
3926 Local<v8::Object> obj = templ->NewInstance();
3927 context->Global()->Set(v8_str("obj"), obj);
3928
3929 const char* code =
3930 "var original = obj;"
3931 "try {"
3932 " for (var i = 0; i < 100; i++) {"
3933 " var expected = i;"
3934 " if (i == 5) {"
3935 " obj = 239;"
3936 " expected = undefined;"
3937 " }"
3938 " var v = obj[i];"
3939 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3940 " if (i == 5) obj = original;"
3941 " }"
3942 " 'PASSED'"
3943 "} catch(e) {"
3944 " e"
3945 "}";
3946 ExpectString(code, "PASSED");
3947}
3948
3949
3950THREADED_TEST(IndexedInterceptorOnProto) {
3951 v8::HandleScope scope;
3952 Local<ObjectTemplate> templ = ObjectTemplate::New();
3953 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3954
3955 LocalContext context;
3956 Local<v8::Object> obj = templ->NewInstance();
3957 context->Global()->Set(v8_str("obj"), obj);
3958
3959 const char* code =
3960 "var o = {__proto__: obj};"
3961 "try {"
3962 " for (var i = 0; i < 100; i++) {"
3963 " var v = o[i];"
3964 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
3965 " }"
3966 " 'PASSED'"
3967 "} catch(e) {"
3968 " e"
3969 "}";
3970 ExpectString(code, "PASSED");
3971}
3972
3973
Steve Blocka7e24c12009-10-30 11:49:00 +00003974THREADED_TEST(MultiContexts) {
3975 v8::HandleScope scope;
3976 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
3977 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
3978
3979 Local<String> password = v8_str("Password");
3980
3981 // Create an environment
3982 LocalContext context0(0, templ);
3983 context0->SetSecurityToken(password);
3984 v8::Handle<v8::Object> global0 = context0->Global();
3985 global0->Set(v8_str("custom"), v8_num(1234));
3986 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
3987
3988 // Create an independent environment
3989 LocalContext context1(0, templ);
3990 context1->SetSecurityToken(password);
3991 v8::Handle<v8::Object> global1 = context1->Global();
3992 global1->Set(v8_str("custom"), v8_num(1234));
3993 CHECK_NE(global0, global1);
3994 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
3995 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
3996
3997 // Now create a new context with the old global
3998 LocalContext context2(0, templ, global1);
3999 context2->SetSecurityToken(password);
4000 v8::Handle<v8::Object> global2 = context2->Global();
4001 CHECK_EQ(global1, global2);
4002 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
4003 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
4004}
4005
4006
4007THREADED_TEST(FunctionPrototypeAcrossContexts) {
4008 // Make sure that functions created by cloning boilerplates cannot
4009 // communicate through their __proto__ field.
4010
4011 v8::HandleScope scope;
4012
4013 LocalContext env0;
4014 v8::Handle<v8::Object> global0 =
4015 env0->Global();
4016 v8::Handle<v8::Object> object0 =
Steve Block6ded16b2010-05-10 14:33:55 +01004017 global0->Get(v8_str("Object")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00004018 v8::Handle<v8::Object> tostring0 =
Steve Block6ded16b2010-05-10 14:33:55 +01004019 object0->Get(v8_str("toString")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00004020 v8::Handle<v8::Object> proto0 =
Steve Block6ded16b2010-05-10 14:33:55 +01004021 tostring0->Get(v8_str("__proto__")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00004022 proto0->Set(v8_str("custom"), v8_num(1234));
4023
4024 LocalContext env1;
4025 v8::Handle<v8::Object> global1 =
4026 env1->Global();
4027 v8::Handle<v8::Object> object1 =
Steve Block6ded16b2010-05-10 14:33:55 +01004028 global1->Get(v8_str("Object")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00004029 v8::Handle<v8::Object> tostring1 =
Steve Block6ded16b2010-05-10 14:33:55 +01004030 object1->Get(v8_str("toString")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00004031 v8::Handle<v8::Object> proto1 =
Steve Block6ded16b2010-05-10 14:33:55 +01004032 tostring1->Get(v8_str("__proto__")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00004033 CHECK(!proto1->Has(v8_str("custom")));
4034}
4035
4036
4037THREADED_TEST(Regress892105) {
4038 // Make sure that object and array literals created by cloning
4039 // boilerplates cannot communicate through their __proto__
4040 // field. This is rather difficult to check, but we try to add stuff
4041 // to Object.prototype and Array.prototype and create a new
4042 // environment. This should succeed.
4043
4044 v8::HandleScope scope;
4045
4046 Local<String> source = v8_str("Object.prototype.obj = 1234;"
4047 "Array.prototype.arr = 4567;"
4048 "8901");
4049
4050 LocalContext env0;
4051 Local<Script> script0 = Script::Compile(source);
4052 CHECK_EQ(8901.0, script0->Run()->NumberValue());
4053
4054 LocalContext env1;
4055 Local<Script> script1 = Script::Compile(source);
4056 CHECK_EQ(8901.0, script1->Run()->NumberValue());
4057}
4058
4059
Steve Blocka7e24c12009-10-30 11:49:00 +00004060THREADED_TEST(UndetectableObject) {
4061 v8::HandleScope scope;
4062 LocalContext env;
4063
4064 Local<v8::FunctionTemplate> desc =
4065 v8::FunctionTemplate::New(0, v8::Handle<Value>());
4066 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4067
4068 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4069 env->Global()->Set(v8_str("undetectable"), obj);
4070
4071 ExpectString("undetectable.toString()", "[object Object]");
4072 ExpectString("typeof undetectable", "undefined");
4073 ExpectString("typeof(undetectable)", "undefined");
4074 ExpectBoolean("typeof undetectable == 'undefined'", true);
4075 ExpectBoolean("typeof undetectable == 'object'", false);
4076 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
4077 ExpectBoolean("!undetectable", true);
4078
4079 ExpectObject("true&&undetectable", obj);
4080 ExpectBoolean("false&&undetectable", false);
4081 ExpectBoolean("true||undetectable", true);
4082 ExpectObject("false||undetectable", obj);
4083
4084 ExpectObject("undetectable&&true", obj);
4085 ExpectObject("undetectable&&false", obj);
4086 ExpectBoolean("undetectable||true", true);
4087 ExpectBoolean("undetectable||false", false);
4088
4089 ExpectBoolean("undetectable==null", true);
4090 ExpectBoolean("null==undetectable", true);
4091 ExpectBoolean("undetectable==undefined", true);
4092 ExpectBoolean("undefined==undetectable", true);
4093 ExpectBoolean("undetectable==undetectable", true);
4094
4095
4096 ExpectBoolean("undetectable===null", false);
4097 ExpectBoolean("null===undetectable", false);
4098 ExpectBoolean("undetectable===undefined", false);
4099 ExpectBoolean("undefined===undetectable", false);
4100 ExpectBoolean("undetectable===undetectable", true);
4101}
4102
4103
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004104THREADED_TEST(VoidLiteral) {
4105 v8::HandleScope scope;
4106 LocalContext env;
4107
4108 Local<v8::FunctionTemplate> desc =
4109 v8::FunctionTemplate::New(0, v8::Handle<Value>());
4110 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4111
4112 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4113 env->Global()->Set(v8_str("undetectable"), obj);
4114
4115 ExpectBoolean("undefined == void 0", true);
4116 ExpectBoolean("undetectable == void 0", true);
4117 ExpectBoolean("null == void 0", true);
4118 ExpectBoolean("undefined === void 0", true);
4119 ExpectBoolean("undetectable === void 0", false);
4120 ExpectBoolean("null === void 0", false);
4121
4122 ExpectBoolean("void 0 == undefined", true);
4123 ExpectBoolean("void 0 == undetectable", true);
4124 ExpectBoolean("void 0 == null", true);
4125 ExpectBoolean("void 0 === undefined", true);
4126 ExpectBoolean("void 0 === undetectable", false);
4127 ExpectBoolean("void 0 === null", false);
4128
4129 ExpectString("(function() {"
4130 " try {"
4131 " return x === void 0;"
4132 " } catch(e) {"
4133 " return e.toString();"
4134 " }"
4135 "})()",
4136 "ReferenceError: x is not defined");
4137 ExpectString("(function() {"
4138 " try {"
4139 " return void 0 === x;"
4140 " } catch(e) {"
4141 " return e.toString();"
4142 " }"
4143 "})()",
4144 "ReferenceError: x is not defined");
4145}
4146
Steve Block8defd9f2010-07-08 12:39:36 +01004147
4148THREADED_TEST(ExtensibleOnUndetectable) {
4149 v8::HandleScope scope;
4150 LocalContext env;
4151
4152 Local<v8::FunctionTemplate> desc =
4153 v8::FunctionTemplate::New(0, v8::Handle<Value>());
4154 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4155
4156 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4157 env->Global()->Set(v8_str("undetectable"), obj);
4158
4159 Local<String> source = v8_str("undetectable.x = 42;"
4160 "undetectable.x");
4161
4162 Local<Script> script = Script::Compile(source);
4163
4164 CHECK_EQ(v8::Integer::New(42), script->Run());
4165
4166 ExpectBoolean("Object.isExtensible(undetectable)", true);
4167
4168 source = v8_str("Object.preventExtensions(undetectable);");
4169 script = Script::Compile(source);
4170 script->Run();
4171 ExpectBoolean("Object.isExtensible(undetectable)", false);
4172
4173 source = v8_str("undetectable.y = 2000;");
4174 script = Script::Compile(source);
Steve Block8defd9f2010-07-08 12:39:36 +01004175 Local<Value> result = script->Run();
Steve Block44f0eee2011-05-26 01:26:41 +01004176 ExpectBoolean("undetectable.y == undefined", true);
Steve Block8defd9f2010-07-08 12:39:36 +01004177}
4178
4179
4180
Steve Blocka7e24c12009-10-30 11:49:00 +00004181THREADED_TEST(UndetectableString) {
4182 v8::HandleScope scope;
4183 LocalContext env;
4184
4185 Local<String> obj = String::NewUndetectable("foo");
4186 env->Global()->Set(v8_str("undetectable"), obj);
4187
4188 ExpectString("undetectable", "foo");
4189 ExpectString("typeof undetectable", "undefined");
4190 ExpectString("typeof(undetectable)", "undefined");
4191 ExpectBoolean("typeof undetectable == 'undefined'", true);
4192 ExpectBoolean("typeof undetectable == 'string'", false);
4193 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
4194 ExpectBoolean("!undetectable", true);
4195
4196 ExpectObject("true&&undetectable", obj);
4197 ExpectBoolean("false&&undetectable", false);
4198 ExpectBoolean("true||undetectable", true);
4199 ExpectObject("false||undetectable", obj);
4200
4201 ExpectObject("undetectable&&true", obj);
4202 ExpectObject("undetectable&&false", obj);
4203 ExpectBoolean("undetectable||true", true);
4204 ExpectBoolean("undetectable||false", false);
4205
4206 ExpectBoolean("undetectable==null", true);
4207 ExpectBoolean("null==undetectable", true);
4208 ExpectBoolean("undetectable==undefined", true);
4209 ExpectBoolean("undefined==undetectable", true);
4210 ExpectBoolean("undetectable==undetectable", true);
4211
4212
4213 ExpectBoolean("undetectable===null", false);
4214 ExpectBoolean("null===undetectable", false);
4215 ExpectBoolean("undetectable===undefined", false);
4216 ExpectBoolean("undefined===undetectable", false);
4217 ExpectBoolean("undetectable===undetectable", true);
4218}
4219
4220
Ben Murdoch257744e2011-11-30 15:57:28 +00004221TEST(UndetectableOptimized) {
4222 i::FLAG_allow_natives_syntax = true;
4223 v8::HandleScope scope;
4224 LocalContext env;
4225
4226 Local<String> obj = String::NewUndetectable("foo");
4227 env->Global()->Set(v8_str("undetectable"), obj);
4228 env->Global()->Set(v8_str("detectable"), v8_str("bar"));
4229
4230 ExpectString(
4231 "function testBranch() {"
4232 " if (!%_IsUndetectableObject(undetectable)) throw 1;"
4233 " if (%_IsUndetectableObject(detectable)) throw 2;"
4234 "}\n"
4235 "function testBool() {"
4236 " var b1 = !%_IsUndetectableObject(undetectable);"
4237 " var b2 = %_IsUndetectableObject(detectable);"
4238 " if (b1) throw 3;"
4239 " if (b2) throw 4;"
4240 " return b1 == b2;"
4241 "}\n"
4242 "%OptimizeFunctionOnNextCall(testBranch);"
4243 "%OptimizeFunctionOnNextCall(testBool);"
4244 "for (var i = 0; i < 10; i++) {"
4245 " testBranch();"
4246 " testBool();"
4247 "}\n"
4248 "\"PASS\"",
4249 "PASS");
4250}
4251
4252
Steve Blocka7e24c12009-10-30 11:49:00 +00004253template <typename T> static void USE(T) { }
4254
4255
4256// This test is not intended to be run, just type checked.
4257static void PersistentHandles() {
4258 USE(PersistentHandles);
4259 Local<String> str = v8_str("foo");
4260 v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
4261 USE(p_str);
4262 Local<Script> scr = Script::Compile(v8_str(""));
4263 v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
4264 USE(p_scr);
4265 Local<ObjectTemplate> templ = ObjectTemplate::New();
4266 v8::Persistent<ObjectTemplate> p_templ =
4267 v8::Persistent<ObjectTemplate>::New(templ);
4268 USE(p_templ);
4269}
4270
4271
4272static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
4273 ApiTestFuzzer::Fuzz();
4274 return v8::Undefined();
4275}
4276
4277
4278THREADED_TEST(GlobalObjectTemplate) {
4279 v8::HandleScope handle_scope;
4280 Local<ObjectTemplate> global_template = ObjectTemplate::New();
4281 global_template->Set(v8_str("JSNI_Log"),
4282 v8::FunctionTemplate::New(HandleLogDelegator));
4283 v8::Persistent<Context> context = Context::New(0, global_template);
4284 Context::Scope context_scope(context);
4285 Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
4286 context.Dispose();
4287}
4288
4289
4290static const char* kSimpleExtensionSource =
4291 "function Foo() {"
4292 " return 4;"
4293 "}";
4294
4295
4296THREADED_TEST(SimpleExtensions) {
4297 v8::HandleScope handle_scope;
4298 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
4299 const char* extension_names[] = { "simpletest" };
4300 v8::ExtensionConfiguration extensions(1, extension_names);
4301 v8::Handle<Context> context = Context::New(&extensions);
4302 Context::Scope lock(context);
4303 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
4304 CHECK_EQ(result, v8::Integer::New(4));
4305}
4306
4307
4308static const char* kEvalExtensionSource1 =
4309 "function UseEval1() {"
4310 " var x = 42;"
4311 " return eval('x');"
4312 "}";
4313
4314
4315static const char* kEvalExtensionSource2 =
4316 "(function() {"
4317 " var x = 42;"
4318 " function e() {"
4319 " return eval('x');"
4320 " }"
4321 " this.UseEval2 = e;"
4322 "})()";
4323
4324
4325THREADED_TEST(UseEvalFromExtension) {
4326 v8::HandleScope handle_scope;
4327 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
4328 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
4329 const char* extension_names[] = { "evaltest1", "evaltest2" };
4330 v8::ExtensionConfiguration extensions(2, extension_names);
4331 v8::Handle<Context> context = Context::New(&extensions);
4332 Context::Scope lock(context);
4333 v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
4334 CHECK_EQ(result, v8::Integer::New(42));
4335 result = Script::Compile(v8_str("UseEval2()"))->Run();
4336 CHECK_EQ(result, v8::Integer::New(42));
4337}
4338
4339
4340static const char* kWithExtensionSource1 =
4341 "function UseWith1() {"
4342 " var x = 42;"
4343 " with({x:87}) { return x; }"
4344 "}";
4345
4346
4347
4348static const char* kWithExtensionSource2 =
4349 "(function() {"
4350 " var x = 42;"
4351 " function e() {"
4352 " with ({x:87}) { return x; }"
4353 " }"
4354 " this.UseWith2 = e;"
4355 "})()";
4356
4357
4358THREADED_TEST(UseWithFromExtension) {
4359 v8::HandleScope handle_scope;
4360 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
4361 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
4362 const char* extension_names[] = { "withtest1", "withtest2" };
4363 v8::ExtensionConfiguration extensions(2, extension_names);
4364 v8::Handle<Context> context = Context::New(&extensions);
4365 Context::Scope lock(context);
4366 v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
4367 CHECK_EQ(result, v8::Integer::New(87));
4368 result = Script::Compile(v8_str("UseWith2()"))->Run();
4369 CHECK_EQ(result, v8::Integer::New(87));
4370}
4371
4372
4373THREADED_TEST(AutoExtensions) {
4374 v8::HandleScope handle_scope;
4375 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
4376 extension->set_auto_enable(true);
4377 v8::RegisterExtension(extension);
4378 v8::Handle<Context> context = Context::New();
4379 Context::Scope lock(context);
4380 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
4381 CHECK_EQ(result, v8::Integer::New(4));
4382}
4383
4384
Steve Blockd0582a62009-12-15 09:54:21 +00004385static const char* kSyntaxErrorInExtensionSource =
4386 "[";
4387
4388
4389// Test that a syntax error in an extension does not cause a fatal
4390// error but results in an empty context.
4391THREADED_TEST(SyntaxErrorExtensions) {
4392 v8::HandleScope handle_scope;
4393 v8::RegisterExtension(new Extension("syntaxerror",
4394 kSyntaxErrorInExtensionSource));
4395 const char* extension_names[] = { "syntaxerror" };
4396 v8::ExtensionConfiguration extensions(1, extension_names);
4397 v8::Handle<Context> context = Context::New(&extensions);
4398 CHECK(context.IsEmpty());
4399}
4400
4401
4402static const char* kExceptionInExtensionSource =
4403 "throw 42";
4404
4405
4406// Test that an exception when installing an extension does not cause
4407// a fatal error but results in an empty context.
4408THREADED_TEST(ExceptionExtensions) {
4409 v8::HandleScope handle_scope;
4410 v8::RegisterExtension(new Extension("exception",
4411 kExceptionInExtensionSource));
4412 const char* extension_names[] = { "exception" };
4413 v8::ExtensionConfiguration extensions(1, extension_names);
4414 v8::Handle<Context> context = Context::New(&extensions);
4415 CHECK(context.IsEmpty());
4416}
4417
4418
Iain Merrick9ac36c92010-09-13 15:29:50 +01004419static const char* kNativeCallInExtensionSource =
4420 "function call_runtime_last_index_of(x) {"
4421 " return %StringLastIndexOf(x, 'bob', 10);"
4422 "}";
4423
4424
4425static const char* kNativeCallTest =
4426 "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
4427
4428// Test that a native runtime calls are supported in extensions.
4429THREADED_TEST(NativeCallInExtensions) {
4430 v8::HandleScope handle_scope;
4431 v8::RegisterExtension(new Extension("nativecall",
4432 kNativeCallInExtensionSource));
4433 const char* extension_names[] = { "nativecall" };
4434 v8::ExtensionConfiguration extensions(1, extension_names);
4435 v8::Handle<Context> context = Context::New(&extensions);
4436 Context::Scope lock(context);
4437 v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run();
4438 CHECK_EQ(result, v8::Integer::New(3));
4439}
4440
4441
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004442class NativeFunctionExtension : public Extension {
4443 public:
4444 NativeFunctionExtension(const char* name,
4445 const char* source,
4446 v8::InvocationCallback fun = &Echo)
4447 : Extension(name, source),
4448 function_(fun) { }
4449
4450 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
4451 v8::Handle<v8::String> name) {
4452 return v8::FunctionTemplate::New(function_);
4453 }
4454
4455 static v8::Handle<v8::Value> Echo(const v8::Arguments& args) {
4456 if (args.Length() >= 1) return (args[0]);
4457 return v8::Undefined();
4458 }
4459 private:
4460 v8::InvocationCallback function_;
4461};
4462
4463
4464THREADED_TEST(NativeFunctionDeclaration) {
4465 v8::HandleScope handle_scope;
4466 const char* name = "nativedecl";
4467 v8::RegisterExtension(new NativeFunctionExtension(name,
4468 "native function foo();"));
4469 const char* extension_names[] = { name };
4470 v8::ExtensionConfiguration extensions(1, extension_names);
4471 v8::Handle<Context> context = Context::New(&extensions);
4472 Context::Scope lock(context);
4473 v8::Handle<Value> result = Script::Compile(v8_str("foo(42);"))->Run();
4474 CHECK_EQ(result, v8::Integer::New(42));
4475}
4476
4477
4478THREADED_TEST(NativeFunctionDeclarationError) {
4479 v8::HandleScope handle_scope;
4480 const char* name = "nativedeclerr";
4481 // Syntax error in extension code.
4482 v8::RegisterExtension(new NativeFunctionExtension(name,
4483 "native\nfunction foo();"));
4484 const char* extension_names[] = { name };
4485 v8::ExtensionConfiguration extensions(1, extension_names);
4486 v8::Handle<Context> context = Context::New(&extensions);
4487 ASSERT(context.IsEmpty());
4488}
4489
4490THREADED_TEST(NativeFunctionDeclarationErrorEscape) {
4491 v8::HandleScope handle_scope;
4492 const char* name = "nativedeclerresc";
4493 // Syntax error in extension code - escape code in "native" means that
4494 // it's not treated as a keyword.
4495 v8::RegisterExtension(new NativeFunctionExtension(
4496 name,
4497 "nativ\\u0065 function foo();"));
4498 const char* extension_names[] = { name };
4499 v8::ExtensionConfiguration extensions(1, extension_names);
4500 v8::Handle<Context> context = Context::New(&extensions);
4501 ASSERT(context.IsEmpty());
4502}
4503
4504
Steve Blocka7e24c12009-10-30 11:49:00 +00004505static void CheckDependencies(const char* name, const char* expected) {
4506 v8::HandleScope handle_scope;
4507 v8::ExtensionConfiguration config(1, &name);
4508 LocalContext context(&config);
4509 CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
4510}
4511
4512
4513/*
4514 * Configuration:
4515 *
4516 * /-- B <--\
4517 * A <- -- D <-- E
4518 * \-- C <--/
4519 */
4520THREADED_TEST(ExtensionDependency) {
4521 static const char* kEDeps[] = { "D" };
4522 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
4523 static const char* kDDeps[] = { "B", "C" };
4524 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
4525 static const char* kBCDeps[] = { "A" };
4526 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
4527 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
4528 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
4529 CheckDependencies("A", "undefinedA");
4530 CheckDependencies("B", "undefinedAB");
4531 CheckDependencies("C", "undefinedAC");
4532 CheckDependencies("D", "undefinedABCD");
4533 CheckDependencies("E", "undefinedABCDE");
4534 v8::HandleScope handle_scope;
4535 static const char* exts[2] = { "C", "E" };
4536 v8::ExtensionConfiguration config(2, exts);
4537 LocalContext context(&config);
4538 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
4539}
4540
4541
4542static const char* kExtensionTestScript =
4543 "native function A();"
4544 "native function B();"
4545 "native function C();"
4546 "function Foo(i) {"
4547 " if (i == 0) return A();"
4548 " if (i == 1) return B();"
4549 " if (i == 2) return C();"
4550 "}";
4551
4552
4553static v8::Handle<Value> CallFun(const v8::Arguments& args) {
4554 ApiTestFuzzer::Fuzz();
Leon Clarkee46be812010-01-19 14:06:41 +00004555 if (args.IsConstructCall()) {
4556 args.This()->Set(v8_str("data"), args.Data());
4557 return v8::Null();
4558 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004559 return args.Data();
4560}
4561
4562
4563class FunctionExtension : public Extension {
4564 public:
4565 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
4566 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
4567 v8::Handle<String> name);
4568};
4569
4570
4571static int lookup_count = 0;
4572v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
4573 v8::Handle<String> name) {
4574 lookup_count++;
4575 if (name->Equals(v8_str("A"))) {
4576 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
4577 } else if (name->Equals(v8_str("B"))) {
4578 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
4579 } else if (name->Equals(v8_str("C"))) {
4580 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
4581 } else {
4582 return v8::Handle<v8::FunctionTemplate>();
4583 }
4584}
4585
4586
4587THREADED_TEST(FunctionLookup) {
4588 v8::RegisterExtension(new FunctionExtension());
4589 v8::HandleScope handle_scope;
4590 static const char* exts[1] = { "functiontest" };
4591 v8::ExtensionConfiguration config(1, exts);
4592 LocalContext context(&config);
4593 CHECK_EQ(3, lookup_count);
4594 CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
4595 CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
4596 CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
4597}
4598
4599
Leon Clarkee46be812010-01-19 14:06:41 +00004600THREADED_TEST(NativeFunctionConstructCall) {
4601 v8::RegisterExtension(new FunctionExtension());
4602 v8::HandleScope handle_scope;
4603 static const char* exts[1] = { "functiontest" };
4604 v8::ExtensionConfiguration config(1, exts);
4605 LocalContext context(&config);
Leon Clarked91b9f72010-01-27 17:25:45 +00004606 for (int i = 0; i < 10; i++) {
4607 // Run a few times to ensure that allocation of objects doesn't
4608 // change behavior of a constructor function.
4609 CHECK_EQ(v8::Integer::New(8),
4610 Script::Compile(v8_str("(new A()).data"))->Run());
4611 CHECK_EQ(v8::Integer::New(7),
4612 Script::Compile(v8_str("(new B()).data"))->Run());
4613 CHECK_EQ(v8::Integer::New(6),
4614 Script::Compile(v8_str("(new C()).data"))->Run());
4615 }
Leon Clarkee46be812010-01-19 14:06:41 +00004616}
4617
4618
Steve Blocka7e24c12009-10-30 11:49:00 +00004619static const char* last_location;
4620static const char* last_message;
4621void StoringErrorCallback(const char* location, const char* message) {
4622 if (last_location == NULL) {
4623 last_location = location;
4624 last_message = message;
4625 }
4626}
4627
4628
4629// ErrorReporting creates a circular extensions configuration and
4630// tests that the fatal error handler gets called. This renders V8
4631// unusable and therefore this test cannot be run in parallel.
4632TEST(ErrorReporting) {
4633 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
4634 static const char* aDeps[] = { "B" };
4635 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
4636 static const char* bDeps[] = { "A" };
4637 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
4638 last_location = NULL;
4639 v8::ExtensionConfiguration config(1, bDeps);
4640 v8::Handle<Context> context = Context::New(&config);
4641 CHECK(context.IsEmpty());
4642 CHECK_NE(last_location, NULL);
4643}
4644
4645
4646static const char* js_code_causing_huge_string_flattening =
4647 "var str = 'X';"
4648 "for (var i = 0; i < 30; i++) {"
4649 " str = str + str;"
4650 "}"
4651 "str.match(/X/);";
4652
4653
4654void OOMCallback(const char* location, const char* message) {
4655 exit(0);
4656}
4657
4658
4659TEST(RegexpOutOfMemory) {
4660 // Execute a script that causes out of memory when flattening a string.
4661 v8::HandleScope scope;
4662 v8::V8::SetFatalErrorHandler(OOMCallback);
4663 LocalContext context;
4664 Local<Script> script =
4665 Script::Compile(String::New(js_code_causing_huge_string_flattening));
4666 last_location = NULL;
4667 Local<Value> result = script->Run();
4668
4669 CHECK(false); // Should not return.
4670}
4671
4672
4673static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
4674 v8::Handle<Value> data) {
4675 CHECK_EQ(v8::Undefined(), data);
4676 CHECK(message->GetScriptResourceName()->IsUndefined());
4677 CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
4678 message->GetLineNumber();
4679 message->GetSourceLine();
4680}
4681
4682
4683THREADED_TEST(ErrorWithMissingScriptInfo) {
4684 v8::HandleScope scope;
4685 LocalContext context;
4686 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
4687 Script::Compile(v8_str("throw Error()"))->Run();
4688 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
4689}
4690
4691
4692int global_index = 0;
4693
4694class Snorkel {
4695 public:
4696 Snorkel() { index_ = global_index++; }
4697 int index_;
4698};
4699
4700class Whammy {
4701 public:
4702 Whammy() {
4703 cursor_ = 0;
4704 }
4705 ~Whammy() {
4706 script_.Dispose();
4707 }
4708 v8::Handle<Script> getScript() {
4709 if (script_.IsEmpty())
4710 script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
4711 return Local<Script>(*script_);
4712 }
4713
4714 public:
4715 static const int kObjectCount = 256;
4716 int cursor_;
4717 v8::Persistent<v8::Object> objects_[kObjectCount];
4718 v8::Persistent<Script> script_;
4719};
4720
4721static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
4722 Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
4723 delete snorkel;
4724 obj.ClearWeak();
4725}
4726
4727v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
4728 const AccessorInfo& info) {
4729 Whammy* whammy =
4730 static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
4731
4732 v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
4733
4734 v8::Handle<v8::Object> obj = v8::Object::New();
4735 v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
4736 if (!prev.IsEmpty()) {
4737 prev->Set(v8_str("next"), obj);
4738 prev.MakeWeak(new Snorkel(), &HandleWeakReference);
4739 whammy->objects_[whammy->cursor_].Clear();
4740 }
4741 whammy->objects_[whammy->cursor_] = global;
4742 whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
4743 return whammy->getScript()->Run();
4744}
4745
4746THREADED_TEST(WeakReference) {
4747 v8::HandleScope handle_scope;
4748 v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
Ben Murdoch3bec4d22010-07-22 14:51:16 +01004749 Whammy* whammy = new Whammy();
Steve Blocka7e24c12009-10-30 11:49:00 +00004750 templ->SetNamedPropertyHandler(WhammyPropertyGetter,
4751 0, 0, 0, 0,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01004752 v8::External::New(whammy));
Steve Blocka7e24c12009-10-30 11:49:00 +00004753 const char* extension_list[] = { "v8/gc" };
4754 v8::ExtensionConfiguration extensions(1, extension_list);
4755 v8::Persistent<Context> context = Context::New(&extensions);
4756 Context::Scope context_scope(context);
4757
4758 v8::Handle<v8::Object> interceptor = templ->NewInstance();
4759 context->Global()->Set(v8_str("whammy"), interceptor);
4760 const char* code =
4761 "var last;"
4762 "for (var i = 0; i < 10000; i++) {"
4763 " var obj = whammy.length;"
4764 " if (last) last.next = obj;"
4765 " last = obj;"
4766 "}"
4767 "gc();"
4768 "4";
4769 v8::Handle<Value> result = CompileRun(code);
4770 CHECK_EQ(4.0, result->NumberValue());
Ben Murdoch3bec4d22010-07-22 14:51:16 +01004771 delete whammy;
Steve Blocka7e24c12009-10-30 11:49:00 +00004772 context.Dispose();
4773}
4774
4775
Ben Murdoch257744e2011-11-30 15:57:28 +00004776static void DisposeAndSetFlag(v8::Persistent<v8::Value> obj, void* data) {
Steve Blockd0582a62009-12-15 09:54:21 +00004777 obj.Dispose();
4778 obj.Clear();
Steve Blockd0582a62009-12-15 09:54:21 +00004779 *(reinterpret_cast<bool*>(data)) = true;
4780}
4781
Steve Blockd0582a62009-12-15 09:54:21 +00004782
Ben Murdoch257744e2011-11-30 15:57:28 +00004783THREADED_TEST(IndependentWeakHandle) {
Steve Blockd0582a62009-12-15 09:54:21 +00004784 v8::Persistent<Context> context = Context::New();
4785 Context::Scope context_scope(context);
4786
4787 v8::Persistent<v8::Object> object_a;
Steve Blockd0582a62009-12-15 09:54:21 +00004788
4789 {
4790 v8::HandleScope handle_scope;
Steve Blockd0582a62009-12-15 09:54:21 +00004791 object_a = v8::Persistent<v8::Object>::New(v8::Object::New());
4792 }
4793
4794 bool object_a_disposed = false;
Ben Murdoch257744e2011-11-30 15:57:28 +00004795 object_a.MakeWeak(&object_a_disposed, &DisposeAndSetFlag);
4796 object_a.MarkIndependent();
4797 HEAP->PerformScavenge();
4798 CHECK(object_a_disposed);
4799}
Steve Blockd0582a62009-12-15 09:54:21 +00004800
Ben Murdoch257744e2011-11-30 15:57:28 +00004801
4802static void InvokeScavenge() {
4803 HEAP->PerformScavenge();
4804}
4805
4806
4807static void InvokeMarkSweep() {
4808 HEAP->CollectAllGarbage(false);
4809}
4810
4811
4812static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
4813 obj.Dispose();
4814 obj.Clear();
4815 *(reinterpret_cast<bool*>(data)) = true;
4816 InvokeScavenge();
4817}
4818
4819
4820static void ForceMarkSweep(v8::Persistent<v8::Value> obj, void* data) {
4821 obj.Dispose();
4822 obj.Clear();
4823 *(reinterpret_cast<bool*>(data)) = true;
4824 InvokeMarkSweep();
4825}
4826
4827
4828THREADED_TEST(GCFromWeakCallbacks) {
4829 v8::Persistent<Context> context = Context::New();
4830 Context::Scope context_scope(context);
4831
4832 static const int kNumberOfGCTypes = 2;
4833 v8::WeakReferenceCallback gc_forcing_callback[kNumberOfGCTypes] =
4834 {&ForceScavenge, &ForceMarkSweep};
4835
4836 typedef void (*GCInvoker)();
4837 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
4838
4839 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
4840 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
4841 v8::Persistent<v8::Object> object;
4842 {
4843 v8::HandleScope handle_scope;
4844 object = v8::Persistent<v8::Object>::New(v8::Object::New());
4845 }
4846 bool disposed = false;
4847 object.MakeWeak(&disposed, gc_forcing_callback[inner_gc]);
4848 object.MarkIndependent();
4849 invoke_gc[outer_gc]();
4850 CHECK(disposed);
4851 }
Steve Blockd0582a62009-12-15 09:54:21 +00004852 }
Ben Murdoch257744e2011-11-30 15:57:28 +00004853}
4854
4855
4856static void RevivingCallback(v8::Persistent<v8::Value> obj, void* data) {
4857 obj.ClearWeak();
4858 *(reinterpret_cast<bool*>(data)) = true;
4859}
4860
4861
4862THREADED_TEST(IndependentHandleRevival) {
4863 v8::Persistent<Context> context = Context::New();
4864 Context::Scope context_scope(context);
4865
4866 v8::Persistent<v8::Object> object;
4867 {
4868 v8::HandleScope handle_scope;
4869 object = v8::Persistent<v8::Object>::New(v8::Object::New());
4870 object->Set(v8_str("x"), v8::Integer::New(1));
4871 v8::Local<String> y_str = v8_str("y");
4872 object->Set(y_str, y_str);
4873 }
4874 bool revived = false;
4875 object.MakeWeak(&revived, &RevivingCallback);
4876 object.MarkIndependent();
4877 HEAP->PerformScavenge();
4878 CHECK(revived);
4879 HEAP->CollectAllGarbage(true);
4880 {
4881 v8::HandleScope handle_scope;
4882 v8::Local<String> y_str = v8_str("y");
4883 CHECK_EQ(v8::Integer::New(1), object->Get(v8_str("x")));
4884 CHECK(object->Get(y_str)->Equals(y_str));
4885 }
Steve Blockd0582a62009-12-15 09:54:21 +00004886}
4887
4888
Steve Blocka7e24c12009-10-30 11:49:00 +00004889v8::Handle<Function> args_fun;
4890
4891
4892static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
4893 ApiTestFuzzer::Fuzz();
4894 CHECK_EQ(args_fun, args.Callee());
4895 CHECK_EQ(3, args.Length());
4896 CHECK_EQ(v8::Integer::New(1), args[0]);
4897 CHECK_EQ(v8::Integer::New(2), args[1]);
4898 CHECK_EQ(v8::Integer::New(3), args[2]);
4899 CHECK_EQ(v8::Undefined(), args[3]);
4900 v8::HandleScope scope;
Steve Block44f0eee2011-05-26 01:26:41 +01004901 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +00004902 return v8::Undefined();
4903}
4904
4905
4906THREADED_TEST(Arguments) {
4907 v8::HandleScope scope;
4908 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
4909 global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
4910 LocalContext context(NULL, global);
Steve Block6ded16b2010-05-10 14:33:55 +01004911 args_fun = context->Global()->Get(v8_str("f")).As<Function>();
Steve Blocka7e24c12009-10-30 11:49:00 +00004912 v8_compile("f(1, 2, 3)")->Run();
4913}
4914
4915
Steve Blocka7e24c12009-10-30 11:49:00 +00004916static v8::Handle<Value> NoBlockGetterX(Local<String> name,
4917 const AccessorInfo&) {
4918 return v8::Handle<Value>();
4919}
4920
4921
4922static v8::Handle<Value> NoBlockGetterI(uint32_t index,
4923 const AccessorInfo&) {
4924 return v8::Handle<Value>();
4925}
4926
4927
4928static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
4929 const AccessorInfo&) {
4930 if (!name->Equals(v8_str("foo"))) {
4931 return v8::Handle<v8::Boolean>(); // not intercepted
4932 }
4933
4934 return v8::False(); // intercepted, and don't delete the property
4935}
4936
4937
4938static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
4939 if (index != 2) {
4940 return v8::Handle<v8::Boolean>(); // not intercepted
4941 }
4942
4943 return v8::False(); // intercepted, and don't delete the property
4944}
4945
4946
4947THREADED_TEST(Deleter) {
4948 v8::HandleScope scope;
4949 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4950 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
4951 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
4952 LocalContext context;
4953 context->Global()->Set(v8_str("k"), obj->NewInstance());
4954 CompileRun(
4955 "k.foo = 'foo';"
4956 "k.bar = 'bar';"
4957 "k[2] = 2;"
4958 "k[4] = 4;");
4959 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
4960 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
4961
4962 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
4963 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
4964
4965 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
4966 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
4967
4968 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
4969 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
4970}
4971
4972
4973static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
4974 ApiTestFuzzer::Fuzz();
4975 if (name->Equals(v8_str("foo")) ||
4976 name->Equals(v8_str("bar")) ||
4977 name->Equals(v8_str("baz"))) {
4978 return v8::Undefined();
4979 }
4980 return v8::Handle<Value>();
4981}
4982
4983
4984static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
4985 ApiTestFuzzer::Fuzz();
4986 if (index == 0 || index == 1) return v8::Undefined();
4987 return v8::Handle<Value>();
4988}
4989
4990
4991static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
4992 ApiTestFuzzer::Fuzz();
4993 v8::Handle<v8::Array> result = v8::Array::New(3);
4994 result->Set(v8::Integer::New(0), v8_str("foo"));
4995 result->Set(v8::Integer::New(1), v8_str("bar"));
4996 result->Set(v8::Integer::New(2), v8_str("baz"));
4997 return result;
4998}
4999
5000
5001static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
5002 ApiTestFuzzer::Fuzz();
5003 v8::Handle<v8::Array> result = v8::Array::New(2);
5004 result->Set(v8::Integer::New(0), v8_str("0"));
5005 result->Set(v8::Integer::New(1), v8_str("1"));
5006 return result;
5007}
5008
5009
5010THREADED_TEST(Enumerators) {
5011 v8::HandleScope scope;
5012 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5013 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
5014 obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
5015 LocalContext context;
5016 context->Global()->Set(v8_str("k"), obj->NewInstance());
5017 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
5018 "k[10] = 0;"
5019 "k.a = 0;"
5020 "k[5] = 0;"
5021 "k.b = 0;"
5022 "k[4294967295] = 0;"
5023 "k.c = 0;"
5024 "k[4294967296] = 0;"
5025 "k.d = 0;"
5026 "k[140000] = 0;"
5027 "k.e = 0;"
5028 "k[30000000000] = 0;"
5029 "k.f = 0;"
5030 "var result = [];"
5031 "for (var prop in k) {"
5032 " result.push(prop);"
5033 "}"
5034 "result"));
5035 // Check that we get all the property names returned including the
5036 // ones from the enumerators in the right order: indexed properties
5037 // in numerical order, indexed interceptor properties, named
5038 // properties in insertion order, named interceptor properties.
5039 // This order is not mandated by the spec, so this test is just
5040 // documenting our behavior.
5041 CHECK_EQ(17, result->Length());
5042 // Indexed properties in numerical order.
5043 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
5044 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
5045 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
5046 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
5047 // Indexed interceptor properties in the order they are returned
5048 // from the enumerator interceptor.
5049 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
5050 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
5051 // Named properties in insertion order.
5052 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
5053 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
5054 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
5055 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
5056 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
5057 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
5058 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
5059 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
5060 // Named interceptor properties.
5061 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
5062 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
5063 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
5064}
5065
5066
5067int p_getter_count;
5068int p_getter_count2;
5069
5070
5071static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
5072 ApiTestFuzzer::Fuzz();
5073 p_getter_count++;
5074 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5075 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
5076 if (name->Equals(v8_str("p1"))) {
5077 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
5078 } else if (name->Equals(v8_str("p2"))) {
5079 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
5080 } else if (name->Equals(v8_str("p3"))) {
5081 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
5082 } else if (name->Equals(v8_str("p4"))) {
5083 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
5084 }
5085 return v8::Undefined();
5086}
5087
5088
5089static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
5090 ApiTestFuzzer::Fuzz();
5091 LocalContext context;
5092 context->Global()->Set(v8_str("o1"), obj->NewInstance());
5093 CompileRun(
5094 "o1.__proto__ = { };"
5095 "var o2 = { __proto__: o1 };"
5096 "var o3 = { __proto__: o2 };"
5097 "var o4 = { __proto__: o3 };"
5098 "for (var i = 0; i < 10; i++) o4.p4;"
5099 "for (var i = 0; i < 10; i++) o3.p3;"
5100 "for (var i = 0; i < 10; i++) o2.p2;"
5101 "for (var i = 0; i < 10; i++) o1.p1;");
5102}
5103
5104
5105static v8::Handle<Value> PGetter2(Local<String> name,
5106 const AccessorInfo& info) {
5107 ApiTestFuzzer::Fuzz();
5108 p_getter_count2++;
5109 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5110 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
5111 if (name->Equals(v8_str("p1"))) {
5112 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
5113 } else if (name->Equals(v8_str("p2"))) {
5114 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
5115 } else if (name->Equals(v8_str("p3"))) {
5116 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
5117 } else if (name->Equals(v8_str("p4"))) {
5118 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
5119 }
5120 return v8::Undefined();
5121}
5122
5123
5124THREADED_TEST(GetterHolders) {
5125 v8::HandleScope scope;
5126 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5127 obj->SetAccessor(v8_str("p1"), PGetter);
5128 obj->SetAccessor(v8_str("p2"), PGetter);
5129 obj->SetAccessor(v8_str("p3"), PGetter);
5130 obj->SetAccessor(v8_str("p4"), PGetter);
5131 p_getter_count = 0;
5132 RunHolderTest(obj);
5133 CHECK_EQ(40, p_getter_count);
5134}
5135
5136
5137THREADED_TEST(PreInterceptorHolders) {
5138 v8::HandleScope scope;
5139 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5140 obj->SetNamedPropertyHandler(PGetter2);
5141 p_getter_count2 = 0;
5142 RunHolderTest(obj);
5143 CHECK_EQ(40, p_getter_count2);
5144}
5145
5146
5147THREADED_TEST(ObjectInstantiation) {
5148 v8::HandleScope scope;
5149 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5150 templ->SetAccessor(v8_str("t"), PGetter2);
5151 LocalContext context;
5152 context->Global()->Set(v8_str("o"), templ->NewInstance());
5153 for (int i = 0; i < 100; i++) {
5154 v8::HandleScope inner_scope;
5155 v8::Handle<v8::Object> obj = templ->NewInstance();
5156 CHECK_NE(obj, context->Global()->Get(v8_str("o")));
5157 context->Global()->Set(v8_str("o2"), obj);
5158 v8::Handle<Value> value =
5159 Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
5160 CHECK_EQ(v8::True(), value);
5161 context->Global()->Set(v8_str("o"), obj);
5162 }
5163}
5164
5165
Ben Murdochb0fe1622011-05-05 13:52:32 +01005166static int StrCmp16(uint16_t* a, uint16_t* b) {
5167 while (true) {
5168 if (*a == 0 && *b == 0) return 0;
5169 if (*a != *b) return 0 + *a - *b;
5170 a++;
5171 b++;
5172 }
5173}
5174
5175
5176static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
5177 while (true) {
5178 if (n-- == 0) return 0;
5179 if (*a == 0 && *b == 0) return 0;
5180 if (*a != *b) return 0 + *a - *b;
5181 a++;
5182 b++;
5183 }
5184}
5185
5186
Steve Blocka7e24c12009-10-30 11:49:00 +00005187THREADED_TEST(StringWrite) {
5188 v8::HandleScope scope;
5189 v8::Handle<String> str = v8_str("abcde");
Ben Murdochb0fe1622011-05-05 13:52:32 +01005190 // abc<Icelandic eth><Unicode snowman>.
5191 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
5192
5193 CHECK_EQ(5, str2->Length());
Steve Blocka7e24c12009-10-30 11:49:00 +00005194
5195 char buf[100];
Ben Murdochb0fe1622011-05-05 13:52:32 +01005196 char utf8buf[100];
5197 uint16_t wbuf[100];
Steve Blocka7e24c12009-10-30 11:49:00 +00005198 int len;
Ben Murdochb0fe1622011-05-05 13:52:32 +01005199 int charlen;
5200
5201 memset(utf8buf, 0x1, sizeof(utf8buf));
5202 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01005203 CHECK_EQ(9, len);
5204 CHECK_EQ(5, charlen);
5205 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005206
5207 memset(utf8buf, 0x1, sizeof(utf8buf));
5208 len = str2->WriteUtf8(utf8buf, 8, &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01005209 CHECK_EQ(8, len);
5210 CHECK_EQ(5, charlen);
5211 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005212
5213 memset(utf8buf, 0x1, sizeof(utf8buf));
5214 len = str2->WriteUtf8(utf8buf, 7, &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01005215 CHECK_EQ(5, len);
5216 CHECK_EQ(4, charlen);
5217 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005218
5219 memset(utf8buf, 0x1, sizeof(utf8buf));
5220 len = str2->WriteUtf8(utf8buf, 6, &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01005221 CHECK_EQ(5, len);
5222 CHECK_EQ(4, charlen);
5223 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005224
5225 memset(utf8buf, 0x1, sizeof(utf8buf));
5226 len = str2->WriteUtf8(utf8buf, 5, &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01005227 CHECK_EQ(5, len);
5228 CHECK_EQ(4, charlen);
5229 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005230
5231 memset(utf8buf, 0x1, sizeof(utf8buf));
5232 len = str2->WriteUtf8(utf8buf, 4, &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01005233 CHECK_EQ(3, len);
5234 CHECK_EQ(3, charlen);
5235 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005236
5237 memset(utf8buf, 0x1, sizeof(utf8buf));
5238 len = str2->WriteUtf8(utf8buf, 3, &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01005239 CHECK_EQ(3, len);
5240 CHECK_EQ(3, charlen);
5241 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005242
5243 memset(utf8buf, 0x1, sizeof(utf8buf));
5244 len = str2->WriteUtf8(utf8buf, 2, &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01005245 CHECK_EQ(2, len);
5246 CHECK_EQ(2, charlen);
5247 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
Steve Blocka7e24c12009-10-30 11:49:00 +00005248
5249 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005250 memset(wbuf, 0x1, sizeof(wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00005251 len = str->WriteAscii(buf);
Steve Block44f0eee2011-05-26 01:26:41 +01005252 CHECK_EQ(5, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005253 len = str->Write(wbuf);
Steve Block44f0eee2011-05-26 01:26:41 +01005254 CHECK_EQ(5, len);
5255 CHECK_EQ(0, strcmp("abcde", buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005256 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
Steve Block44f0eee2011-05-26 01:26:41 +01005257 CHECK_EQ(0, StrCmp16(answer1, wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00005258
5259 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005260 memset(wbuf, 0x1, sizeof(wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00005261 len = str->WriteAscii(buf, 0, 4);
Steve Block44f0eee2011-05-26 01:26:41 +01005262 CHECK_EQ(4, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005263 len = str->Write(wbuf, 0, 4);
Steve Block44f0eee2011-05-26 01:26:41 +01005264 CHECK_EQ(4, len);
5265 CHECK_EQ(0, strncmp("abcd\1", buf, 5));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005266 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
Steve Block44f0eee2011-05-26 01:26:41 +01005267 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
Steve Blocka7e24c12009-10-30 11:49:00 +00005268
5269 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005270 memset(wbuf, 0x1, sizeof(wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00005271 len = str->WriteAscii(buf, 0, 5);
Steve Block44f0eee2011-05-26 01:26:41 +01005272 CHECK_EQ(5, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005273 len = str->Write(wbuf, 0, 5);
Steve Block44f0eee2011-05-26 01:26:41 +01005274 CHECK_EQ(5, len);
5275 CHECK_EQ(0, strncmp("abcde\1", buf, 6));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005276 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
Steve Block44f0eee2011-05-26 01:26:41 +01005277 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
Steve Blocka7e24c12009-10-30 11:49:00 +00005278
5279 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005280 memset(wbuf, 0x1, sizeof(wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00005281 len = str->WriteAscii(buf, 0, 6);
Steve Block44f0eee2011-05-26 01:26:41 +01005282 CHECK_EQ(5, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005283 len = str->Write(wbuf, 0, 6);
Steve Block44f0eee2011-05-26 01:26:41 +01005284 CHECK_EQ(5, len);
5285 CHECK_EQ(0, strcmp("abcde", buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005286 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
Steve Block44f0eee2011-05-26 01:26:41 +01005287 CHECK_EQ(0, StrCmp16(answer4, wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00005288
5289 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005290 memset(wbuf, 0x1, sizeof(wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00005291 len = str->WriteAscii(buf, 4, -1);
Steve Block44f0eee2011-05-26 01:26:41 +01005292 CHECK_EQ(1, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005293 len = str->Write(wbuf, 4, -1);
Steve Block44f0eee2011-05-26 01:26:41 +01005294 CHECK_EQ(1, len);
5295 CHECK_EQ(0, strcmp("e", buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005296 uint16_t answer5[] = {'e', '\0'};
Steve Block44f0eee2011-05-26 01:26:41 +01005297 CHECK_EQ(0, StrCmp16(answer5, wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00005298
5299 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005300 memset(wbuf, 0x1, sizeof(wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00005301 len = str->WriteAscii(buf, 4, 6);
Steve Block44f0eee2011-05-26 01:26:41 +01005302 CHECK_EQ(1, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005303 len = str->Write(wbuf, 4, 6);
Steve Block44f0eee2011-05-26 01:26:41 +01005304 CHECK_EQ(1, len);
5305 CHECK_EQ(0, strcmp("e", buf));
5306 CHECK_EQ(0, StrCmp16(answer5, wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00005307
5308 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005309 memset(wbuf, 0x1, sizeof(wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00005310 len = str->WriteAscii(buf, 4, 1);
Steve Block44f0eee2011-05-26 01:26:41 +01005311 CHECK_EQ(1, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005312 len = str->Write(wbuf, 4, 1);
Steve Block44f0eee2011-05-26 01:26:41 +01005313 CHECK_EQ(1, len);
5314 CHECK_EQ(0, strncmp("e\1", buf, 2));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005315 uint16_t answer6[] = {'e', 0x101};
Steve Block44f0eee2011-05-26 01:26:41 +01005316 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005317
5318 memset(buf, 0x1, sizeof(buf));
5319 memset(wbuf, 0x1, sizeof(wbuf));
5320 len = str->WriteAscii(buf, 3, 1);
Steve Block44f0eee2011-05-26 01:26:41 +01005321 CHECK_EQ(1, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005322 len = str->Write(wbuf, 3, 1);
Steve Block44f0eee2011-05-26 01:26:41 +01005323 CHECK_EQ(1, len);
5324 CHECK_EQ(0, strncmp("d\1", buf, 2));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005325 uint16_t answer7[] = {'d', 0x101};
Steve Block44f0eee2011-05-26 01:26:41 +01005326 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005327
5328 memset(wbuf, 0x1, sizeof(wbuf));
5329 wbuf[5] = 'X';
5330 len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
5331 CHECK_EQ(5, len);
5332 CHECK_EQ('X', wbuf[5]);
5333 uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
5334 uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
5335 CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
5336 CHECK_NE(0, StrCmp16(answer8b, wbuf));
5337 wbuf[5] = '\0';
5338 CHECK_EQ(0, StrCmp16(answer8b, wbuf));
5339
5340 memset(buf, 0x1, sizeof(buf));
5341 buf[5] = 'X';
5342 len = str->WriteAscii(buf, 0, 6, String::NO_NULL_TERMINATION);
5343 CHECK_EQ(5, len);
5344 CHECK_EQ('X', buf[5]);
5345 CHECK_EQ(0, strncmp("abcde", buf, 5));
5346 CHECK_NE(0, strcmp("abcde", buf));
5347 buf[5] = '\0';
5348 CHECK_EQ(0, strcmp("abcde", buf));
5349
5350 memset(utf8buf, 0x1, sizeof(utf8buf));
5351 utf8buf[8] = 'X';
5352 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
5353 String::NO_NULL_TERMINATION);
5354 CHECK_EQ(8, len);
5355 CHECK_EQ('X', utf8buf[8]);
5356 CHECK_EQ(5, charlen);
5357 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
5358 CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
5359 utf8buf[8] = '\0';
5360 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
Steve Blocka7e24c12009-10-30 11:49:00 +00005361}
5362
5363
5364THREADED_TEST(ToArrayIndex) {
5365 v8::HandleScope scope;
5366 LocalContext context;
5367
5368 v8::Handle<String> str = v8_str("42");
5369 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
5370 CHECK(!index.IsEmpty());
5371 CHECK_EQ(42.0, index->Uint32Value());
5372 str = v8_str("42asdf");
5373 index = str->ToArrayIndex();
5374 CHECK(index.IsEmpty());
5375 str = v8_str("-42");
5376 index = str->ToArrayIndex();
5377 CHECK(index.IsEmpty());
5378 str = v8_str("4294967295");
5379 index = str->ToArrayIndex();
5380 CHECK(!index.IsEmpty());
5381 CHECK_EQ(4294967295.0, index->Uint32Value());
5382 v8::Handle<v8::Number> num = v8::Number::New(1);
5383 index = num->ToArrayIndex();
5384 CHECK(!index.IsEmpty());
5385 CHECK_EQ(1.0, index->Uint32Value());
5386 num = v8::Number::New(-1);
5387 index = num->ToArrayIndex();
5388 CHECK(index.IsEmpty());
5389 v8::Handle<v8::Object> obj = v8::Object::New();
5390 index = obj->ToArrayIndex();
5391 CHECK(index.IsEmpty());
5392}
5393
5394
5395THREADED_TEST(ErrorConstruction) {
5396 v8::HandleScope scope;
5397 LocalContext context;
5398
5399 v8::Handle<String> foo = v8_str("foo");
5400 v8::Handle<String> message = v8_str("message");
5401 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
5402 CHECK(range_error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01005403 v8::Handle<v8::Object> range_obj = range_error.As<v8::Object>();
5404 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00005405 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
5406 CHECK(reference_error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01005407 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00005408 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
5409 CHECK(syntax_error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01005410 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00005411 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
5412 CHECK(type_error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01005413 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00005414 v8::Handle<Value> error = v8::Exception::Error(foo);
5415 CHECK(error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01005416 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00005417}
5418
5419
5420static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
5421 ApiTestFuzzer::Fuzz();
5422 return v8_num(10);
5423}
5424
5425
5426static void YSetter(Local<String> name,
5427 Local<Value> value,
5428 const AccessorInfo& info) {
5429 if (info.This()->Has(name)) {
5430 info.This()->Delete(name);
5431 }
5432 info.This()->Set(name, value);
5433}
5434
5435
5436THREADED_TEST(DeleteAccessor) {
5437 v8::HandleScope scope;
5438 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5439 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
5440 LocalContext context;
5441 v8::Handle<v8::Object> holder = obj->NewInstance();
5442 context->Global()->Set(v8_str("holder"), holder);
5443 v8::Handle<Value> result = CompileRun(
5444 "holder.y = 11; holder.y = 12; holder.y");
5445 CHECK_EQ(12, result->Uint32Value());
5446}
5447
5448
5449THREADED_TEST(TypeSwitch) {
5450 v8::HandleScope scope;
5451 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
5452 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
5453 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
5454 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
5455 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
5456 LocalContext context;
5457 v8::Handle<v8::Object> obj0 = v8::Object::New();
5458 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
5459 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
5460 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
5461 for (int i = 0; i < 10; i++) {
5462 CHECK_EQ(0, type_switch->match(obj0));
5463 CHECK_EQ(1, type_switch->match(obj1));
5464 CHECK_EQ(2, type_switch->match(obj2));
5465 CHECK_EQ(3, type_switch->match(obj3));
5466 CHECK_EQ(3, type_switch->match(obj3));
5467 CHECK_EQ(2, type_switch->match(obj2));
5468 CHECK_EQ(1, type_switch->match(obj1));
5469 CHECK_EQ(0, type_switch->match(obj0));
5470 }
5471}
5472
5473
5474// For use within the TestSecurityHandler() test.
5475static bool g_security_callback_result = false;
5476static bool NamedSecurityTestCallback(Local<v8::Object> global,
5477 Local<Value> name,
5478 v8::AccessType type,
5479 Local<Value> data) {
5480 // Always allow read access.
5481 if (type == v8::ACCESS_GET)
5482 return true;
5483
5484 // Sometimes allow other access.
5485 return g_security_callback_result;
5486}
5487
5488
5489static bool IndexedSecurityTestCallback(Local<v8::Object> global,
5490 uint32_t key,
5491 v8::AccessType type,
5492 Local<Value> data) {
5493 // Always allow read access.
5494 if (type == v8::ACCESS_GET)
5495 return true;
5496
5497 // Sometimes allow other access.
5498 return g_security_callback_result;
5499}
5500
5501
5502static int trouble_nesting = 0;
5503static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
5504 ApiTestFuzzer::Fuzz();
5505 trouble_nesting++;
5506
5507 // Call a JS function that throws an uncaught exception.
5508 Local<v8::Object> arg_this = Context::GetCurrent()->Global();
5509 Local<Value> trouble_callee = (trouble_nesting == 3) ?
5510 arg_this->Get(v8_str("trouble_callee")) :
5511 arg_this->Get(v8_str("trouble_caller"));
5512 CHECK(trouble_callee->IsFunction());
5513 return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
5514}
5515
5516
5517static int report_count = 0;
5518static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
5519 v8::Handle<Value>) {
5520 report_count++;
5521}
5522
5523
5524// Counts uncaught exceptions, but other tests running in parallel
5525// also have uncaught exceptions.
5526TEST(ApiUncaughtException) {
5527 report_count = 0;
5528 v8::HandleScope scope;
5529 LocalContext env;
5530 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
5531
5532 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
5533 v8::Local<v8::Object> global = env->Global();
5534 global->Set(v8_str("trouble"), fun->GetFunction());
5535
5536 Script::Compile(v8_str("function trouble_callee() {"
5537 " var x = null;"
5538 " return x.foo;"
5539 "};"
5540 "function trouble_caller() {"
5541 " trouble();"
5542 "};"))->Run();
5543 Local<Value> trouble = global->Get(v8_str("trouble"));
5544 CHECK(trouble->IsFunction());
5545 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
5546 CHECK(trouble_callee->IsFunction());
5547 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
5548 CHECK(trouble_caller->IsFunction());
5549 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
5550 CHECK_EQ(1, report_count);
5551 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
5552}
5553
Leon Clarke4515c472010-02-03 11:58:03 +00005554static const char* script_resource_name = "ExceptionInNativeScript.js";
5555static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
5556 v8::Handle<Value>) {
5557 v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
5558 CHECK(!name_val.IsEmpty() && name_val->IsString());
5559 v8::String::AsciiValue name(message->GetScriptResourceName());
5560 CHECK_EQ(script_resource_name, *name);
5561 CHECK_EQ(3, message->GetLineNumber());
5562 v8::String::AsciiValue source_line(message->GetSourceLine());
5563 CHECK_EQ(" new o.foo();", *source_line);
5564}
5565
5566TEST(ExceptionInNativeScript) {
5567 v8::HandleScope scope;
5568 LocalContext env;
5569 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
5570
5571 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
5572 v8::Local<v8::Object> global = env->Global();
5573 global->Set(v8_str("trouble"), fun->GetFunction());
5574
5575 Script::Compile(v8_str("function trouble() {\n"
5576 " var o = {};\n"
5577 " new o.foo();\n"
5578 "};"), v8::String::New(script_resource_name))->Run();
5579 Local<Value> trouble = global->Get(v8_str("trouble"));
5580 CHECK(trouble->IsFunction());
5581 Function::Cast(*trouble)->Call(global, 0, NULL);
5582 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
5583}
5584
Steve Blocka7e24c12009-10-30 11:49:00 +00005585
5586TEST(CompilationErrorUsingTryCatchHandler) {
5587 v8::HandleScope scope;
5588 LocalContext env;
5589 v8::TryCatch try_catch;
5590 Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
5591 CHECK_NE(NULL, *try_catch.Exception());
5592 CHECK(try_catch.HasCaught());
5593}
5594
5595
5596TEST(TryCatchFinallyUsingTryCatchHandler) {
5597 v8::HandleScope scope;
5598 LocalContext env;
5599 v8::TryCatch try_catch;
5600 Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
5601 CHECK(!try_catch.HasCaught());
5602 Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
5603 CHECK(try_catch.HasCaught());
5604 try_catch.Reset();
5605 Script::Compile(v8_str("(function() {"
5606 "try { throw ''; } finally { return; }"
5607 "})()"))->Run();
5608 CHECK(!try_catch.HasCaught());
5609 Script::Compile(v8_str("(function()"
5610 " { try { throw ''; } finally { throw 0; }"
5611 "})()"))->Run();
5612 CHECK(try_catch.HasCaught());
5613}
5614
5615
5616// SecurityHandler can't be run twice
5617TEST(SecurityHandler) {
5618 v8::HandleScope scope0;
5619 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
5620 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
5621 IndexedSecurityTestCallback);
5622 // Create an environment
5623 v8::Persistent<Context> context0 =
5624 Context::New(NULL, global_template);
5625 context0->Enter();
5626
5627 v8::Handle<v8::Object> global0 = context0->Global();
5628 v8::Handle<Script> script0 = v8_compile("foo = 111");
5629 script0->Run();
5630 global0->Set(v8_str("0"), v8_num(999));
5631 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
5632 CHECK_EQ(111, foo0->Int32Value());
5633 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
5634 CHECK_EQ(999, z0->Int32Value());
5635
5636 // Create another environment, should fail security checks.
5637 v8::HandleScope scope1;
5638
5639 v8::Persistent<Context> context1 =
5640 Context::New(NULL, global_template);
5641 context1->Enter();
5642
5643 v8::Handle<v8::Object> global1 = context1->Global();
5644 global1->Set(v8_str("othercontext"), global0);
5645 // This set will fail the security check.
5646 v8::Handle<Script> script1 =
5647 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
5648 script1->Run();
5649 // This read will pass the security check.
5650 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
5651 CHECK_EQ(111, foo1->Int32Value());
5652 // This read will pass the security check.
5653 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
5654 CHECK_EQ(999, z1->Int32Value());
5655
5656 // Create another environment, should pass security checks.
5657 { g_security_callback_result = true; // allow security handler to pass.
5658 v8::HandleScope scope2;
5659 LocalContext context2;
5660 v8::Handle<v8::Object> global2 = context2->Global();
5661 global2->Set(v8_str("othercontext"), global0);
5662 v8::Handle<Script> script2 =
5663 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
5664 script2->Run();
5665 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
5666 CHECK_EQ(333, foo2->Int32Value());
5667 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
5668 CHECK_EQ(888, z2->Int32Value());
5669 }
5670
5671 context1->Exit();
5672 context1.Dispose();
5673
5674 context0->Exit();
5675 context0.Dispose();
5676}
5677
5678
5679THREADED_TEST(SecurityChecks) {
5680 v8::HandleScope handle_scope;
5681 LocalContext env1;
5682 v8::Persistent<Context> env2 = Context::New();
5683
5684 Local<Value> foo = v8_str("foo");
5685 Local<Value> bar = v8_str("bar");
5686
5687 // Set to the same domain.
5688 env1->SetSecurityToken(foo);
5689
5690 // Create a function in env1.
5691 Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
5692 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
5693 CHECK(spy->IsFunction());
5694
5695 // Create another function accessing global objects.
5696 Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
5697 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
5698 CHECK(spy2->IsFunction());
5699
5700 // Switch to env2 in the same domain and invoke spy on env2.
5701 {
5702 env2->SetSecurityToken(foo);
5703 // Enter env2
5704 Context::Scope scope_env2(env2);
5705 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
5706 CHECK(result->IsFunction());
5707 }
5708
5709 {
5710 env2->SetSecurityToken(bar);
5711 Context::Scope scope_env2(env2);
5712
5713 // Call cross_domain_call, it should throw an exception
5714 v8::TryCatch try_catch;
5715 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
5716 CHECK(try_catch.HasCaught());
5717 }
5718
5719 env2.Dispose();
5720}
5721
5722
5723// Regression test case for issue 1183439.
5724THREADED_TEST(SecurityChecksForPrototypeChain) {
5725 v8::HandleScope scope;
5726 LocalContext current;
5727 v8::Persistent<Context> other = Context::New();
5728
5729 // Change context to be able to get to the Object function in the
5730 // other context without hitting the security checks.
5731 v8::Local<Value> other_object;
5732 { Context::Scope scope(other);
5733 other_object = other->Global()->Get(v8_str("Object"));
5734 other->Global()->Set(v8_num(42), v8_num(87));
5735 }
5736
5737 current->Global()->Set(v8_str("other"), other->Global());
5738 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
5739
5740 // Make sure the security check fails here and we get an undefined
5741 // result instead of getting the Object function. Repeat in a loop
5742 // to make sure to exercise the IC code.
5743 v8::Local<Script> access_other0 = v8_compile("other.Object");
5744 v8::Local<Script> access_other1 = v8_compile("other[42]");
5745 for (int i = 0; i < 5; i++) {
5746 CHECK(!access_other0->Run()->Equals(other_object));
5747 CHECK(access_other0->Run()->IsUndefined());
5748 CHECK(!access_other1->Run()->Equals(v8_num(87)));
5749 CHECK(access_other1->Run()->IsUndefined());
5750 }
5751
5752 // Create an object that has 'other' in its prototype chain and make
5753 // sure we cannot access the Object function indirectly through
5754 // that. Repeat in a loop to make sure to exercise the IC code.
5755 v8_compile("function F() { };"
5756 "F.prototype = other;"
5757 "var f = new F();")->Run();
5758 v8::Local<Script> access_f0 = v8_compile("f.Object");
5759 v8::Local<Script> access_f1 = v8_compile("f[42]");
5760 for (int j = 0; j < 5; j++) {
5761 CHECK(!access_f0->Run()->Equals(other_object));
5762 CHECK(access_f0->Run()->IsUndefined());
5763 CHECK(!access_f1->Run()->Equals(v8_num(87)));
5764 CHECK(access_f1->Run()->IsUndefined());
5765 }
5766
5767 // Now it gets hairy: Set the prototype for the other global object
5768 // to be the current global object. The prototype chain for 'f' now
5769 // goes through 'other' but ends up in the current global object.
5770 { Context::Scope scope(other);
5771 other->Global()->Set(v8_str("__proto__"), current->Global());
5772 }
5773 // Set a named and an index property on the current global
5774 // object. To force the lookup to go through the other global object,
5775 // the properties must not exist in the other global object.
5776 current->Global()->Set(v8_str("foo"), v8_num(100));
5777 current->Global()->Set(v8_num(99), v8_num(101));
5778 // Try to read the properties from f and make sure that the access
5779 // gets stopped by the security checks on the other global object.
5780 Local<Script> access_f2 = v8_compile("f.foo");
5781 Local<Script> access_f3 = v8_compile("f[99]");
5782 for (int k = 0; k < 5; k++) {
5783 CHECK(!access_f2->Run()->Equals(v8_num(100)));
5784 CHECK(access_f2->Run()->IsUndefined());
5785 CHECK(!access_f3->Run()->Equals(v8_num(101)));
5786 CHECK(access_f3->Run()->IsUndefined());
5787 }
5788 other.Dispose();
5789}
5790
5791
5792THREADED_TEST(CrossDomainDelete) {
5793 v8::HandleScope handle_scope;
5794 LocalContext env1;
5795 v8::Persistent<Context> env2 = Context::New();
5796
5797 Local<Value> foo = v8_str("foo");
5798 Local<Value> bar = v8_str("bar");
5799
5800 // Set to the same domain.
5801 env1->SetSecurityToken(foo);
5802 env2->SetSecurityToken(foo);
5803
5804 env1->Global()->Set(v8_str("prop"), v8_num(3));
5805 env2->Global()->Set(v8_str("env1"), env1->Global());
5806
5807 // Change env2 to a different domain and delete env1.prop.
5808 env2->SetSecurityToken(bar);
5809 {
5810 Context::Scope scope_env2(env2);
5811 Local<Value> result =
5812 Script::Compile(v8_str("delete env1.prop"))->Run();
5813 CHECK(result->IsFalse());
5814 }
5815
5816 // Check that env1.prop still exists.
5817 Local<Value> v = env1->Global()->Get(v8_str("prop"));
5818 CHECK(v->IsNumber());
5819 CHECK_EQ(3, v->Int32Value());
5820
5821 env2.Dispose();
5822}
5823
5824
5825THREADED_TEST(CrossDomainIsPropertyEnumerable) {
5826 v8::HandleScope handle_scope;
5827 LocalContext env1;
5828 v8::Persistent<Context> env2 = Context::New();
5829
5830 Local<Value> foo = v8_str("foo");
5831 Local<Value> bar = v8_str("bar");
5832
5833 // Set to the same domain.
5834 env1->SetSecurityToken(foo);
5835 env2->SetSecurityToken(foo);
5836
5837 env1->Global()->Set(v8_str("prop"), v8_num(3));
5838 env2->Global()->Set(v8_str("env1"), env1->Global());
5839
5840 // env1.prop is enumerable in env2.
5841 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
5842 {
5843 Context::Scope scope_env2(env2);
5844 Local<Value> result = Script::Compile(test)->Run();
5845 CHECK(result->IsTrue());
5846 }
5847
5848 // Change env2 to a different domain and test again.
5849 env2->SetSecurityToken(bar);
5850 {
5851 Context::Scope scope_env2(env2);
5852 Local<Value> result = Script::Compile(test)->Run();
5853 CHECK(result->IsFalse());
5854 }
5855
5856 env2.Dispose();
5857}
5858
5859
5860THREADED_TEST(CrossDomainForIn) {
5861 v8::HandleScope handle_scope;
5862 LocalContext env1;
5863 v8::Persistent<Context> env2 = Context::New();
5864
5865 Local<Value> foo = v8_str("foo");
5866 Local<Value> bar = v8_str("bar");
5867
5868 // Set to the same domain.
5869 env1->SetSecurityToken(foo);
5870 env2->SetSecurityToken(foo);
5871
5872 env1->Global()->Set(v8_str("prop"), v8_num(3));
5873 env2->Global()->Set(v8_str("env1"), env1->Global());
5874
5875 // Change env2 to a different domain and set env1's global object
5876 // as the __proto__ of an object in env2 and enumerate properties
5877 // in for-in. It shouldn't enumerate properties on env1's global
5878 // object.
5879 env2->SetSecurityToken(bar);
5880 {
5881 Context::Scope scope_env2(env2);
5882 Local<Value> result =
5883 CompileRun("(function(){var obj = {'__proto__':env1};"
5884 "for (var p in obj)"
5885 " if (p == 'prop') return false;"
5886 "return true;})()");
5887 CHECK(result->IsTrue());
5888 }
5889 env2.Dispose();
5890}
5891
5892
5893TEST(ContextDetachGlobal) {
5894 v8::HandleScope handle_scope;
5895 LocalContext env1;
5896 v8::Persistent<Context> env2 = Context::New();
5897
5898 Local<v8::Object> global1 = env1->Global();
5899
5900 Local<Value> foo = v8_str("foo");
5901
5902 // Set to the same domain.
5903 env1->SetSecurityToken(foo);
5904 env2->SetSecurityToken(foo);
5905
5906 // Enter env2
5907 env2->Enter();
5908
Andrei Popescu74b3c142010-03-29 12:03:09 +01005909 // Create a function in env2 and add a reference to it in env1.
Steve Blocka7e24c12009-10-30 11:49:00 +00005910 Local<v8::Object> global2 = env2->Global();
5911 global2->Set(v8_str("prop"), v8::Integer::New(1));
5912 CompileRun("function getProp() {return prop;}");
5913
5914 env1->Global()->Set(v8_str("getProp"),
5915 global2->Get(v8_str("getProp")));
5916
Andrei Popescu74b3c142010-03-29 12:03:09 +01005917 // Detach env2's global, and reuse the global object of env2
Steve Blocka7e24c12009-10-30 11:49:00 +00005918 env2->Exit();
5919 env2->DetachGlobal();
5920 // env2 has a new global object.
5921 CHECK(!env2->Global()->Equals(global2));
5922
5923 v8::Persistent<Context> env3 =
5924 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
5925 env3->SetSecurityToken(v8_str("bar"));
5926 env3->Enter();
5927
5928 Local<v8::Object> global3 = env3->Global();
5929 CHECK_EQ(global2, global3);
5930 CHECK(global3->Get(v8_str("prop"))->IsUndefined());
5931 CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
5932 global3->Set(v8_str("prop"), v8::Integer::New(-1));
5933 global3->Set(v8_str("prop2"), v8::Integer::New(2));
5934 env3->Exit();
5935
5936 // Call getProp in env1, and it should return the value 1
5937 {
5938 Local<Value> get_prop = global1->Get(v8_str("getProp"));
5939 CHECK(get_prop->IsFunction());
5940 v8::TryCatch try_catch;
5941 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
5942 CHECK(!try_catch.HasCaught());
5943 CHECK_EQ(1, r->Int32Value());
5944 }
5945
5946 // Check that env3 is not accessible from env1
5947 {
5948 Local<Value> r = global3->Get(v8_str("prop2"));
5949 CHECK(r->IsUndefined());
5950 }
5951
5952 env2.Dispose();
5953 env3.Dispose();
5954}
5955
5956
Andrei Popescu74b3c142010-03-29 12:03:09 +01005957TEST(DetachAndReattachGlobal) {
5958 v8::HandleScope scope;
5959 LocalContext env1;
5960
5961 // Create second environment.
5962 v8::Persistent<Context> env2 = Context::New();
5963
5964 Local<Value> foo = v8_str("foo");
5965
5966 // Set same security token for env1 and env2.
5967 env1->SetSecurityToken(foo);
5968 env2->SetSecurityToken(foo);
5969
5970 // Create a property on the global object in env2.
5971 {
5972 v8::Context::Scope scope(env2);
5973 env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
5974 }
5975
5976 // Create a reference to env2 global from env1 global.
5977 env1->Global()->Set(v8_str("other"), env2->Global());
5978
5979 // Check that we have access to other.p in env2 from env1.
5980 Local<Value> result = CompileRun("other.p");
5981 CHECK(result->IsInt32());
5982 CHECK_EQ(42, result->Int32Value());
5983
5984 // Hold on to global from env2 and detach global from env2.
5985 Local<v8::Object> global2 = env2->Global();
5986 env2->DetachGlobal();
5987
5988 // Check that the global has been detached. No other.p property can
5989 // be found.
5990 result = CompileRun("other.p");
5991 CHECK(result->IsUndefined());
5992
5993 // Reuse global2 for env3.
5994 v8::Persistent<Context> env3 =
5995 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
5996 CHECK_EQ(global2, env3->Global());
5997
5998 // Start by using the same security token for env3 as for env1 and env2.
5999 env3->SetSecurityToken(foo);
6000
6001 // Create a property on the global object in env3.
6002 {
6003 v8::Context::Scope scope(env3);
6004 env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
6005 }
6006
6007 // Check that other.p is now the property in env3 and that we have access.
6008 result = CompileRun("other.p");
6009 CHECK(result->IsInt32());
6010 CHECK_EQ(24, result->Int32Value());
6011
6012 // Change security token for env3 to something different from env1 and env2.
6013 env3->SetSecurityToken(v8_str("bar"));
6014
6015 // Check that we do not have access to other.p in env1. |other| is now
6016 // the global object for env3 which has a different security token,
6017 // so access should be blocked.
6018 result = CompileRun("other.p");
6019 CHECK(result->IsUndefined());
6020
6021 // Detach the global for env3 and reattach it to env2.
6022 env3->DetachGlobal();
6023 env2->ReattachGlobal(global2);
6024
6025 // Check that we have access to other.p again in env1. |other| is now
6026 // the global object for env2 which has the same security token as env1.
6027 result = CompileRun("other.p");
6028 CHECK(result->IsInt32());
6029 CHECK_EQ(42, result->Int32Value());
6030
6031 env2.Dispose();
6032 env3.Dispose();
6033}
6034
6035
Steve Block1e0659c2011-05-24 12:43:12 +01006036static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
Steve Blocka7e24c12009-10-30 11:49:00 +00006037static bool NamedAccessBlocker(Local<v8::Object> global,
6038 Local<Value> name,
6039 v8::AccessType type,
6040 Local<Value> data) {
Steve Block1e0659c2011-05-24 12:43:12 +01006041 return Context::GetCurrent()->Global()->Equals(global) ||
6042 allowed_access_type[type];
Steve Blocka7e24c12009-10-30 11:49:00 +00006043}
6044
6045
6046static bool IndexedAccessBlocker(Local<v8::Object> global,
6047 uint32_t key,
6048 v8::AccessType type,
6049 Local<Value> data) {
Steve Block1e0659c2011-05-24 12:43:12 +01006050 return Context::GetCurrent()->Global()->Equals(global) ||
6051 allowed_access_type[type];
Steve Blocka7e24c12009-10-30 11:49:00 +00006052}
6053
6054
6055static int g_echo_value = -1;
6056static v8::Handle<Value> EchoGetter(Local<String> name,
6057 const AccessorInfo& info) {
6058 return v8_num(g_echo_value);
6059}
6060
6061
6062static void EchoSetter(Local<String> name,
6063 Local<Value> value,
6064 const AccessorInfo&) {
6065 if (value->IsNumber())
6066 g_echo_value = value->Int32Value();
6067}
6068
6069
6070static v8::Handle<Value> UnreachableGetter(Local<String> name,
6071 const AccessorInfo& info) {
6072 CHECK(false); // This function should not be called..
6073 return v8::Undefined();
6074}
6075
6076
6077static void UnreachableSetter(Local<String>, Local<Value>,
6078 const AccessorInfo&) {
6079 CHECK(false); // This function should nto be called.
6080}
6081
6082
Steve Block1e0659c2011-05-24 12:43:12 +01006083TEST(AccessControl) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006084 v8::HandleScope handle_scope;
6085 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
6086
6087 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
6088 IndexedAccessBlocker);
6089
6090 // Add an accessor accessible by cross-domain JS code.
6091 global_template->SetAccessor(
6092 v8_str("accessible_prop"),
6093 EchoGetter, EchoSetter,
6094 v8::Handle<Value>(),
6095 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
6096
6097 // Add an accessor that is not accessible by cross-domain JS code.
6098 global_template->SetAccessor(v8_str("blocked_prop"),
6099 UnreachableGetter, UnreachableSetter,
6100 v8::Handle<Value>(),
6101 v8::DEFAULT);
6102
6103 // Create an environment
6104 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6105 context0->Enter();
6106
6107 v8::Handle<v8::Object> global0 = context0->Global();
6108
Steve Block1e0659c2011-05-24 12:43:12 +01006109 // Define a property with JS getter and setter.
6110 CompileRun(
6111 "function getter() { return 'getter'; };\n"
6112 "function setter() { return 'setter'; }\n"
6113 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
6114
6115 Local<Value> getter = global0->Get(v8_str("getter"));
6116 Local<Value> setter = global0->Get(v8_str("setter"));
6117
6118 // And define normal element.
6119 global0->Set(239, v8_str("239"));
6120
6121 // Define an element with JS getter and setter.
6122 CompileRun(
6123 "function el_getter() { return 'el_getter'; };\n"
6124 "function el_setter() { return 'el_setter'; };\n"
6125 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
6126
6127 Local<Value> el_getter = global0->Get(v8_str("el_getter"));
6128 Local<Value> el_setter = global0->Get(v8_str("el_setter"));
6129
Steve Blocka7e24c12009-10-30 11:49:00 +00006130 v8::HandleScope scope1;
6131
6132 v8::Persistent<Context> context1 = Context::New();
6133 context1->Enter();
6134
6135 v8::Handle<v8::Object> global1 = context1->Global();
6136 global1->Set(v8_str("other"), global0);
6137
Steve Block1e0659c2011-05-24 12:43:12 +01006138 // Access blocked property.
6139 CompileRun("other.blocked_prop = 1");
6140
6141 ExpectUndefined("other.blocked_prop");
6142 ExpectUndefined(
6143 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
6144 ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
6145
6146 // Enable ACCESS_HAS
6147 allowed_access_type[v8::ACCESS_HAS] = true;
6148 ExpectUndefined("other.blocked_prop");
6149 // ... and now we can get the descriptor...
6150 ExpectUndefined(
6151 "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
6152 // ... and enumerate the property.
6153 ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
6154 allowed_access_type[v8::ACCESS_HAS] = false;
6155
6156 // Access blocked element.
6157 CompileRun("other[239] = 1");
6158
6159 ExpectUndefined("other[239]");
6160 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
6161 ExpectFalse("propertyIsEnumerable.call(other, '239')");
6162
6163 // Enable ACCESS_HAS
6164 allowed_access_type[v8::ACCESS_HAS] = true;
6165 ExpectUndefined("other[239]");
6166 // ... and now we can get the descriptor...
6167 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
6168 // ... and enumerate the property.
6169 ExpectTrue("propertyIsEnumerable.call(other, '239')");
6170 allowed_access_type[v8::ACCESS_HAS] = false;
6171
6172 // Access a property with JS accessor.
6173 CompileRun("other.js_accessor_p = 2");
6174
6175 ExpectUndefined("other.js_accessor_p");
6176 ExpectUndefined(
6177 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
6178
6179 // Enable ACCESS_HAS.
6180 allowed_access_type[v8::ACCESS_HAS] = true;
6181 ExpectUndefined("other.js_accessor_p");
6182 ExpectUndefined(
6183 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
6184 ExpectUndefined(
6185 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
6186 ExpectUndefined(
6187 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6188 allowed_access_type[v8::ACCESS_HAS] = false;
6189
6190 // Enable both ACCESS_HAS and ACCESS_GET.
6191 allowed_access_type[v8::ACCESS_HAS] = true;
6192 allowed_access_type[v8::ACCESS_GET] = true;
6193
6194 ExpectString("other.js_accessor_p", "getter");
6195 ExpectObject(
6196 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
6197 ExpectUndefined(
6198 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
6199 ExpectUndefined(
6200 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6201
6202 allowed_access_type[v8::ACCESS_GET] = false;
6203 allowed_access_type[v8::ACCESS_HAS] = false;
6204
6205 // Enable both ACCESS_HAS and ACCESS_SET.
6206 allowed_access_type[v8::ACCESS_HAS] = true;
6207 allowed_access_type[v8::ACCESS_SET] = true;
6208
6209 ExpectUndefined("other.js_accessor_p");
6210 ExpectUndefined(
6211 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
6212 ExpectObject(
6213 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
6214 ExpectUndefined(
6215 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6216
6217 allowed_access_type[v8::ACCESS_SET] = false;
6218 allowed_access_type[v8::ACCESS_HAS] = false;
6219
6220 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
6221 allowed_access_type[v8::ACCESS_HAS] = true;
6222 allowed_access_type[v8::ACCESS_GET] = true;
6223 allowed_access_type[v8::ACCESS_SET] = true;
6224
6225 ExpectString("other.js_accessor_p", "getter");
6226 ExpectObject(
6227 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
6228 ExpectObject(
6229 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
6230 ExpectUndefined(
6231 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6232
6233 allowed_access_type[v8::ACCESS_SET] = false;
6234 allowed_access_type[v8::ACCESS_GET] = false;
6235 allowed_access_type[v8::ACCESS_HAS] = false;
6236
6237 // Access an element with JS accessor.
6238 CompileRun("other[42] = 2");
6239
6240 ExpectUndefined("other[42]");
6241 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
6242
6243 // Enable ACCESS_HAS.
6244 allowed_access_type[v8::ACCESS_HAS] = true;
6245 ExpectUndefined("other[42]");
6246 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
6247 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
6248 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6249 allowed_access_type[v8::ACCESS_HAS] = false;
6250
6251 // Enable both ACCESS_HAS and ACCESS_GET.
6252 allowed_access_type[v8::ACCESS_HAS] = true;
6253 allowed_access_type[v8::ACCESS_GET] = true;
6254
6255 ExpectString("other[42]", "el_getter");
6256 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
6257 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
6258 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6259
6260 allowed_access_type[v8::ACCESS_GET] = false;
6261 allowed_access_type[v8::ACCESS_HAS] = false;
6262
6263 // Enable both ACCESS_HAS and ACCESS_SET.
6264 allowed_access_type[v8::ACCESS_HAS] = true;
6265 allowed_access_type[v8::ACCESS_SET] = true;
6266
6267 ExpectUndefined("other[42]");
6268 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
6269 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
6270 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6271
6272 allowed_access_type[v8::ACCESS_SET] = false;
6273 allowed_access_type[v8::ACCESS_HAS] = false;
6274
6275 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
6276 allowed_access_type[v8::ACCESS_HAS] = true;
6277 allowed_access_type[v8::ACCESS_GET] = true;
6278 allowed_access_type[v8::ACCESS_SET] = true;
6279
6280 ExpectString("other[42]", "el_getter");
6281 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
6282 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
6283 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6284
6285 allowed_access_type[v8::ACCESS_SET] = false;
6286 allowed_access_type[v8::ACCESS_GET] = false;
6287 allowed_access_type[v8::ACCESS_HAS] = false;
6288
Steve Blocka7e24c12009-10-30 11:49:00 +00006289 v8::Handle<Value> value;
6290
Steve Blocka7e24c12009-10-30 11:49:00 +00006291 // Access accessible property
Steve Block1e0659c2011-05-24 12:43:12 +01006292 value = CompileRun("other.accessible_prop = 3");
Steve Blocka7e24c12009-10-30 11:49:00 +00006293 CHECK(value->IsNumber());
6294 CHECK_EQ(3, value->Int32Value());
Andrei Popescu31002712010-02-23 13:46:05 +00006295 CHECK_EQ(3, g_echo_value);
Steve Blocka7e24c12009-10-30 11:49:00 +00006296
Steve Block1e0659c2011-05-24 12:43:12 +01006297 value = CompileRun("other.accessible_prop");
Steve Blocka7e24c12009-10-30 11:49:00 +00006298 CHECK(value->IsNumber());
6299 CHECK_EQ(3, value->Int32Value());
6300
Steve Block1e0659c2011-05-24 12:43:12 +01006301 value = CompileRun(
6302 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
6303 CHECK(value->IsNumber());
6304 CHECK_EQ(3, value->Int32Value());
6305
6306 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
Steve Blocka7e24c12009-10-30 11:49:00 +00006307 CHECK(value->IsTrue());
6308
6309 // Enumeration doesn't enumerate accessors from inaccessible objects in
6310 // the prototype chain even if the accessors are in themselves accessible.
Steve Block1e0659c2011-05-24 12:43:12 +01006311 value =
Steve Blocka7e24c12009-10-30 11:49:00 +00006312 CompileRun("(function(){var obj = {'__proto__':other};"
6313 "for (var p in obj)"
6314 " if (p == 'accessible_prop' || p == 'blocked_prop') {"
6315 " return false;"
6316 " }"
6317 "return true;})()");
Steve Block1e0659c2011-05-24 12:43:12 +01006318 CHECK(value->IsTrue());
Steve Blocka7e24c12009-10-30 11:49:00 +00006319
6320 context1->Exit();
6321 context0->Exit();
6322 context1.Dispose();
6323 context0.Dispose();
6324}
6325
6326
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006327TEST(AccessControlES5) {
6328 v8::HandleScope handle_scope;
6329 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
6330
6331 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
6332 IndexedAccessBlocker);
6333
Steve Block44f0eee2011-05-26 01:26:41 +01006334 // Add accessible accessor.
6335 global_template->SetAccessor(
6336 v8_str("accessible_prop"),
6337 EchoGetter, EchoSetter,
6338 v8::Handle<Value>(),
6339 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
6340
6341
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006342 // Add an accessor that is not accessible by cross-domain JS code.
6343 global_template->SetAccessor(v8_str("blocked_prop"),
6344 UnreachableGetter, UnreachableSetter,
6345 v8::Handle<Value>(),
6346 v8::DEFAULT);
6347
6348 // Create an environment
6349 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6350 context0->Enter();
6351
6352 v8::Handle<v8::Object> global0 = context0->Global();
6353
6354 v8::Persistent<Context> context1 = Context::New();
6355 context1->Enter();
6356 v8::Handle<v8::Object> global1 = context1->Global();
6357 global1->Set(v8_str("other"), global0);
6358
6359 // Regression test for issue 1154.
6360 ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
6361
6362 ExpectUndefined("other.blocked_prop");
6363
6364 // Regression test for issue 1027.
6365 CompileRun("Object.defineProperty(\n"
6366 " other, 'blocked_prop', {configurable: false})");
6367 ExpectUndefined("other.blocked_prop");
6368 ExpectUndefined(
6369 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
6370
6371 // Regression test for issue 1171.
6372 ExpectTrue("Object.isExtensible(other)");
6373 CompileRun("Object.preventExtensions(other)");
6374 ExpectTrue("Object.isExtensible(other)");
6375
6376 // Object.seal and Object.freeze.
6377 CompileRun("Object.freeze(other)");
6378 ExpectTrue("Object.isExtensible(other)");
6379
6380 CompileRun("Object.seal(other)");
6381 ExpectTrue("Object.isExtensible(other)");
Steve Block44f0eee2011-05-26 01:26:41 +01006382
6383 // Regression test for issue 1250.
6384 // Make sure that we can set the accessible accessors value using normal
6385 // assignment.
6386 CompileRun("other.accessible_prop = 42");
6387 CHECK_EQ(42, g_echo_value);
6388
6389 v8::Handle<Value> value;
6390 // We follow Safari in ignoring assignments to host object accessors.
6391 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
6392 value = CompileRun("other.accessible_prop == 42");
6393 CHECK(value->IsTrue());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006394}
6395
6396
Leon Clarke4515c472010-02-03 11:58:03 +00006397static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
6398 Local<Value> name,
6399 v8::AccessType type,
6400 Local<Value> data) {
6401 return false;
6402}
6403
6404
6405static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
6406 uint32_t key,
6407 v8::AccessType type,
6408 Local<Value> data) {
6409 return false;
6410}
6411
6412
6413THREADED_TEST(AccessControlGetOwnPropertyNames) {
6414 v8::HandleScope handle_scope;
6415 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
6416
6417 obj_template->Set(v8_str("x"), v8::Integer::New(42));
6418 obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
6419 GetOwnPropertyNamesIndexedBlocker);
6420
6421 // Create an environment
6422 v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
6423 context0->Enter();
6424
6425 v8::Handle<v8::Object> global0 = context0->Global();
6426
6427 v8::HandleScope scope1;
6428
6429 v8::Persistent<Context> context1 = Context::New();
6430 context1->Enter();
6431
6432 v8::Handle<v8::Object> global1 = context1->Global();
6433 global1->Set(v8_str("other"), global0);
6434 global1->Set(v8_str("object"), obj_template->NewInstance());
6435
6436 v8::Handle<Value> value;
6437
6438 // Attempt to get the property names of the other global object and
6439 // of an object that requires access checks. Accessing the other
6440 // global object should be blocked by access checks on the global
6441 // proxy object. Accessing the object that requires access checks
6442 // is blocked by the access checks on the object itself.
6443 value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
6444 CHECK(value->IsTrue());
6445
6446 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
6447 CHECK(value->IsTrue());
6448
6449 context1->Exit();
6450 context0->Exit();
6451 context1.Dispose();
6452 context0.Dispose();
6453}
6454
6455
Steve Block8defd9f2010-07-08 12:39:36 +01006456static v8::Handle<v8::Array> NamedPropertyEnumerator(const AccessorInfo& info) {
6457 v8::Handle<v8::Array> result = v8::Array::New(1);
6458 result->Set(0, v8_str("x"));
6459 return result;
6460}
6461
6462
6463THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
6464 v8::HandleScope handle_scope;
6465 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
6466
6467 obj_template->Set(v8_str("x"), v8::Integer::New(42));
6468 obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
6469 NamedPropertyEnumerator);
6470
6471 LocalContext context;
6472 v8::Handle<v8::Object> global = context->Global();
6473 global->Set(v8_str("object"), obj_template->NewInstance());
6474
6475 v8::Handle<Value> value =
6476 CompileRun("Object.getOwnPropertyNames(object).join(',')");
6477 CHECK_EQ(v8_str("x"), value);
6478}
6479
6480
Steve Blocka7e24c12009-10-30 11:49:00 +00006481static v8::Handle<Value> ConstTenGetter(Local<String> name,
6482 const AccessorInfo& info) {
6483 return v8_num(10);
6484}
6485
6486
6487THREADED_TEST(CrossDomainAccessors) {
6488 v8::HandleScope handle_scope;
6489
6490 v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
6491
6492 v8::Handle<v8::ObjectTemplate> global_template =
6493 func_template->InstanceTemplate();
6494
6495 v8::Handle<v8::ObjectTemplate> proto_template =
6496 func_template->PrototypeTemplate();
6497
6498 // Add an accessor to proto that's accessible by cross-domain JS code.
6499 proto_template->SetAccessor(v8_str("accessible"),
6500 ConstTenGetter, 0,
6501 v8::Handle<Value>(),
6502 v8::ALL_CAN_READ);
6503
6504 // Add an accessor that is not accessible by cross-domain JS code.
6505 global_template->SetAccessor(v8_str("unreachable"),
6506 UnreachableGetter, 0,
6507 v8::Handle<Value>(),
6508 v8::DEFAULT);
6509
6510 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6511 context0->Enter();
6512
6513 Local<v8::Object> global = context0->Global();
6514 // Add a normal property that shadows 'accessible'
6515 global->Set(v8_str("accessible"), v8_num(11));
6516
6517 // Enter a new context.
6518 v8::HandleScope scope1;
6519 v8::Persistent<Context> context1 = Context::New();
6520 context1->Enter();
6521
6522 v8::Handle<v8::Object> global1 = context1->Global();
6523 global1->Set(v8_str("other"), global);
6524
6525 // Should return 10, instead of 11
6526 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
6527 CHECK(value->IsNumber());
6528 CHECK_EQ(10, value->Int32Value());
6529
6530 value = v8_compile("other.unreachable")->Run();
6531 CHECK(value->IsUndefined());
6532
6533 context1->Exit();
6534 context0->Exit();
6535 context1.Dispose();
6536 context0.Dispose();
6537}
6538
6539
6540static int named_access_count = 0;
6541static int indexed_access_count = 0;
6542
6543static bool NamedAccessCounter(Local<v8::Object> global,
6544 Local<Value> name,
6545 v8::AccessType type,
6546 Local<Value> data) {
6547 named_access_count++;
6548 return true;
6549}
6550
6551
6552static bool IndexedAccessCounter(Local<v8::Object> global,
6553 uint32_t key,
6554 v8::AccessType type,
6555 Local<Value> data) {
6556 indexed_access_count++;
6557 return true;
6558}
6559
6560
6561// This one is too easily disturbed by other tests.
6562TEST(AccessControlIC) {
6563 named_access_count = 0;
6564 indexed_access_count = 0;
6565
6566 v8::HandleScope handle_scope;
6567
6568 // Create an environment.
6569 v8::Persistent<Context> context0 = Context::New();
6570 context0->Enter();
6571
6572 // Create an object that requires access-check functions to be
6573 // called for cross-domain access.
6574 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
6575 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
6576 IndexedAccessCounter);
6577 Local<v8::Object> object = object_template->NewInstance();
6578
6579 v8::HandleScope scope1;
6580
6581 // Create another environment.
6582 v8::Persistent<Context> context1 = Context::New();
6583 context1->Enter();
6584
6585 // Make easy access to the object from the other environment.
6586 v8::Handle<v8::Object> global1 = context1->Global();
6587 global1->Set(v8_str("obj"), object);
6588
6589 v8::Handle<Value> value;
6590
6591 // Check that the named access-control function is called every time.
6592 CompileRun("function testProp(obj) {"
6593 " for (var i = 0; i < 10; i++) obj.prop = 1;"
6594 " for (var j = 0; j < 10; j++) obj.prop;"
6595 " return obj.prop"
6596 "}");
6597 value = CompileRun("testProp(obj)");
6598 CHECK(value->IsNumber());
6599 CHECK_EQ(1, value->Int32Value());
6600 CHECK_EQ(21, named_access_count);
6601
6602 // Check that the named access-control function is called every time.
6603 CompileRun("var p = 'prop';"
6604 "function testKeyed(obj) {"
6605 " for (var i = 0; i < 10; i++) obj[p] = 1;"
6606 " for (var j = 0; j < 10; j++) obj[p];"
6607 " return obj[p];"
6608 "}");
6609 // Use obj which requires access checks. No inline caching is used
6610 // in that case.
6611 value = CompileRun("testKeyed(obj)");
6612 CHECK(value->IsNumber());
6613 CHECK_EQ(1, value->Int32Value());
6614 CHECK_EQ(42, named_access_count);
6615 // Force the inline caches into generic state and try again.
6616 CompileRun("testKeyed({ a: 0 })");
6617 CompileRun("testKeyed({ b: 0 })");
6618 value = CompileRun("testKeyed(obj)");
6619 CHECK(value->IsNumber());
6620 CHECK_EQ(1, value->Int32Value());
6621 CHECK_EQ(63, named_access_count);
6622
6623 // Check that the indexed access-control function is called every time.
6624 CompileRun("function testIndexed(obj) {"
6625 " for (var i = 0; i < 10; i++) obj[0] = 1;"
6626 " for (var j = 0; j < 10; j++) obj[0];"
6627 " return obj[0]"
6628 "}");
6629 value = CompileRun("testIndexed(obj)");
6630 CHECK(value->IsNumber());
6631 CHECK_EQ(1, value->Int32Value());
6632 CHECK_EQ(21, indexed_access_count);
6633 // Force the inline caches into generic state.
6634 CompileRun("testIndexed(new Array(1))");
6635 // Test that the indexed access check is called.
6636 value = CompileRun("testIndexed(obj)");
6637 CHECK(value->IsNumber());
6638 CHECK_EQ(1, value->Int32Value());
6639 CHECK_EQ(42, indexed_access_count);
6640
6641 // Check that the named access check is called when invoking
6642 // functions on an object that requires access checks.
6643 CompileRun("obj.f = function() {}");
6644 CompileRun("function testCallNormal(obj) {"
6645 " for (var i = 0; i < 10; i++) obj.f();"
6646 "}");
6647 CompileRun("testCallNormal(obj)");
6648 CHECK_EQ(74, named_access_count);
6649
6650 // Force obj into slow case.
6651 value = CompileRun("delete obj.prop");
6652 CHECK(value->BooleanValue());
6653 // Force inline caches into dictionary probing mode.
6654 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
6655 // Test that the named access check is called.
6656 value = CompileRun("testProp(obj);");
6657 CHECK(value->IsNumber());
6658 CHECK_EQ(1, value->Int32Value());
6659 CHECK_EQ(96, named_access_count);
6660
6661 // Force the call inline cache into dictionary probing mode.
6662 CompileRun("o.f = function() {}; testCallNormal(o)");
6663 // Test that the named access check is still called for each
6664 // invocation of the function.
6665 value = CompileRun("testCallNormal(obj)");
6666 CHECK_EQ(106, named_access_count);
6667
6668 context1->Exit();
6669 context0->Exit();
6670 context1.Dispose();
6671 context0.Dispose();
6672}
6673
6674
6675static bool NamedAccessFlatten(Local<v8::Object> global,
6676 Local<Value> name,
6677 v8::AccessType type,
6678 Local<Value> data) {
6679 char buf[100];
6680 int len;
6681
6682 CHECK(name->IsString());
6683
6684 memset(buf, 0x1, sizeof(buf));
Steve Block6ded16b2010-05-10 14:33:55 +01006685 len = name.As<String>()->WriteAscii(buf);
Steve Blocka7e24c12009-10-30 11:49:00 +00006686 CHECK_EQ(4, len);
6687
6688 uint16_t buf2[100];
6689
6690 memset(buf, 0x1, sizeof(buf));
Steve Block6ded16b2010-05-10 14:33:55 +01006691 len = name.As<String>()->Write(buf2);
Steve Blocka7e24c12009-10-30 11:49:00 +00006692 CHECK_EQ(4, len);
6693
6694 return true;
6695}
6696
6697
6698static bool IndexedAccessFlatten(Local<v8::Object> global,
6699 uint32_t key,
6700 v8::AccessType type,
6701 Local<Value> data) {
6702 return true;
6703}
6704
6705
6706// Regression test. In access checks, operations that may cause
6707// garbage collection are not allowed. It used to be the case that
6708// using the Write operation on a string could cause a garbage
6709// collection due to flattening of the string. This is no longer the
6710// case.
6711THREADED_TEST(AccessControlFlatten) {
6712 named_access_count = 0;
6713 indexed_access_count = 0;
6714
6715 v8::HandleScope handle_scope;
6716
6717 // Create an environment.
6718 v8::Persistent<Context> context0 = Context::New();
6719 context0->Enter();
6720
6721 // Create an object that requires access-check functions to be
6722 // called for cross-domain access.
6723 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
6724 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
6725 IndexedAccessFlatten);
6726 Local<v8::Object> object = object_template->NewInstance();
6727
6728 v8::HandleScope scope1;
6729
6730 // Create another environment.
6731 v8::Persistent<Context> context1 = Context::New();
6732 context1->Enter();
6733
6734 // Make easy access to the object from the other environment.
6735 v8::Handle<v8::Object> global1 = context1->Global();
6736 global1->Set(v8_str("obj"), object);
6737
6738 v8::Handle<Value> value;
6739
6740 value = v8_compile("var p = 'as' + 'df';")->Run();
6741 value = v8_compile("obj[p];")->Run();
6742
6743 context1->Exit();
6744 context0->Exit();
6745 context1.Dispose();
6746 context0.Dispose();
6747}
6748
6749
6750static v8::Handle<Value> AccessControlNamedGetter(
6751 Local<String>, const AccessorInfo&) {
6752 return v8::Integer::New(42);
6753}
6754
6755
6756static v8::Handle<Value> AccessControlNamedSetter(
6757 Local<String>, Local<Value> value, const AccessorInfo&) {
6758 return value;
6759}
6760
6761
6762static v8::Handle<Value> AccessControlIndexedGetter(
6763 uint32_t index,
6764 const AccessorInfo& info) {
6765 return v8_num(42);
6766}
6767
6768
6769static v8::Handle<Value> AccessControlIndexedSetter(
6770 uint32_t, Local<Value> value, const AccessorInfo&) {
6771 return value;
6772}
6773
6774
6775THREADED_TEST(AccessControlInterceptorIC) {
6776 named_access_count = 0;
6777 indexed_access_count = 0;
6778
6779 v8::HandleScope handle_scope;
6780
6781 // Create an environment.
6782 v8::Persistent<Context> context0 = Context::New();
6783 context0->Enter();
6784
6785 // Create an object that requires access-check functions to be
6786 // called for cross-domain access. The object also has interceptors
6787 // interceptor.
6788 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
6789 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
6790 IndexedAccessCounter);
6791 object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
6792 AccessControlNamedSetter);
6793 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
6794 AccessControlIndexedSetter);
6795 Local<v8::Object> object = object_template->NewInstance();
6796
6797 v8::HandleScope scope1;
6798
6799 // Create another environment.
6800 v8::Persistent<Context> context1 = Context::New();
6801 context1->Enter();
6802
6803 // Make easy access to the object from the other environment.
6804 v8::Handle<v8::Object> global1 = context1->Global();
6805 global1->Set(v8_str("obj"), object);
6806
6807 v8::Handle<Value> value;
6808
6809 // Check that the named access-control function is called every time
6810 // eventhough there is an interceptor on the object.
6811 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
6812 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
6813 "obj.x")->Run();
6814 CHECK(value->IsNumber());
6815 CHECK_EQ(42, value->Int32Value());
6816 CHECK_EQ(21, named_access_count);
6817
6818 value = v8_compile("var p = 'x';")->Run();
6819 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
6820 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
6821 "obj[p]")->Run();
6822 CHECK(value->IsNumber());
6823 CHECK_EQ(42, value->Int32Value());
6824 CHECK_EQ(42, named_access_count);
6825
6826 // Check that the indexed access-control function is called every
6827 // time eventhough there is an interceptor on the object.
6828 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
6829 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
6830 "obj[0]")->Run();
6831 CHECK(value->IsNumber());
6832 CHECK_EQ(42, value->Int32Value());
6833 CHECK_EQ(21, indexed_access_count);
6834
6835 context1->Exit();
6836 context0->Exit();
6837 context1.Dispose();
6838 context0.Dispose();
6839}
6840
6841
6842THREADED_TEST(Version) {
6843 v8::V8::GetVersion();
6844}
6845
6846
6847static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
6848 ApiTestFuzzer::Fuzz();
6849 return v8_num(12);
6850}
6851
6852
6853THREADED_TEST(InstanceProperties) {
6854 v8::HandleScope handle_scope;
6855 LocalContext context;
6856
6857 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6858 Local<ObjectTemplate> instance = t->InstanceTemplate();
6859
6860 instance->Set(v8_str("x"), v8_num(42));
6861 instance->Set(v8_str("f"),
6862 v8::FunctionTemplate::New(InstanceFunctionCallback));
6863
6864 Local<Value> o = t->GetFunction()->NewInstance();
6865
6866 context->Global()->Set(v8_str("i"), o);
6867 Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
6868 CHECK_EQ(42, value->Int32Value());
6869
6870 value = Script::Compile(v8_str("i.f()"))->Run();
6871 CHECK_EQ(12, value->Int32Value());
6872}
6873
6874
6875static v8::Handle<Value>
6876GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
6877 ApiTestFuzzer::Fuzz();
6878 return v8::Handle<Value>();
6879}
6880
6881
6882THREADED_TEST(GlobalObjectInstanceProperties) {
6883 v8::HandleScope handle_scope;
6884
6885 Local<Value> global_object;
6886
6887 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6888 t->InstanceTemplate()->SetNamedPropertyHandler(
6889 GlobalObjectInstancePropertiesGet);
6890 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
6891 instance_template->Set(v8_str("x"), v8_num(42));
6892 instance_template->Set(v8_str("f"),
6893 v8::FunctionTemplate::New(InstanceFunctionCallback));
6894
Ben Murdochb0fe1622011-05-05 13:52:32 +01006895 // The script to check how Crankshaft compiles missing global function
6896 // invocations. function g is not defined and should throw on call.
6897 const char* script =
6898 "function wrapper(call) {"
6899 " var x = 0, y = 1;"
6900 " for (var i = 0; i < 1000; i++) {"
6901 " x += i * 100;"
6902 " y += i * 100;"
6903 " }"
6904 " if (call) g();"
6905 "}"
6906 "for (var i = 0; i < 17; i++) wrapper(false);"
6907 "var thrown = 0;"
6908 "try { wrapper(true); } catch (e) { thrown = 1; };"
6909 "thrown";
6910
Steve Blocka7e24c12009-10-30 11:49:00 +00006911 {
6912 LocalContext env(NULL, instance_template);
6913 // Hold on to the global object so it can be used again in another
6914 // environment initialization.
6915 global_object = env->Global();
6916
6917 Local<Value> value = Script::Compile(v8_str("x"))->Run();
6918 CHECK_EQ(42, value->Int32Value());
6919 value = Script::Compile(v8_str("f()"))->Run();
6920 CHECK_EQ(12, value->Int32Value());
Ben Murdochb0fe1622011-05-05 13:52:32 +01006921 value = Script::Compile(v8_str(script))->Run();
6922 CHECK_EQ(1, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00006923 }
6924
6925 {
6926 // Create new environment reusing the global object.
6927 LocalContext env(NULL, instance_template, global_object);
6928 Local<Value> value = Script::Compile(v8_str("x"))->Run();
6929 CHECK_EQ(42, value->Int32Value());
6930 value = Script::Compile(v8_str("f()"))->Run();
6931 CHECK_EQ(12, value->Int32Value());
Ben Murdochb0fe1622011-05-05 13:52:32 +01006932 value = Script::Compile(v8_str(script))->Run();
6933 CHECK_EQ(1, value->Int32Value());
6934 }
6935}
6936
6937
6938THREADED_TEST(CallKnownGlobalReceiver) {
6939 v8::HandleScope handle_scope;
6940
6941 Local<Value> global_object;
6942
6943 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6944 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
6945
6946 // The script to check that we leave global object not
6947 // global object proxy on stack when we deoptimize from inside
6948 // arguments evaluation.
6949 // To provoke error we need to both force deoptimization
6950 // from arguments evaluation and to force CallIC to take
6951 // CallIC_Miss code path that can't cope with global proxy.
6952 const char* script =
6953 "function bar(x, y) { try { } finally { } }"
6954 "function baz(x) { try { } finally { } }"
6955 "function bom(x) { try { } finally { } }"
6956 "function foo(x) { bar([x], bom(2)); }"
6957 "for (var i = 0; i < 10000; i++) foo(1);"
6958 "foo";
6959
6960 Local<Value> foo;
6961 {
6962 LocalContext env(NULL, instance_template);
6963 // Hold on to the global object so it can be used again in another
6964 // environment initialization.
6965 global_object = env->Global();
6966 foo = Script::Compile(v8_str(script))->Run();
6967 }
6968
6969 {
6970 // Create new environment reusing the global object.
6971 LocalContext env(NULL, instance_template, global_object);
6972 env->Global()->Set(v8_str("foo"), foo);
6973 Local<Value> value = Script::Compile(v8_str("foo()"))->Run();
Steve Blocka7e24c12009-10-30 11:49:00 +00006974 }
6975}
6976
6977
6978static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
6979 ApiTestFuzzer::Fuzz();
6980 return v8_num(42);
6981}
6982
6983
6984static int shadow_y;
6985static int shadow_y_setter_call_count;
6986static int shadow_y_getter_call_count;
6987
6988
6989static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
6990 shadow_y_setter_call_count++;
6991 shadow_y = 42;
6992}
6993
6994
6995static v8::Handle<Value> ShadowYGetter(Local<String> name,
6996 const AccessorInfo& info) {
6997 ApiTestFuzzer::Fuzz();
6998 shadow_y_getter_call_count++;
6999 return v8_num(shadow_y);
7000}
7001
7002
7003static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
7004 const AccessorInfo& info) {
7005 return v8::Handle<Value>();
7006}
7007
7008
7009static v8::Handle<Value> ShadowNamedGet(Local<String> key,
7010 const AccessorInfo&) {
7011 return v8::Handle<Value>();
7012}
7013
7014
7015THREADED_TEST(ShadowObject) {
7016 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
7017 v8::HandleScope handle_scope;
7018
7019 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
7020 LocalContext context(NULL, global_template);
7021
7022 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7023 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
7024 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
7025 Local<ObjectTemplate> proto = t->PrototypeTemplate();
7026 Local<ObjectTemplate> instance = t->InstanceTemplate();
7027
7028 // Only allow calls of f on instances of t.
7029 Local<v8::Signature> signature = v8::Signature::New(t);
7030 proto->Set(v8_str("f"),
7031 v8::FunctionTemplate::New(ShadowFunctionCallback,
7032 Local<Value>(),
7033 signature));
7034 proto->Set(v8_str("x"), v8_num(12));
7035
7036 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
7037
7038 Local<Value> o = t->GetFunction()->NewInstance();
7039 context->Global()->Set(v8_str("__proto__"), o);
7040
7041 Local<Value> value =
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007042 Script::Compile(v8_str("this.propertyIsEnumerable(0)"))->Run();
Steve Blocka7e24c12009-10-30 11:49:00 +00007043 CHECK(value->IsBoolean());
7044 CHECK(!value->BooleanValue());
7045
7046 value = Script::Compile(v8_str("x"))->Run();
7047 CHECK_EQ(12, value->Int32Value());
7048
7049 value = Script::Compile(v8_str("f()"))->Run();
7050 CHECK_EQ(42, value->Int32Value());
7051
7052 Script::Compile(v8_str("y = 42"))->Run();
7053 CHECK_EQ(1, shadow_y_setter_call_count);
7054 value = Script::Compile(v8_str("y"))->Run();
7055 CHECK_EQ(1, shadow_y_getter_call_count);
7056 CHECK_EQ(42, value->Int32Value());
7057}
7058
7059
7060THREADED_TEST(HiddenPrototype) {
7061 v8::HandleScope handle_scope;
7062 LocalContext context;
7063
7064 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
7065 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
7066 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
7067 t1->SetHiddenPrototype(true);
7068 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
7069 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
7070 t2->SetHiddenPrototype(true);
7071 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
7072 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
7073 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
7074
7075 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
7076 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
7077 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
7078 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
7079
7080 // Setting the prototype on an object skips hidden prototypes.
7081 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7082 o0->Set(v8_str("__proto__"), o1);
7083 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7084 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7085 o0->Set(v8_str("__proto__"), o2);
7086 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7087 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7088 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7089 o0->Set(v8_str("__proto__"), o3);
7090 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7091 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7092 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7093 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
7094
7095 // Getting the prototype of o0 should get the first visible one
7096 // which is o3. Therefore, z should not be defined on the prototype
7097 // object.
7098 Local<Value> proto = o0->Get(v8_str("__proto__"));
7099 CHECK(proto->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01007100 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
Steve Blocka7e24c12009-10-30 11:49:00 +00007101}
7102
7103
Andrei Popescu402d9372010-02-26 13:31:12 +00007104THREADED_TEST(SetPrototype) {
7105 v8::HandleScope handle_scope;
7106 LocalContext context;
7107
7108 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
7109 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
7110 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
7111 t1->SetHiddenPrototype(true);
7112 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
7113 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
7114 t2->SetHiddenPrototype(true);
7115 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
7116 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
7117 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
7118
7119 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
7120 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
7121 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
7122 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
7123
7124 // Setting the prototype on an object does not skip hidden prototypes.
7125 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7126 CHECK(o0->SetPrototype(o1));
7127 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7128 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7129 CHECK(o1->SetPrototype(o2));
7130 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7131 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7132 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7133 CHECK(o2->SetPrototype(o3));
7134 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7135 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7136 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7137 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
7138
7139 // Getting the prototype of o0 should get the first visible one
7140 // which is o3. Therefore, z should not be defined on the prototype
7141 // object.
7142 Local<Value> proto = o0->Get(v8_str("__proto__"));
7143 CHECK(proto->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01007144 CHECK_EQ(proto.As<v8::Object>(), o3);
Andrei Popescu402d9372010-02-26 13:31:12 +00007145
7146 // However, Object::GetPrototype ignores hidden prototype.
7147 Local<Value> proto0 = o0->GetPrototype();
7148 CHECK(proto0->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01007149 CHECK_EQ(proto0.As<v8::Object>(), o1);
Andrei Popescu402d9372010-02-26 13:31:12 +00007150
7151 Local<Value> proto1 = o1->GetPrototype();
7152 CHECK(proto1->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01007153 CHECK_EQ(proto1.As<v8::Object>(), o2);
Andrei Popescu402d9372010-02-26 13:31:12 +00007154
7155 Local<Value> proto2 = o2->GetPrototype();
7156 CHECK(proto2->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01007157 CHECK_EQ(proto2.As<v8::Object>(), o3);
Andrei Popescu402d9372010-02-26 13:31:12 +00007158}
7159
7160
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007161THREADED_TEST(FunctionReadOnlyPrototype) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007162 v8::HandleScope handle_scope;
7163 LocalContext context;
7164
7165 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007166 t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
7167 t1->ReadOnlyPrototype();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007168 context->Global()->Set(v8_str("func1"), t1->GetFunction());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007169 // Configured value of ReadOnly flag.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007170 CHECK(CompileRun(
7171 "(function() {"
7172 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007173 " return (descriptor['writable'] == false);"
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007174 "})()")->BooleanValue());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007175 CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
7176 CHECK_EQ(42,
7177 CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007178
7179 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007180 t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007181 context->Global()->Set(v8_str("func2"), t2->GetFunction());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007182 // Default value of ReadOnly flag.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007183 CHECK(CompileRun(
7184 "(function() {"
7185 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007186 " return (descriptor['writable'] == true);"
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007187 "})()")->BooleanValue());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007188 CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007189}
7190
7191
Andrei Popescu402d9372010-02-26 13:31:12 +00007192THREADED_TEST(SetPrototypeThrows) {
7193 v8::HandleScope handle_scope;
7194 LocalContext context;
7195
7196 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7197
7198 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
7199 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
7200
7201 CHECK(o0->SetPrototype(o1));
7202 // If setting the prototype leads to the cycle, SetPrototype should
7203 // return false and keep VM in sane state.
7204 v8::TryCatch try_catch;
7205 CHECK(!o1->SetPrototype(o0));
7206 CHECK(!try_catch.HasCaught());
Steve Block44f0eee2011-05-26 01:26:41 +01007207 ASSERT(!i::Isolate::Current()->has_pending_exception());
Andrei Popescu402d9372010-02-26 13:31:12 +00007208
7209 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
7210}
7211
7212
Steve Blocka7e24c12009-10-30 11:49:00 +00007213THREADED_TEST(GetterSetterExceptions) {
7214 v8::HandleScope handle_scope;
7215 LocalContext context;
7216 CompileRun(
7217 "function Foo() { };"
7218 "function Throw() { throw 5; };"
7219 "var x = { };"
7220 "x.__defineSetter__('set', Throw);"
7221 "x.__defineGetter__('get', Throw);");
7222 Local<v8::Object> x =
7223 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
7224 v8::TryCatch try_catch;
7225 x->Set(v8_str("set"), v8::Integer::New(8));
7226 x->Get(v8_str("get"));
7227 x->Set(v8_str("set"), v8::Integer::New(8));
7228 x->Get(v8_str("get"));
7229 x->Set(v8_str("set"), v8::Integer::New(8));
7230 x->Get(v8_str("get"));
7231 x->Set(v8_str("set"), v8::Integer::New(8));
7232 x->Get(v8_str("get"));
7233}
7234
7235
7236THREADED_TEST(Constructor) {
7237 v8::HandleScope handle_scope;
7238 LocalContext context;
7239 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7240 templ->SetClassName(v8_str("Fun"));
7241 Local<Function> cons = templ->GetFunction();
7242 context->Global()->Set(v8_str("Fun"), cons);
7243 Local<v8::Object> inst = cons->NewInstance();
7244 i::Handle<i::JSObject> obj = v8::Utils::OpenHandle(*inst);
7245 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
7246 CHECK(value->BooleanValue());
7247}
7248
Ben Murdoch257744e2011-11-30 15:57:28 +00007249
7250static Handle<Value> ConstructorCallback(const Arguments& args) {
7251 ApiTestFuzzer::Fuzz();
7252 Local<Object> This;
7253
7254 if (args.IsConstructCall()) {
7255 Local<Object> Holder = args.Holder();
7256 This = Object::New();
7257 Local<Value> proto = Holder->GetPrototype();
7258 if (proto->IsObject()) {
7259 This->SetPrototype(proto);
7260 }
7261 } else {
7262 This = args.This();
7263 }
7264
7265 This->Set(v8_str("a"), args[0]);
7266 return This;
7267}
7268
7269
7270static Handle<Value> FakeConstructorCallback(const Arguments& args) {
7271 ApiTestFuzzer::Fuzz();
7272 return args[0];
7273}
7274
7275
7276THREADED_TEST(ConstructorForObject) {
7277 v8::HandleScope handle_scope;
7278 LocalContext context;
7279
7280 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7281 instance_template->SetCallAsFunctionHandler(ConstructorCallback);
7282 Local<Object> instance = instance_template->NewInstance();
7283 context->Global()->Set(v8_str("obj"), instance);
7284 v8::TryCatch try_catch;
7285 Local<Value> value;
7286 CHECK(!try_catch.HasCaught());
7287
7288 // Call the Object's constructor with a 32-bit signed integer.
7289 value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
7290 CHECK(!try_catch.HasCaught());
7291 CHECK(value->IsInt32());
7292 CHECK_EQ(28, value->Int32Value());
7293
7294 Local<Value> args1[] = { v8_num(28) };
7295 Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
7296 CHECK(value_obj1->IsObject());
7297 Local<Object> object1 = Local<Object>::Cast(value_obj1);
7298 value = object1->Get(v8_str("a"));
7299 CHECK(value->IsInt32());
7300 CHECK(!try_catch.HasCaught());
7301 CHECK_EQ(28, value->Int32Value());
7302
7303 // Call the Object's constructor with a String.
7304 value = CompileRun(
7305 "(function() { var o = new obj('tipli'); return o.a; })()");
7306 CHECK(!try_catch.HasCaught());
7307 CHECK(value->IsString());
7308 String::AsciiValue string_value1(value->ToString());
7309 CHECK_EQ("tipli", *string_value1);
7310
7311 Local<Value> args2[] = { v8_str("tipli") };
7312 Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
7313 CHECK(value_obj2->IsObject());
7314 Local<Object> object2 = Local<Object>::Cast(value_obj2);
7315 value = object2->Get(v8_str("a"));
7316 CHECK(!try_catch.HasCaught());
7317 CHECK(value->IsString());
7318 String::AsciiValue string_value2(value->ToString());
7319 CHECK_EQ("tipli", *string_value2);
7320
7321 // Call the Object's constructor with a Boolean.
7322 value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
7323 CHECK(!try_catch.HasCaught());
7324 CHECK(value->IsBoolean());
7325 CHECK_EQ(true, value->BooleanValue());
7326
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007327 Handle<Value> args3[] = { v8::True() };
Ben Murdoch257744e2011-11-30 15:57:28 +00007328 Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
7329 CHECK(value_obj3->IsObject());
7330 Local<Object> object3 = Local<Object>::Cast(value_obj3);
7331 value = object3->Get(v8_str("a"));
7332 CHECK(!try_catch.HasCaught());
7333 CHECK(value->IsBoolean());
7334 CHECK_EQ(true, value->BooleanValue());
7335
7336 // Call the Object's constructor with undefined.
7337 Handle<Value> args4[] = { v8::Undefined() };
7338 Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
7339 CHECK(value_obj4->IsObject());
7340 Local<Object> object4 = Local<Object>::Cast(value_obj4);
7341 value = object4->Get(v8_str("a"));
7342 CHECK(!try_catch.HasCaught());
7343 CHECK(value->IsUndefined());
7344
7345 // Call the Object's constructor with null.
7346 Handle<Value> args5[] = { v8::Null() };
7347 Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
7348 CHECK(value_obj5->IsObject());
7349 Local<Object> object5 = Local<Object>::Cast(value_obj5);
7350 value = object5->Get(v8_str("a"));
7351 CHECK(!try_catch.HasCaught());
7352 CHECK(value->IsNull());
7353 }
7354
7355 // Check exception handling when there is no constructor set for the Object.
7356 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7357 Local<Object> instance = instance_template->NewInstance();
7358 context->Global()->Set(v8_str("obj2"), instance);
7359 v8::TryCatch try_catch;
7360 Local<Value> value;
7361 CHECK(!try_catch.HasCaught());
7362
7363 value = CompileRun("new obj2(28)");
7364 CHECK(try_catch.HasCaught());
7365 String::AsciiValue exception_value1(try_catch.Exception());
7366 CHECK_EQ("TypeError: object is not a function", *exception_value1);
7367 try_catch.Reset();
7368
7369 Local<Value> args[] = { v8_num(29) };
7370 value = instance->CallAsConstructor(1, args);
7371 CHECK(try_catch.HasCaught());
7372 String::AsciiValue exception_value2(try_catch.Exception());
7373 CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
7374 try_catch.Reset();
7375 }
7376
7377 // Check the case when constructor throws exception.
7378 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7379 instance_template->SetCallAsFunctionHandler(ThrowValue);
7380 Local<Object> instance = instance_template->NewInstance();
7381 context->Global()->Set(v8_str("obj3"), instance);
7382 v8::TryCatch try_catch;
7383 Local<Value> value;
7384 CHECK(!try_catch.HasCaught());
7385
7386 value = CompileRun("new obj3(22)");
7387 CHECK(try_catch.HasCaught());
7388 String::AsciiValue exception_value1(try_catch.Exception());
7389 CHECK_EQ("22", *exception_value1);
7390 try_catch.Reset();
7391
7392 Local<Value> args[] = { v8_num(23) };
7393 value = instance->CallAsConstructor(1, args);
7394 CHECK(try_catch.HasCaught());
7395 String::AsciiValue exception_value2(try_catch.Exception());
7396 CHECK_EQ("23", *exception_value2);
7397 try_catch.Reset();
7398 }
7399
7400 // Check whether constructor returns with an object or non-object.
7401 { Local<FunctionTemplate> function_template =
7402 FunctionTemplate::New(FakeConstructorCallback);
7403 Local<Function> function = function_template->GetFunction();
7404 Local<Object> instance1 = function;
7405 context->Global()->Set(v8_str("obj4"), instance1);
7406 v8::TryCatch try_catch;
7407 Local<Value> value;
7408 CHECK(!try_catch.HasCaught());
7409
7410 CHECK(instance1->IsObject());
7411 CHECK(instance1->IsFunction());
7412
7413 value = CompileRun("new obj4(28)");
7414 CHECK(!try_catch.HasCaught());
7415 CHECK(value->IsObject());
7416
7417 Local<Value> args1[] = { v8_num(28) };
7418 value = instance1->CallAsConstructor(1, args1);
7419 CHECK(!try_catch.HasCaught());
7420 CHECK(value->IsObject());
7421
7422 Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7423 instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
7424 Local<Object> instance2 = instance_template->NewInstance();
7425 context->Global()->Set(v8_str("obj5"), instance2);
7426 CHECK(!try_catch.HasCaught());
7427
7428 CHECK(instance2->IsObject());
7429 CHECK(!instance2->IsFunction());
7430
7431 value = CompileRun("new obj5(28)");
7432 CHECK(!try_catch.HasCaught());
7433 CHECK(!value->IsObject());
7434
7435 Local<Value> args2[] = { v8_num(28) };
7436 value = instance2->CallAsConstructor(1, args2);
7437 CHECK(!try_catch.HasCaught());
7438 CHECK(!value->IsObject());
7439 }
7440}
7441
7442
Steve Blocka7e24c12009-10-30 11:49:00 +00007443THREADED_TEST(FunctionDescriptorException) {
7444 v8::HandleScope handle_scope;
7445 LocalContext context;
7446 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7447 templ->SetClassName(v8_str("Fun"));
7448 Local<Function> cons = templ->GetFunction();
7449 context->Global()->Set(v8_str("Fun"), cons);
7450 Local<Value> value = CompileRun(
7451 "function test() {"
7452 " try {"
7453 " (new Fun()).blah()"
7454 " } catch (e) {"
7455 " var str = String(e);"
7456 " if (str.indexOf('TypeError') == -1) return 1;"
7457 " if (str.indexOf('[object Fun]') != -1) return 2;"
Steve Block1e0659c2011-05-24 12:43:12 +01007458 " if (str.indexOf('#<Fun>') == -1) return 3;"
Steve Blocka7e24c12009-10-30 11:49:00 +00007459 " return 0;"
7460 " }"
7461 " return 4;"
7462 "}"
7463 "test();");
7464 CHECK_EQ(0, value->Int32Value());
7465}
7466
7467
7468THREADED_TEST(EvalAliasedDynamic) {
7469 v8::HandleScope scope;
7470 LocalContext current;
7471
7472 // Tests where aliased eval can only be resolved dynamically.
7473 Local<Script> script =
7474 Script::Compile(v8_str("function f(x) { "
7475 " var foo = 2;"
7476 " with (x) { return eval('foo'); }"
7477 "}"
7478 "foo = 0;"
7479 "result1 = f(new Object());"
7480 "result2 = f(this);"
7481 "var x = new Object();"
7482 "x.eval = function(x) { return 1; };"
7483 "result3 = f(x);"));
7484 script->Run();
7485 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
7486 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
7487 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
7488
7489 v8::TryCatch try_catch;
7490 script =
7491 Script::Compile(v8_str("function f(x) { "
7492 " var bar = 2;"
7493 " with (x) { return eval('bar'); }"
7494 "}"
7495 "f(this)"));
7496 script->Run();
7497 CHECK(try_catch.HasCaught());
7498 try_catch.Reset();
7499}
7500
7501
7502THREADED_TEST(CrossEval) {
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 // Check that new variables are introduced in other context.
7515 Local<Script> script =
7516 Script::Compile(v8_str("other.eval('var foo = 1234')"));
7517 script->Run();
7518 Local<Value> foo = other->Global()->Get(v8_str("foo"));
7519 CHECK_EQ(1234, foo->Int32Value());
7520 CHECK(!current->Global()->Has(v8_str("foo")));
7521
7522 // Check that writing to non-existing properties introduces them in
7523 // the other context.
7524 script =
7525 Script::Compile(v8_str("other.eval('na = 1234')"));
7526 script->Run();
7527 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
7528 CHECK(!current->Global()->Has(v8_str("na")));
7529
7530 // Check that global variables in current context are not visible in other
7531 // context.
7532 v8::TryCatch try_catch;
7533 script =
7534 Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
7535 Local<Value> result = script->Run();
7536 CHECK(try_catch.HasCaught());
7537 try_catch.Reset();
7538
7539 // Check that local variables in current context are not visible in other
7540 // context.
7541 script =
7542 Script::Compile(v8_str("(function() { "
7543 " var baz = 87;"
7544 " return other.eval('baz');"
7545 "})();"));
7546 result = script->Run();
7547 CHECK(try_catch.HasCaught());
7548 try_catch.Reset();
7549
7550 // Check that global variables in the other environment are visible
7551 // when evaluting code.
7552 other->Global()->Set(v8_str("bis"), v8_num(1234));
7553 script = Script::Compile(v8_str("other.eval('bis')"));
7554 CHECK_EQ(1234, script->Run()->Int32Value());
7555 CHECK(!try_catch.HasCaught());
7556
7557 // Check that the 'this' pointer points to the global object evaluating
7558 // code.
7559 other->Global()->Set(v8_str("t"), other->Global());
7560 script = Script::Compile(v8_str("other.eval('this == t')"));
7561 result = script->Run();
7562 CHECK(result->IsTrue());
7563 CHECK(!try_catch.HasCaught());
7564
7565 // Check that variables introduced in with-statement are not visible in
7566 // other context.
7567 script =
7568 Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
7569 result = script->Run();
7570 CHECK(try_catch.HasCaught());
7571 try_catch.Reset();
7572
7573 // Check that you cannot use 'eval.call' with another object than the
7574 // current global object.
7575 script =
7576 Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
7577 result = script->Run();
7578 CHECK(try_catch.HasCaught());
7579}
7580
7581
7582// Test that calling eval in a context which has been detached from
7583// its global throws an exception. This behavior is consistent with
7584// other JavaScript implementations.
7585THREADED_TEST(EvalInDetachedGlobal) {
7586 v8::HandleScope scope;
7587
7588 v8::Persistent<Context> context0 = Context::New();
7589 v8::Persistent<Context> context1 = Context::New();
7590
7591 // Setup function in context0 that uses eval from context0.
7592 context0->Enter();
7593 v8::Handle<v8::Value> fun =
7594 CompileRun("var x = 42;"
7595 "(function() {"
7596 " var e = eval;"
7597 " return function(s) { return e(s); }"
7598 "})()");
7599 context0->Exit();
7600
7601 // Put the function into context1 and call it before and after
7602 // detaching the global. Before detaching, the call succeeds and
7603 // after detaching and exception is thrown.
7604 context1->Enter();
7605 context1->Global()->Set(v8_str("fun"), fun);
7606 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
7607 CHECK_EQ(42, x_value->Int32Value());
7608 context0->DetachGlobal();
7609 v8::TryCatch catcher;
7610 x_value = CompileRun("fun('x')");
7611 CHECK(x_value.IsEmpty());
7612 CHECK(catcher.HasCaught());
7613 context1->Exit();
7614
7615 context1.Dispose();
7616 context0.Dispose();
7617}
7618
7619
7620THREADED_TEST(CrossLazyLoad) {
7621 v8::HandleScope scope;
7622 LocalContext other;
7623 LocalContext current;
7624
7625 Local<String> token = v8_str("<security token>");
7626 other->SetSecurityToken(token);
7627 current->SetSecurityToken(token);
7628
7629 // Setup reference from current to other.
7630 current->Global()->Set(v8_str("other"), other->Global());
7631
7632 // Trigger lazy loading in other context.
7633 Local<Script> script =
7634 Script::Compile(v8_str("other.eval('new Date(42)')"));
7635 Local<Value> value = script->Run();
7636 CHECK_EQ(42.0, value->NumberValue());
7637}
7638
7639
7640static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
Andrei Popescu402d9372010-02-26 13:31:12 +00007641 ApiTestFuzzer::Fuzz();
Steve Blocka7e24c12009-10-30 11:49:00 +00007642 if (args.IsConstructCall()) {
7643 if (args[0]->IsInt32()) {
7644 return v8_num(-args[0]->Int32Value());
7645 }
7646 }
7647
7648 return args[0];
7649}
7650
7651
7652// Test that a call handler can be set for objects which will allow
7653// non-function objects created through the API to be called as
7654// functions.
7655THREADED_TEST(CallAsFunction) {
7656 v8::HandleScope scope;
7657 LocalContext context;
7658
Ben Murdoch257744e2011-11-30 15:57:28 +00007659 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7660 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7661 instance_template->SetCallAsFunctionHandler(call_as_function);
7662 Local<v8::Object> instance = t->GetFunction()->NewInstance();
7663 context->Global()->Set(v8_str("obj"), instance);
7664 v8::TryCatch try_catch;
7665 Local<Value> value;
7666 CHECK(!try_catch.HasCaught());
Steve Blocka7e24c12009-10-30 11:49:00 +00007667
Ben Murdoch257744e2011-11-30 15:57:28 +00007668 value = CompileRun("obj(42)");
7669 CHECK(!try_catch.HasCaught());
7670 CHECK_EQ(42, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00007671
Ben Murdoch257744e2011-11-30 15:57:28 +00007672 value = CompileRun("(function(o){return o(49)})(obj)");
7673 CHECK(!try_catch.HasCaught());
7674 CHECK_EQ(49, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00007675
Ben Murdoch257744e2011-11-30 15:57:28 +00007676 // test special case of call as function
7677 value = CompileRun("[obj]['0'](45)");
7678 CHECK(!try_catch.HasCaught());
7679 CHECK_EQ(45, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00007680
Ben Murdoch257744e2011-11-30 15:57:28 +00007681 value = CompileRun("obj.call = Function.prototype.call;"
7682 "obj.call(null, 87)");
7683 CHECK(!try_catch.HasCaught());
7684 CHECK_EQ(87, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00007685
Ben Murdoch257744e2011-11-30 15:57:28 +00007686 // Regression tests for bug #1116356: Calling call through call/apply
7687 // must work for non-function receivers.
7688 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
7689 value = CompileRun(apply_99);
7690 CHECK(!try_catch.HasCaught());
7691 CHECK_EQ(99, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00007692
Ben Murdoch257744e2011-11-30 15:57:28 +00007693 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
7694 value = CompileRun(call_17);
7695 CHECK(!try_catch.HasCaught());
7696 CHECK_EQ(17, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00007697
Ben Murdoch257744e2011-11-30 15:57:28 +00007698 // Check that the call-as-function handler can be called through
7699 // new.
7700 value = CompileRun("new obj(43)");
7701 CHECK(!try_catch.HasCaught());
7702 CHECK_EQ(-43, value->Int32Value());
7703
7704 // Check that the call-as-function handler can be called through
7705 // the API.
7706 v8::Handle<Value> args[] = { v8_num(28) };
7707 value = instance->CallAsFunction(instance, 1, args);
7708 CHECK(!try_catch.HasCaught());
7709 CHECK_EQ(28, value->Int32Value());
7710 }
7711
7712 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7713 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7714 Local<v8::Object> instance = t->GetFunction()->NewInstance();
7715 context->Global()->Set(v8_str("obj2"), instance);
7716 v8::TryCatch try_catch;
7717 Local<Value> value;
7718 CHECK(!try_catch.HasCaught());
7719
7720 // Call an object without call-as-function handler through the JS
7721 value = CompileRun("obj2(28)");
7722 CHECK(value.IsEmpty());
7723 CHECK(try_catch.HasCaught());
7724 String::AsciiValue exception_value1(try_catch.Exception());
7725 CHECK_EQ("TypeError: Property 'obj2' of object #<Object> is not a function",
7726 *exception_value1);
7727 try_catch.Reset();
7728
7729 // Call an object without call-as-function handler through the API
7730 value = CompileRun("obj2(28)");
7731 v8::Handle<Value> args[] = { v8_num(28) };
7732 value = instance->CallAsFunction(instance, 1, args);
7733 CHECK(value.IsEmpty());
7734 CHECK(try_catch.HasCaught());
7735 String::AsciiValue exception_value2(try_catch.Exception());
7736 CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
7737 try_catch.Reset();
7738 }
7739
7740 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7741 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7742 instance_template->SetCallAsFunctionHandler(ThrowValue);
7743 Local<v8::Object> instance = t->GetFunction()->NewInstance();
7744 context->Global()->Set(v8_str("obj3"), instance);
7745 v8::TryCatch try_catch;
7746 Local<Value> value;
7747 CHECK(!try_catch.HasCaught());
7748
7749 // Catch the exception which is thrown by call-as-function handler
7750 value = CompileRun("obj3(22)");
7751 CHECK(try_catch.HasCaught());
7752 String::AsciiValue exception_value1(try_catch.Exception());
7753 CHECK_EQ("22", *exception_value1);
7754 try_catch.Reset();
7755
7756 v8::Handle<Value> args[] = { v8_num(23) };
7757 value = instance->CallAsFunction(instance, 1, args);
7758 CHECK(try_catch.HasCaught());
7759 String::AsciiValue exception_value2(try_catch.Exception());
7760 CHECK_EQ("23", *exception_value2);
7761 try_catch.Reset();
7762 }
7763}
7764
7765
7766// Check whether a non-function object is callable.
7767THREADED_TEST(CallableObject) {
7768 v8::HandleScope scope;
7769 LocalContext context;
7770
7771 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7772 instance_template->SetCallAsFunctionHandler(call_as_function);
7773 Local<Object> instance = instance_template->NewInstance();
7774 v8::TryCatch try_catch;
7775
7776 CHECK(instance->IsCallable());
7777 CHECK(!try_catch.HasCaught());
7778 }
7779
7780 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7781 Local<Object> instance = instance_template->NewInstance();
7782 v8::TryCatch try_catch;
7783
7784 CHECK(!instance->IsCallable());
7785 CHECK(!try_catch.HasCaught());
7786 }
7787
7788 { Local<FunctionTemplate> function_template =
7789 FunctionTemplate::New(call_as_function);
7790 Local<Function> function = function_template->GetFunction();
7791 Local<Object> instance = function;
7792 v8::TryCatch try_catch;
7793
7794 CHECK(instance->IsCallable());
7795 CHECK(!try_catch.HasCaught());
7796 }
7797
7798 { Local<FunctionTemplate> function_template = FunctionTemplate::New();
7799 Local<Function> function = function_template->GetFunction();
7800 Local<Object> instance = function;
7801 v8::TryCatch try_catch;
7802
7803 CHECK(instance->IsCallable());
7804 CHECK(!try_catch.HasCaught());
7805 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007806}
7807
7808
7809static int CountHandles() {
7810 return v8::HandleScope::NumberOfHandles();
7811}
7812
7813
7814static int Recurse(int depth, int iterations) {
7815 v8::HandleScope scope;
7816 if (depth == 0) return CountHandles();
7817 for (int i = 0; i < iterations; i++) {
7818 Local<v8::Number> n = v8::Integer::New(42);
7819 }
7820 return Recurse(depth - 1, iterations);
7821}
7822
7823
7824THREADED_TEST(HandleIteration) {
7825 static const int kIterations = 500;
7826 static const int kNesting = 200;
7827 CHECK_EQ(0, CountHandles());
7828 {
7829 v8::HandleScope scope1;
7830 CHECK_EQ(0, CountHandles());
7831 for (int i = 0; i < kIterations; i++) {
7832 Local<v8::Number> n = v8::Integer::New(42);
7833 CHECK_EQ(i + 1, CountHandles());
7834 }
7835
7836 CHECK_EQ(kIterations, CountHandles());
7837 {
7838 v8::HandleScope scope2;
7839 for (int j = 0; j < kIterations; j++) {
7840 Local<v8::Number> n = v8::Integer::New(42);
7841 CHECK_EQ(j + 1 + kIterations, CountHandles());
7842 }
7843 }
7844 CHECK_EQ(kIterations, CountHandles());
7845 }
7846 CHECK_EQ(0, CountHandles());
7847 CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
7848}
7849
7850
7851static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
7852 Local<String> name,
7853 const AccessorInfo& info) {
7854 ApiTestFuzzer::Fuzz();
7855 return v8::Handle<Value>();
7856}
7857
7858
7859THREADED_TEST(InterceptorHasOwnProperty) {
7860 v8::HandleScope scope;
7861 LocalContext context;
7862 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7863 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
7864 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
7865 Local<Function> function = fun_templ->GetFunction();
7866 context->Global()->Set(v8_str("constructor"), function);
7867 v8::Handle<Value> value = CompileRun(
7868 "var o = new constructor();"
7869 "o.hasOwnProperty('ostehaps');");
7870 CHECK_EQ(false, value->BooleanValue());
7871 value = CompileRun(
7872 "o.ostehaps = 42;"
7873 "o.hasOwnProperty('ostehaps');");
7874 CHECK_EQ(true, value->BooleanValue());
7875 value = CompileRun(
7876 "var p = new constructor();"
7877 "p.hasOwnProperty('ostehaps');");
7878 CHECK_EQ(false, value->BooleanValue());
7879}
7880
7881
7882static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
7883 Local<String> name,
7884 const AccessorInfo& info) {
7885 ApiTestFuzzer::Fuzz();
Steve Block44f0eee2011-05-26 01:26:41 +01007886 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +00007887 return v8::Handle<Value>();
7888}
7889
7890
7891THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
7892 v8::HandleScope scope;
7893 LocalContext context;
7894 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7895 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
7896 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
7897 Local<Function> function = fun_templ->GetFunction();
7898 context->Global()->Set(v8_str("constructor"), function);
7899 // Let's first make some stuff so we can be sure to get a good GC.
7900 CompileRun(
7901 "function makestr(size) {"
7902 " switch (size) {"
7903 " case 1: return 'f';"
7904 " case 2: return 'fo';"
7905 " case 3: return 'foo';"
7906 " }"
7907 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
7908 "}"
7909 "var x = makestr(12345);"
7910 "x = makestr(31415);"
7911 "x = makestr(23456);");
7912 v8::Handle<Value> value = CompileRun(
7913 "var o = new constructor();"
7914 "o.__proto__ = new String(x);"
7915 "o.hasOwnProperty('ostehaps');");
7916 CHECK_EQ(false, value->BooleanValue());
7917}
7918
7919
7920typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
7921 const AccessorInfo& info);
7922
7923
7924static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
7925 const char* source,
7926 int expected) {
7927 v8::HandleScope scope;
7928 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08007929 templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
Steve Blocka7e24c12009-10-30 11:49:00 +00007930 LocalContext context;
7931 context->Global()->Set(v8_str("o"), templ->NewInstance());
7932 v8::Handle<Value> value = CompileRun(source);
7933 CHECK_EQ(expected, value->Int32Value());
7934}
7935
7936
7937static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
7938 const AccessorInfo& info) {
7939 ApiTestFuzzer::Fuzz();
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08007940 CHECK_EQ(v8_str("data"), info.Data());
7941 CHECK_EQ(v8_str("x"), name);
Steve Blocka7e24c12009-10-30 11:49:00 +00007942 return v8::Integer::New(42);
7943}
7944
7945
7946// This test should hit the load IC for the interceptor case.
7947THREADED_TEST(InterceptorLoadIC) {
7948 CheckInterceptorLoadIC(InterceptorLoadICGetter,
7949 "var result = 0;"
7950 "for (var i = 0; i < 1000; i++) {"
7951 " result = o.x;"
7952 "}",
7953 42);
7954}
7955
7956
7957// Below go several tests which verify that JITing for various
7958// configurations of interceptor and explicit fields works fine
7959// (those cases are special cased to get better performance).
7960
7961static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
7962 const AccessorInfo& info) {
7963 ApiTestFuzzer::Fuzz();
7964 return v8_str("x")->Equals(name)
7965 ? v8::Integer::New(42) : v8::Handle<v8::Value>();
7966}
7967
7968
7969THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
7970 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7971 "var result = 0;"
7972 "o.y = 239;"
7973 "for (var i = 0; i < 1000; i++) {"
7974 " result = o.y;"
7975 "}",
7976 239);
7977}
7978
7979
7980THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
7981 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7982 "var result = 0;"
7983 "o.__proto__ = { 'y': 239 };"
7984 "for (var i = 0; i < 1000; i++) {"
7985 " result = o.y + o.x;"
7986 "}",
7987 239 + 42);
7988}
7989
7990
7991THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
7992 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7993 "var result = 0;"
7994 "o.__proto__.y = 239;"
7995 "for (var i = 0; i < 1000; i++) {"
7996 " result = o.y + o.x;"
7997 "}",
7998 239 + 42);
7999}
8000
8001
8002THREADED_TEST(InterceptorLoadICUndefined) {
8003 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8004 "var result = 0;"
8005 "for (var i = 0; i < 1000; i++) {"
8006 " result = (o.y == undefined) ? 239 : 42;"
8007 "}",
8008 239);
8009}
8010
8011
8012THREADED_TEST(InterceptorLoadICWithOverride) {
8013 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8014 "fst = new Object(); fst.__proto__ = o;"
8015 "snd = new Object(); snd.__proto__ = fst;"
8016 "var result1 = 0;"
8017 "for (var i = 0; i < 1000; i++) {"
8018 " result1 = snd.x;"
8019 "}"
8020 "fst.x = 239;"
8021 "var result = 0;"
8022 "for (var i = 0; i < 1000; i++) {"
8023 " result = snd.x;"
8024 "}"
8025 "result + result1",
8026 239 + 42);
8027}
8028
8029
8030// Test the case when we stored field into
8031// a stub, but interceptor produced value on its own.
8032THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
8033 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8034 "proto = new Object();"
8035 "o.__proto__ = proto;"
8036 "proto.x = 239;"
8037 "for (var i = 0; i < 1000; i++) {"
8038 " o.x;"
8039 // Now it should be ICed and keep a reference to x defined on proto
8040 "}"
8041 "var result = 0;"
8042 "for (var i = 0; i < 1000; i++) {"
8043 " result += o.x;"
8044 "}"
8045 "result;",
8046 42 * 1000);
8047}
8048
8049
8050// Test the case when we stored field into
8051// a stub, but it got invalidated later on.
8052THREADED_TEST(InterceptorLoadICInvalidatedField) {
8053 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8054 "proto1 = new Object();"
8055 "proto2 = new Object();"
8056 "o.__proto__ = proto1;"
8057 "proto1.__proto__ = proto2;"
8058 "proto2.y = 239;"
8059 "for (var i = 0; i < 1000; i++) {"
8060 " o.y;"
8061 // Now it should be ICed and keep a reference to y defined on proto2
8062 "}"
8063 "proto1.y = 42;"
8064 "var result = 0;"
8065 "for (var i = 0; i < 1000; i++) {"
8066 " result += o.y;"
8067 "}"
8068 "result;",
8069 42 * 1000);
8070}
8071
8072
Steve Block6ded16b2010-05-10 14:33:55 +01008073static int interceptor_load_not_handled_calls = 0;
8074static v8::Handle<Value> InterceptorLoadNotHandled(Local<String> name,
8075 const AccessorInfo& info) {
8076 ++interceptor_load_not_handled_calls;
8077 return v8::Handle<v8::Value>();
8078}
8079
8080
8081// Test how post-interceptor lookups are done in the non-cacheable
8082// case: the interceptor should not be invoked during this lookup.
8083THREADED_TEST(InterceptorLoadICPostInterceptor) {
8084 interceptor_load_not_handled_calls = 0;
8085 CheckInterceptorLoadIC(InterceptorLoadNotHandled,
8086 "receiver = new Object();"
8087 "receiver.__proto__ = o;"
8088 "proto = new Object();"
8089 "/* Make proto a slow-case object. */"
8090 "for (var i = 0; i < 1000; i++) {"
8091 " proto[\"xxxxxxxx\" + i] = [];"
8092 "}"
8093 "proto.x = 17;"
8094 "o.__proto__ = proto;"
8095 "var result = 0;"
8096 "for (var i = 0; i < 1000; i++) {"
8097 " result += receiver.x;"
8098 "}"
8099 "result;",
8100 17 * 1000);
8101 CHECK_EQ(1000, interceptor_load_not_handled_calls);
8102}
8103
8104
Steve Blocka7e24c12009-10-30 11:49:00 +00008105// Test the case when we stored field into
8106// a stub, but it got invalidated later on due to override on
8107// global object which is between interceptor and fields' holders.
8108THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
8109 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8110 "o.__proto__ = this;" // set a global to be a proto of o.
8111 "this.__proto__.y = 239;"
8112 "for (var i = 0; i < 10; i++) {"
8113 " if (o.y != 239) throw 'oops: ' + o.y;"
8114 // Now it should be ICed and keep a reference to y defined on field_holder.
8115 "}"
8116 "this.y = 42;" // Assign on a global.
8117 "var result = 0;"
8118 "for (var i = 0; i < 10; i++) {"
8119 " result += o.y;"
8120 "}"
8121 "result;",
8122 42 * 10);
8123}
8124
8125
Steve Blocka7e24c12009-10-30 11:49:00 +00008126static void SetOnThis(Local<String> name,
8127 Local<Value> value,
8128 const AccessorInfo& info) {
8129 info.This()->ForceSet(name, value);
8130}
8131
8132
8133THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
8134 v8::HandleScope scope;
8135 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8136 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8137 templ->SetAccessor(v8_str("y"), Return239);
8138 LocalContext context;
8139 context->Global()->Set(v8_str("o"), templ->NewInstance());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008140
8141 // Check the case when receiver and interceptor's holder
8142 // are the same objects.
Steve Blocka7e24c12009-10-30 11:49:00 +00008143 v8::Handle<Value> value = CompileRun(
8144 "var result = 0;"
8145 "for (var i = 0; i < 7; i++) {"
8146 " result = o.y;"
8147 "}");
8148 CHECK_EQ(239, value->Int32Value());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008149
8150 // Check the case when interceptor's holder is in proto chain
8151 // of receiver.
8152 value = CompileRun(
8153 "r = { __proto__: o };"
8154 "var result = 0;"
8155 "for (var i = 0; i < 7; i++) {"
8156 " result = r.y;"
8157 "}");
8158 CHECK_EQ(239, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00008159}
8160
8161
8162THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
8163 v8::HandleScope scope;
8164 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8165 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8166 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8167 templ_p->SetAccessor(v8_str("y"), Return239);
8168
8169 LocalContext context;
8170 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8171 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8172
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008173 // Check the case when receiver and interceptor's holder
8174 // are the same objects.
Steve Blocka7e24c12009-10-30 11:49:00 +00008175 v8::Handle<Value> value = CompileRun(
8176 "o.__proto__ = p;"
8177 "var result = 0;"
8178 "for (var i = 0; i < 7; i++) {"
8179 " result = o.x + o.y;"
8180 "}");
8181 CHECK_EQ(239 + 42, value->Int32Value());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008182
8183 // Check the case when interceptor's holder is in proto chain
8184 // of receiver.
8185 value = CompileRun(
8186 "r = { __proto__: o };"
8187 "var result = 0;"
8188 "for (var i = 0; i < 7; i++) {"
8189 " result = r.x + r.y;"
8190 "}");
8191 CHECK_EQ(239 + 42, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00008192}
8193
8194
8195THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
8196 v8::HandleScope scope;
8197 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8198 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8199 templ->SetAccessor(v8_str("y"), Return239);
8200
8201 LocalContext context;
8202 context->Global()->Set(v8_str("o"), templ->NewInstance());
8203
8204 v8::Handle<Value> value = CompileRun(
8205 "fst = new Object(); fst.__proto__ = o;"
8206 "snd = new Object(); snd.__proto__ = fst;"
8207 "var result1 = 0;"
8208 "for (var i = 0; i < 7; i++) {"
8209 " result1 = snd.x;"
8210 "}"
8211 "fst.x = 239;"
8212 "var result = 0;"
8213 "for (var i = 0; i < 7; i++) {"
8214 " result = snd.x;"
8215 "}"
8216 "result + result1");
8217 CHECK_EQ(239 + 42, value->Int32Value());
8218}
8219
8220
8221// Test the case when we stored callback into
8222// a stub, but interceptor produced value on its own.
8223THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
8224 v8::HandleScope scope;
8225 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8226 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8227 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8228 templ_p->SetAccessor(v8_str("y"), Return239);
8229
8230 LocalContext context;
8231 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8232 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8233
8234 v8::Handle<Value> value = CompileRun(
8235 "o.__proto__ = p;"
8236 "for (var i = 0; i < 7; i++) {"
8237 " o.x;"
8238 // Now it should be ICed and keep a reference to x defined on p
8239 "}"
8240 "var result = 0;"
8241 "for (var i = 0; i < 7; i++) {"
8242 " result += o.x;"
8243 "}"
8244 "result");
8245 CHECK_EQ(42 * 7, value->Int32Value());
8246}
8247
8248
8249// Test the case when we stored callback into
8250// a stub, but it got invalidated later on.
8251THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
8252 v8::HandleScope scope;
8253 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8254 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8255 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8256 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
8257
8258 LocalContext context;
8259 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8260 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8261
8262 v8::Handle<Value> value = CompileRun(
8263 "inbetween = new Object();"
8264 "o.__proto__ = inbetween;"
8265 "inbetween.__proto__ = p;"
8266 "for (var i = 0; i < 10; i++) {"
8267 " o.y;"
8268 // Now it should be ICed and keep a reference to y defined on p
8269 "}"
8270 "inbetween.y = 42;"
8271 "var result = 0;"
8272 "for (var i = 0; i < 10; i++) {"
8273 " result += o.y;"
8274 "}"
8275 "result");
8276 CHECK_EQ(42 * 10, value->Int32Value());
8277}
8278
8279
8280// Test the case when we stored callback into
8281// a stub, but it got invalidated later on due to override on
8282// global object which is between interceptor and callbacks' holders.
8283THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
8284 v8::HandleScope scope;
8285 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8286 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8287 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8288 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
8289
8290 LocalContext context;
8291 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8292 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8293
8294 v8::Handle<Value> value = CompileRun(
8295 "o.__proto__ = this;"
8296 "this.__proto__ = p;"
8297 "for (var i = 0; i < 10; i++) {"
8298 " if (o.y != 239) throw 'oops: ' + o.y;"
8299 // Now it should be ICed and keep a reference to y defined on p
8300 "}"
8301 "this.y = 42;"
8302 "var result = 0;"
8303 "for (var i = 0; i < 10; i++) {"
8304 " result += o.y;"
8305 "}"
8306 "result");
8307 CHECK_EQ(42 * 10, value->Int32Value());
8308}
8309
8310
8311static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
8312 const AccessorInfo& info) {
8313 ApiTestFuzzer::Fuzz();
8314 CHECK(v8_str("x")->Equals(name));
8315 return v8::Integer::New(0);
8316}
8317
8318
8319THREADED_TEST(InterceptorReturningZero) {
8320 CheckInterceptorLoadIC(InterceptorLoadICGetter0,
8321 "o.x == undefined ? 1 : 0",
8322 0);
8323}
8324
8325
8326static v8::Handle<Value> InterceptorStoreICSetter(
8327 Local<String> key, Local<Value> value, const AccessorInfo&) {
8328 CHECK(v8_str("x")->Equals(key));
8329 CHECK_EQ(42, value->Int32Value());
8330 return value;
8331}
8332
8333
8334// This test should hit the store IC for the interceptor case.
8335THREADED_TEST(InterceptorStoreIC) {
8336 v8::HandleScope scope;
8337 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8338 templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08008339 InterceptorStoreICSetter,
8340 0, 0, 0, v8_str("data"));
Steve Blocka7e24c12009-10-30 11:49:00 +00008341 LocalContext context;
8342 context->Global()->Set(v8_str("o"), templ->NewInstance());
8343 v8::Handle<Value> value = CompileRun(
8344 "for (var i = 0; i < 1000; i++) {"
8345 " o.x = 42;"
8346 "}");
8347}
8348
8349
8350THREADED_TEST(InterceptorStoreICWithNoSetter) {
8351 v8::HandleScope scope;
8352 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8353 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8354 LocalContext context;
8355 context->Global()->Set(v8_str("o"), templ->NewInstance());
8356 v8::Handle<Value> value = CompileRun(
8357 "for (var i = 0; i < 1000; i++) {"
8358 " o.y = 239;"
8359 "}"
8360 "42 + o.y");
8361 CHECK_EQ(239 + 42, value->Int32Value());
8362}
8363
8364
8365
8366
8367v8::Handle<Value> call_ic_function;
8368v8::Handle<Value> call_ic_function2;
8369v8::Handle<Value> call_ic_function3;
8370
8371static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
8372 const AccessorInfo& info) {
8373 ApiTestFuzzer::Fuzz();
8374 CHECK(v8_str("x")->Equals(name));
8375 return call_ic_function;
8376}
8377
8378
8379// This test should hit the call IC for the interceptor case.
8380THREADED_TEST(InterceptorCallIC) {
8381 v8::HandleScope scope;
8382 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8383 templ->SetNamedPropertyHandler(InterceptorCallICGetter);
8384 LocalContext context;
8385 context->Global()->Set(v8_str("o"), templ->NewInstance());
8386 call_ic_function =
8387 v8_compile("function f(x) { return x + 1; }; f")->Run();
8388 v8::Handle<Value> value = CompileRun(
8389 "var result = 0;"
8390 "for (var i = 0; i < 1000; i++) {"
8391 " result = o.x(41);"
8392 "}");
8393 CHECK_EQ(42, value->Int32Value());
8394}
8395
8396
8397// This test checks that if interceptor doesn't provide
8398// a value, we can fetch regular value.
8399THREADED_TEST(InterceptorCallICSeesOthers) {
8400 v8::HandleScope scope;
8401 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8402 templ->SetNamedPropertyHandler(NoBlockGetterX);
8403 LocalContext context;
8404 context->Global()->Set(v8_str("o"), templ->NewInstance());
8405 v8::Handle<Value> value = CompileRun(
8406 "o.x = function f(x) { return x + 1; };"
8407 "var result = 0;"
8408 "for (var i = 0; i < 7; i++) {"
8409 " result = o.x(41);"
8410 "}");
8411 CHECK_EQ(42, value->Int32Value());
8412}
8413
8414
8415static v8::Handle<Value> call_ic_function4;
8416static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
8417 const AccessorInfo& info) {
8418 ApiTestFuzzer::Fuzz();
8419 CHECK(v8_str("x")->Equals(name));
8420 return call_ic_function4;
8421}
8422
8423
8424// This test checks that if interceptor provides a function,
8425// even if we cached shadowed variant, interceptor's function
8426// is invoked
8427THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
8428 v8::HandleScope scope;
8429 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8430 templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
8431 LocalContext context;
8432 context->Global()->Set(v8_str("o"), templ->NewInstance());
8433 call_ic_function4 =
8434 v8_compile("function f(x) { return x - 1; }; f")->Run();
8435 v8::Handle<Value> value = CompileRun(
8436 "o.__proto__.x = function(x) { return x + 1; };"
8437 "var result = 0;"
8438 "for (var i = 0; i < 1000; i++) {"
8439 " result = o.x(42);"
8440 "}");
8441 CHECK_EQ(41, value->Int32Value());
8442}
8443
8444
8445// Test the case when we stored cacheable lookup into
8446// a stub, but it got invalidated later on
8447THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
8448 v8::HandleScope scope;
8449 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8450 templ->SetNamedPropertyHandler(NoBlockGetterX);
8451 LocalContext context;
8452 context->Global()->Set(v8_str("o"), templ->NewInstance());
8453 v8::Handle<Value> value = CompileRun(
8454 "proto1 = new Object();"
8455 "proto2 = new Object();"
8456 "o.__proto__ = proto1;"
8457 "proto1.__proto__ = proto2;"
8458 "proto2.y = function(x) { return x + 1; };"
8459 // Invoke it many times to compile a stub
8460 "for (var i = 0; i < 7; i++) {"
8461 " o.y(42);"
8462 "}"
8463 "proto1.y = function(x) { return x - 1; };"
8464 "var result = 0;"
8465 "for (var i = 0; i < 7; i++) {"
8466 " result += o.y(42);"
8467 "}");
8468 CHECK_EQ(41 * 7, value->Int32Value());
8469}
8470
8471
8472static v8::Handle<Value> call_ic_function5;
8473static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
8474 const AccessorInfo& info) {
8475 ApiTestFuzzer::Fuzz();
8476 if (v8_str("x")->Equals(name))
8477 return call_ic_function5;
8478 else
8479 return Local<Value>();
8480}
8481
8482
8483// This test checks that if interceptor doesn't provide a function,
8484// cached constant function is used
8485THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
8486 v8::HandleScope scope;
8487 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8488 templ->SetNamedPropertyHandler(NoBlockGetterX);
8489 LocalContext context;
8490 context->Global()->Set(v8_str("o"), templ->NewInstance());
8491 v8::Handle<Value> value = CompileRun(
8492 "function inc(x) { return x + 1; };"
8493 "inc(1);"
8494 "o.x = inc;"
8495 "var result = 0;"
8496 "for (var i = 0; i < 1000; i++) {"
8497 " result = o.x(42);"
8498 "}");
8499 CHECK_EQ(43, value->Int32Value());
8500}
8501
8502
8503// This test checks that if interceptor provides a function,
8504// even if we cached constant function, interceptor's function
8505// is invoked
8506THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
8507 v8::HandleScope scope;
8508 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8509 templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
8510 LocalContext context;
8511 context->Global()->Set(v8_str("o"), templ->NewInstance());
8512 call_ic_function5 =
8513 v8_compile("function f(x) { return x - 1; }; f")->Run();
8514 v8::Handle<Value> value = CompileRun(
8515 "function inc(x) { return x + 1; };"
8516 "inc(1);"
8517 "o.x = inc;"
8518 "var result = 0;"
8519 "for (var i = 0; i < 1000; i++) {"
8520 " result = o.x(42);"
8521 "}");
8522 CHECK_EQ(41, value->Int32Value());
8523}
8524
8525
8526// Test the case when we stored constant function into
8527// a stub, but it got invalidated later on
8528THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
8529 v8::HandleScope scope;
8530 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8531 templ->SetNamedPropertyHandler(NoBlockGetterX);
8532 LocalContext context;
8533 context->Global()->Set(v8_str("o"), templ->NewInstance());
8534 v8::Handle<Value> value = CompileRun(
8535 "function inc(x) { return x + 1; };"
8536 "inc(1);"
8537 "proto1 = new Object();"
8538 "proto2 = new Object();"
8539 "o.__proto__ = proto1;"
8540 "proto1.__proto__ = proto2;"
8541 "proto2.y = inc;"
8542 // Invoke it many times to compile a stub
8543 "for (var i = 0; i < 7; i++) {"
8544 " o.y(42);"
8545 "}"
8546 "proto1.y = function(x) { return x - 1; };"
8547 "var result = 0;"
8548 "for (var i = 0; i < 7; i++) {"
8549 " result += o.y(42);"
8550 "}");
8551 CHECK_EQ(41 * 7, value->Int32Value());
8552}
8553
8554
8555// Test the case when we stored constant function into
8556// a stub, but it got invalidated later on due to override on
8557// global object which is between interceptor and constant function' holders.
8558THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
8559 v8::HandleScope scope;
8560 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8561 templ->SetNamedPropertyHandler(NoBlockGetterX);
8562 LocalContext context;
8563 context->Global()->Set(v8_str("o"), templ->NewInstance());
8564 v8::Handle<Value> value = CompileRun(
8565 "function inc(x) { return x + 1; };"
8566 "inc(1);"
8567 "o.__proto__ = this;"
8568 "this.__proto__.y = inc;"
8569 // Invoke it many times to compile a stub
8570 "for (var i = 0; i < 7; i++) {"
8571 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
8572 "}"
8573 "this.y = function(x) { return x - 1; };"
8574 "var result = 0;"
8575 "for (var i = 0; i < 7; i++) {"
8576 " result += o.y(42);"
8577 "}");
8578 CHECK_EQ(41 * 7, value->Int32Value());
8579}
8580
8581
Leon Clarke4515c472010-02-03 11:58:03 +00008582// Test the case when actual function to call sits on global object.
8583THREADED_TEST(InterceptorCallICCachedFromGlobal) {
8584 v8::HandleScope scope;
8585 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8586 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
8587
8588 LocalContext context;
8589 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8590
8591 v8::Handle<Value> value = CompileRun(
8592 "try {"
8593 " o.__proto__ = this;"
8594 " for (var i = 0; i < 10; i++) {"
8595 " var v = o.parseFloat('239');"
8596 " if (v != 239) throw v;"
8597 // Now it should be ICed and keep a reference to parseFloat.
8598 " }"
8599 " var result = 0;"
8600 " for (var i = 0; i < 10; i++) {"
8601 " result += o.parseFloat('239');"
8602 " }"
8603 " result"
8604 "} catch(e) {"
8605 " e"
8606 "};");
8607 CHECK_EQ(239 * 10, value->Int32Value());
8608}
8609
Andrei Popescu402d9372010-02-26 13:31:12 +00008610static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
8611 const AccessorInfo& info) {
8612 ApiTestFuzzer::Fuzz();
8613 int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data()));
8614 ++(*call_count);
8615 if ((*call_count) % 20 == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01008616 HEAP->CollectAllGarbage(true);
Andrei Popescu402d9372010-02-26 13:31:12 +00008617 }
8618 return v8::Handle<Value>();
8619}
8620
8621static v8::Handle<Value> FastApiCallback_TrivialSignature(
8622 const v8::Arguments& args) {
8623 ApiTestFuzzer::Fuzz();
8624 CHECK_EQ(args.This(), args.Holder());
8625 CHECK(args.Data()->Equals(v8_str("method_data")));
8626 return v8::Integer::New(args[0]->Int32Value() + 1);
8627}
8628
8629static v8::Handle<Value> FastApiCallback_SimpleSignature(
8630 const v8::Arguments& args) {
8631 ApiTestFuzzer::Fuzz();
8632 CHECK_EQ(args.This()->GetPrototype(), args.Holder());
8633 CHECK(args.Data()->Equals(v8_str("method_data")));
8634 // Note, we're using HasRealNamedProperty instead of Has to avoid
8635 // invoking the interceptor again.
8636 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
8637 return v8::Integer::New(args[0]->Int32Value() + 1);
8638}
8639
8640// Helper to maximize the odds of object moving.
8641static void GenerateSomeGarbage() {
8642 CompileRun(
8643 "var garbage;"
8644 "for (var i = 0; i < 1000; i++) {"
8645 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
8646 "}"
8647 "garbage = undefined;");
8648}
8649
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008650
Steve Block1e0659c2011-05-24 12:43:12 +01008651v8::Handle<v8::Value> DirectApiCallback(const v8::Arguments& args) {
8652 static int count = 0;
8653 if (count++ % 3 == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01008654 HEAP-> CollectAllGarbage(true); // This should move the stub
Steve Block1e0659c2011-05-24 12:43:12 +01008655 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
8656 }
8657 return v8::Handle<v8::Value>();
8658}
8659
8660
8661THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
8662 v8::HandleScope scope;
8663 LocalContext context;
8664 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
8665 nativeobject_templ->Set("callback",
8666 v8::FunctionTemplate::New(DirectApiCallback));
8667 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
8668 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
8669 // call the api function multiple times to ensure direct call stub creation.
8670 CompileRun(
8671 "function f() {"
8672 " for (var i = 1; i <= 30; i++) {"
8673 " nativeobject.callback();"
8674 " }"
8675 "}"
8676 "f();");
8677}
8678
8679
8680v8::Handle<v8::Value> ThrowingDirectApiCallback(const v8::Arguments& args) {
8681 return v8::ThrowException(v8_str("g"));
8682}
8683
8684
8685THREADED_TEST(CallICFastApi_DirectCall_Throw) {
8686 v8::HandleScope scope;
8687 LocalContext context;
8688 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
8689 nativeobject_templ->Set("callback",
8690 v8::FunctionTemplate::New(ThrowingDirectApiCallback));
8691 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
8692 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
8693 // call the api function multiple times to ensure direct call stub creation.
8694 v8::Handle<Value> result = CompileRun(
8695 "var result = '';"
8696 "function f() {"
8697 " for (var i = 1; i <= 5; i++) {"
8698 " try { nativeobject.callback(); } catch (e) { result += e; }"
8699 " }"
8700 "}"
8701 "f(); result;");
8702 CHECK_EQ(v8_str("ggggg"), result);
8703}
8704
8705
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008706v8::Handle<v8::Value> DirectGetterCallback(Local<String> name,
8707 const v8::AccessorInfo& info) {
8708 if (++p_getter_count % 3 == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01008709 HEAP->CollectAllGarbage(true);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008710 GenerateSomeGarbage();
8711 }
8712 return v8::Handle<v8::Value>();
8713}
8714
8715
8716THREADED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
8717 v8::HandleScope scope;
8718 LocalContext context;
8719 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
8720 obj->SetAccessor(v8_str("p1"), DirectGetterCallback);
8721 context->Global()->Set(v8_str("o1"), obj->NewInstance());
8722 p_getter_count = 0;
8723 CompileRun(
8724 "function f() {"
8725 " for (var i = 0; i < 30; i++) o1.p1;"
8726 "}"
8727 "f();");
8728 CHECK_EQ(30, p_getter_count);
8729}
8730
8731
8732v8::Handle<v8::Value> ThrowingDirectGetterCallback(
8733 Local<String> name, const v8::AccessorInfo& info) {
8734 return v8::ThrowException(v8_str("g"));
8735}
8736
8737
8738THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
8739 v8::HandleScope scope;
8740 LocalContext context;
8741 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
8742 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
8743 context->Global()->Set(v8_str("o1"), obj->NewInstance());
8744 v8::Handle<Value> result = CompileRun(
8745 "var result = '';"
8746 "for (var i = 0; i < 5; i++) {"
8747 " try { o1.p1; } catch (e) { result += e; }"
8748 "}"
8749 "result;");
8750 CHECK_EQ(v8_str("ggggg"), result);
8751}
8752
8753
Andrei Popescu402d9372010-02-26 13:31:12 +00008754THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
8755 int interceptor_call_count = 0;
8756 v8::HandleScope scope;
8757 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8758 v8::Handle<v8::FunctionTemplate> method_templ =
8759 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
8760 v8_str("method_data"),
8761 v8::Handle<v8::Signature>());
8762 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8763 proto_templ->Set(v8_str("method"), method_templ);
8764 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8765 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8766 NULL, NULL, NULL, NULL,
8767 v8::External::Wrap(&interceptor_call_count));
8768 LocalContext context;
8769 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8770 GenerateSomeGarbage();
8771 context->Global()->Set(v8_str("o"), fun->NewInstance());
8772 v8::Handle<Value> value = CompileRun(
8773 "var result = 0;"
8774 "for (var i = 0; i < 100; i++) {"
8775 " result = o.method(41);"
8776 "}");
8777 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
8778 CHECK_EQ(100, interceptor_call_count);
8779}
8780
8781THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
8782 int interceptor_call_count = 0;
8783 v8::HandleScope scope;
8784 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8785 v8::Handle<v8::FunctionTemplate> method_templ =
8786 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8787 v8_str("method_data"),
8788 v8::Signature::New(fun_templ));
8789 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8790 proto_templ->Set(v8_str("method"), method_templ);
8791 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8792 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8793 NULL, NULL, NULL, NULL,
8794 v8::External::Wrap(&interceptor_call_count));
8795 LocalContext context;
8796 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8797 GenerateSomeGarbage();
8798 context->Global()->Set(v8_str("o"), fun->NewInstance());
8799 v8::Handle<Value> value = CompileRun(
8800 "o.foo = 17;"
8801 "var receiver = {};"
8802 "receiver.__proto__ = o;"
8803 "var result = 0;"
8804 "for (var i = 0; i < 100; i++) {"
8805 " result = receiver.method(41);"
8806 "}");
8807 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
8808 CHECK_EQ(100, interceptor_call_count);
8809}
8810
8811THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
8812 int interceptor_call_count = 0;
8813 v8::HandleScope scope;
8814 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8815 v8::Handle<v8::FunctionTemplate> method_templ =
8816 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8817 v8_str("method_data"),
8818 v8::Signature::New(fun_templ));
8819 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8820 proto_templ->Set(v8_str("method"), method_templ);
8821 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8822 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8823 NULL, NULL, NULL, NULL,
8824 v8::External::Wrap(&interceptor_call_count));
8825 LocalContext context;
8826 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8827 GenerateSomeGarbage();
8828 context->Global()->Set(v8_str("o"), fun->NewInstance());
8829 v8::Handle<Value> value = CompileRun(
8830 "o.foo = 17;"
8831 "var receiver = {};"
8832 "receiver.__proto__ = o;"
8833 "var result = 0;"
8834 "var saved_result = 0;"
8835 "for (var i = 0; i < 100; i++) {"
8836 " result = receiver.method(41);"
8837 " if (i == 50) {"
8838 " saved_result = result;"
8839 " receiver = {method: function(x) { return x - 1 }};"
8840 " }"
8841 "}");
8842 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
8843 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8844 CHECK_GE(interceptor_call_count, 50);
8845}
8846
8847THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
8848 int interceptor_call_count = 0;
8849 v8::HandleScope scope;
8850 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8851 v8::Handle<v8::FunctionTemplate> method_templ =
8852 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8853 v8_str("method_data"),
8854 v8::Signature::New(fun_templ));
8855 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8856 proto_templ->Set(v8_str("method"), method_templ);
8857 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8858 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8859 NULL, NULL, NULL, NULL,
8860 v8::External::Wrap(&interceptor_call_count));
8861 LocalContext context;
8862 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8863 GenerateSomeGarbage();
8864 context->Global()->Set(v8_str("o"), fun->NewInstance());
8865 v8::Handle<Value> value = CompileRun(
8866 "o.foo = 17;"
8867 "var receiver = {};"
8868 "receiver.__proto__ = o;"
8869 "var result = 0;"
8870 "var saved_result = 0;"
8871 "for (var i = 0; i < 100; i++) {"
8872 " result = receiver.method(41);"
8873 " if (i == 50) {"
8874 " saved_result = result;"
8875 " o.method = function(x) { return x - 1 };"
8876 " }"
8877 "}");
8878 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
8879 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8880 CHECK_GE(interceptor_call_count, 50);
8881}
8882
Steve Block6ded16b2010-05-10 14:33:55 +01008883THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
8884 int interceptor_call_count = 0;
8885 v8::HandleScope scope;
8886 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8887 v8::Handle<v8::FunctionTemplate> method_templ =
8888 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8889 v8_str("method_data"),
8890 v8::Signature::New(fun_templ));
8891 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8892 proto_templ->Set(v8_str("method"), method_templ);
8893 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8894 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8895 NULL, NULL, NULL, NULL,
8896 v8::External::Wrap(&interceptor_call_count));
8897 LocalContext context;
8898 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8899 GenerateSomeGarbage();
8900 context->Global()->Set(v8_str("o"), fun->NewInstance());
8901 v8::TryCatch try_catch;
8902 v8::Handle<Value> value = CompileRun(
8903 "o.foo = 17;"
8904 "var receiver = {};"
8905 "receiver.__proto__ = o;"
8906 "var result = 0;"
8907 "var saved_result = 0;"
8908 "for (var i = 0; i < 100; i++) {"
8909 " result = receiver.method(41);"
8910 " if (i == 50) {"
8911 " saved_result = result;"
8912 " receiver = 333;"
8913 " }"
8914 "}");
8915 CHECK(try_catch.HasCaught());
8916 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
8917 try_catch.Exception()->ToString());
8918 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8919 CHECK_GE(interceptor_call_count, 50);
8920}
8921
Andrei Popescu402d9372010-02-26 13:31:12 +00008922THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
8923 int interceptor_call_count = 0;
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 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8934 NULL, NULL, NULL, NULL,
8935 v8::External::Wrap(&interceptor_call_count));
8936 LocalContext context;
8937 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8938 GenerateSomeGarbage();
8939 context->Global()->Set(v8_str("o"), fun->NewInstance());
8940 v8::TryCatch try_catch;
8941 v8::Handle<Value> value = CompileRun(
8942 "o.foo = 17;"
8943 "var receiver = {};"
8944 "receiver.__proto__ = o;"
8945 "var result = 0;"
8946 "var saved_result = 0;"
8947 "for (var i = 0; i < 100; i++) {"
8948 " result = receiver.method(41);"
8949 " if (i == 50) {"
8950 " saved_result = result;"
8951 " receiver = {method: receiver.method};"
8952 " }"
8953 "}");
8954 CHECK(try_catch.HasCaught());
8955 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
8956 try_catch.Exception()->ToString());
8957 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8958 CHECK_GE(interceptor_call_count, 50);
8959}
8960
8961THREADED_TEST(CallICFastApi_TrivialSignature) {
8962 v8::HandleScope scope;
8963 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8964 v8::Handle<v8::FunctionTemplate> method_templ =
8965 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
8966 v8_str("method_data"),
8967 v8::Handle<v8::Signature>());
8968 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8969 proto_templ->Set(v8_str("method"), method_templ);
8970 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8971 LocalContext context;
8972 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8973 GenerateSomeGarbage();
8974 context->Global()->Set(v8_str("o"), fun->NewInstance());
8975 v8::Handle<Value> value = CompileRun(
8976 "var result = 0;"
8977 "for (var i = 0; i < 100; i++) {"
8978 " result = o.method(41);"
8979 "}");
8980
8981 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
8982}
8983
8984THREADED_TEST(CallICFastApi_SimpleSignature) {
8985 v8::HandleScope scope;
8986 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8987 v8::Handle<v8::FunctionTemplate> method_templ =
8988 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8989 v8_str("method_data"),
8990 v8::Signature::New(fun_templ));
8991 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8992 proto_templ->Set(v8_str("method"), method_templ);
8993 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8994 LocalContext context;
8995 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8996 GenerateSomeGarbage();
8997 context->Global()->Set(v8_str("o"), fun->NewInstance());
8998 v8::Handle<Value> value = CompileRun(
8999 "o.foo = 17;"
9000 "var receiver = {};"
9001 "receiver.__proto__ = o;"
9002 "var result = 0;"
9003 "for (var i = 0; i < 100; i++) {"
9004 " result = receiver.method(41);"
9005 "}");
9006
9007 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9008}
9009
Steve Block6ded16b2010-05-10 14:33:55 +01009010THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) {
Andrei Popescu402d9372010-02-26 13:31:12 +00009011 v8::HandleScope scope;
9012 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9013 v8::Handle<v8::FunctionTemplate> method_templ =
9014 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9015 v8_str("method_data"),
9016 v8::Signature::New(fun_templ));
9017 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9018 proto_templ->Set(v8_str("method"), method_templ);
9019 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9020 LocalContext context;
9021 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9022 GenerateSomeGarbage();
9023 context->Global()->Set(v8_str("o"), fun->NewInstance());
9024 v8::Handle<Value> value = CompileRun(
9025 "o.foo = 17;"
9026 "var receiver = {};"
9027 "receiver.__proto__ = o;"
9028 "var result = 0;"
9029 "var saved_result = 0;"
9030 "for (var i = 0; i < 100; i++) {"
9031 " result = receiver.method(41);"
9032 " if (i == 50) {"
9033 " saved_result = result;"
9034 " receiver = {method: function(x) { return x - 1 }};"
9035 " }"
9036 "}");
9037 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
9038 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9039}
9040
Steve Block6ded16b2010-05-10 14:33:55 +01009041THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) {
9042 v8::HandleScope scope;
9043 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9044 v8::Handle<v8::FunctionTemplate> method_templ =
9045 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9046 v8_str("method_data"),
9047 v8::Signature::New(fun_templ));
9048 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9049 proto_templ->Set(v8_str("method"), method_templ);
9050 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9051 LocalContext context;
9052 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9053 GenerateSomeGarbage();
9054 context->Global()->Set(v8_str("o"), fun->NewInstance());
9055 v8::TryCatch try_catch;
9056 v8::Handle<Value> value = CompileRun(
9057 "o.foo = 17;"
9058 "var receiver = {};"
9059 "receiver.__proto__ = o;"
9060 "var result = 0;"
9061 "var saved_result = 0;"
9062 "for (var i = 0; i < 100; i++) {"
9063 " result = receiver.method(41);"
9064 " if (i == 50) {"
9065 " saved_result = result;"
9066 " receiver = 333;"
9067 " }"
9068 "}");
9069 CHECK(try_catch.HasCaught());
9070 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
9071 try_catch.Exception()->ToString());
9072 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9073}
9074
Leon Clarke4515c472010-02-03 11:58:03 +00009075
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009076v8::Handle<Value> keyed_call_ic_function;
9077
9078static v8::Handle<Value> InterceptorKeyedCallICGetter(
9079 Local<String> name, const AccessorInfo& info) {
9080 ApiTestFuzzer::Fuzz();
9081 if (v8_str("x")->Equals(name)) {
9082 return keyed_call_ic_function;
9083 }
9084 return v8::Handle<Value>();
9085}
9086
9087
9088// Test the case when we stored cacheable lookup into
9089// a stub, but the function name changed (to another cacheable function).
9090THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
9091 v8::HandleScope scope;
9092 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9093 templ->SetNamedPropertyHandler(NoBlockGetterX);
9094 LocalContext context;
9095 context->Global()->Set(v8_str("o"), templ->NewInstance());
9096 v8::Handle<Value> value = CompileRun(
9097 "proto = new Object();"
9098 "proto.y = function(x) { return x + 1; };"
9099 "proto.z = function(x) { return x - 1; };"
9100 "o.__proto__ = proto;"
9101 "var result = 0;"
9102 "var method = 'y';"
9103 "for (var i = 0; i < 10; i++) {"
9104 " if (i == 5) { method = 'z'; };"
9105 " result += o[method](41);"
9106 "}");
9107 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9108}
9109
9110
9111// Test the case when we stored cacheable lookup into
9112// a stub, but the function name changed (and the new function is present
9113// both before and after the interceptor in the prototype chain).
9114THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
9115 v8::HandleScope scope;
9116 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9117 templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
9118 LocalContext context;
9119 context->Global()->Set(v8_str("proto1"), templ->NewInstance());
9120 keyed_call_ic_function =
9121 v8_compile("function f(x) { return x - 1; }; f")->Run();
9122 v8::Handle<Value> value = CompileRun(
9123 "o = new Object();"
9124 "proto2 = new Object();"
9125 "o.y = function(x) { return x + 1; };"
9126 "proto2.y = function(x) { return x + 2; };"
9127 "o.__proto__ = proto1;"
9128 "proto1.__proto__ = proto2;"
9129 "var result = 0;"
9130 "var method = 'x';"
9131 "for (var i = 0; i < 10; i++) {"
9132 " if (i == 5) { method = 'y'; };"
9133 " result += o[method](41);"
9134 "}");
9135 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9136}
9137
9138
9139// Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
9140// on the global object.
9141THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
9142 v8::HandleScope scope;
9143 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9144 templ->SetNamedPropertyHandler(NoBlockGetterX);
9145 LocalContext context;
9146 context->Global()->Set(v8_str("o"), templ->NewInstance());
9147 v8::Handle<Value> value = CompileRun(
9148 "function inc(x) { return x + 1; };"
9149 "inc(1);"
9150 "function dec(x) { return x - 1; };"
9151 "dec(1);"
9152 "o.__proto__ = this;"
9153 "this.__proto__.x = inc;"
9154 "this.__proto__.y = dec;"
9155 "var result = 0;"
9156 "var method = 'x';"
9157 "for (var i = 0; i < 10; i++) {"
9158 " if (i == 5) { method = 'y'; };"
9159 " result += o[method](41);"
9160 "}");
9161 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9162}
9163
9164
9165// Test the case when actual function to call sits on global object.
9166THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
9167 v8::HandleScope scope;
9168 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9169 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9170 LocalContext context;
9171 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9172
9173 v8::Handle<Value> value = CompileRun(
9174 "function len(x) { return x.length; };"
9175 "o.__proto__ = this;"
9176 "var m = 'parseFloat';"
9177 "var result = 0;"
9178 "for (var i = 0; i < 10; i++) {"
9179 " if (i == 5) {"
9180 " m = 'len';"
9181 " saved_result = result;"
9182 " };"
9183 " result = o[m]('239');"
9184 "}");
9185 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
9186 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9187}
9188
9189// Test the map transition before the interceptor.
9190THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
9191 v8::HandleScope scope;
9192 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9193 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9194 LocalContext context;
9195 context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
9196
9197 v8::Handle<Value> value = CompileRun(
9198 "var o = new Object();"
9199 "o.__proto__ = proto;"
9200 "o.method = function(x) { return x + 1; };"
9201 "var m = 'method';"
9202 "var result = 0;"
9203 "for (var i = 0; i < 10; i++) {"
9204 " if (i == 5) { o.method = function(x) { return x - 1; }; };"
9205 " result += o[m](41);"
9206 "}");
9207 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9208}
9209
9210
9211// Test the map transition after the interceptor.
9212THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
9213 v8::HandleScope scope;
9214 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9215 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9216 LocalContext context;
9217 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9218
9219 v8::Handle<Value> value = CompileRun(
9220 "var proto = new Object();"
9221 "o.__proto__ = proto;"
9222 "proto.method = function(x) { return x + 1; };"
9223 "var m = 'method';"
9224 "var result = 0;"
9225 "for (var i = 0; i < 10; i++) {"
9226 " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
9227 " result += o[m](41);"
9228 "}");
9229 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9230}
9231
9232
Steve Blocka7e24c12009-10-30 11:49:00 +00009233static int interceptor_call_count = 0;
9234
9235static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
9236 const AccessorInfo& info) {
9237 ApiTestFuzzer::Fuzz();
9238 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
9239 return call_ic_function2;
9240 }
9241 return v8::Handle<Value>();
9242}
9243
9244
9245// This test should hit load and call ICs for the interceptor case.
9246// Once in a while, the interceptor will reply that a property was not
9247// found in which case we should get a reference error.
9248THREADED_TEST(InterceptorICReferenceErrors) {
9249 v8::HandleScope scope;
9250 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9251 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
9252 LocalContext context(0, templ, v8::Handle<Value>());
9253 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
9254 v8::Handle<Value> value = CompileRun(
9255 "function f() {"
9256 " for (var i = 0; i < 1000; i++) {"
9257 " try { x; } catch(e) { return true; }"
9258 " }"
9259 " return false;"
9260 "};"
9261 "f();");
9262 CHECK_EQ(true, value->BooleanValue());
9263 interceptor_call_count = 0;
9264 value = CompileRun(
9265 "function g() {"
9266 " for (var i = 0; i < 1000; i++) {"
9267 " try { x(42); } catch(e) { return true; }"
9268 " }"
9269 " return false;"
9270 "};"
9271 "g();");
9272 CHECK_EQ(true, value->BooleanValue());
9273}
9274
9275
9276static int interceptor_ic_exception_get_count = 0;
9277
9278static v8::Handle<Value> InterceptorICExceptionGetter(
9279 Local<String> name,
9280 const AccessorInfo& info) {
9281 ApiTestFuzzer::Fuzz();
9282 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
9283 return call_ic_function3;
9284 }
9285 if (interceptor_ic_exception_get_count == 20) {
9286 return v8::ThrowException(v8_num(42));
9287 }
9288 // Do not handle get for properties other than x.
9289 return v8::Handle<Value>();
9290}
9291
9292// Test interceptor load/call IC where the interceptor throws an
9293// exception once in a while.
9294THREADED_TEST(InterceptorICGetterExceptions) {
9295 interceptor_ic_exception_get_count = 0;
9296 v8::HandleScope scope;
9297 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9298 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
9299 LocalContext context(0, templ, v8::Handle<Value>());
9300 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
9301 v8::Handle<Value> value = CompileRun(
9302 "function f() {"
9303 " for (var i = 0; i < 100; i++) {"
9304 " try { x; } catch(e) { return true; }"
9305 " }"
9306 " return false;"
9307 "};"
9308 "f();");
9309 CHECK_EQ(true, value->BooleanValue());
9310 interceptor_ic_exception_get_count = 0;
9311 value = CompileRun(
9312 "function f() {"
9313 " for (var i = 0; i < 100; i++) {"
9314 " try { x(42); } catch(e) { return true; }"
9315 " }"
9316 " return false;"
9317 "};"
9318 "f();");
9319 CHECK_EQ(true, value->BooleanValue());
9320}
9321
9322
9323static int interceptor_ic_exception_set_count = 0;
9324
9325static v8::Handle<Value> InterceptorICExceptionSetter(
9326 Local<String> key, Local<Value> value, const AccessorInfo&) {
9327 ApiTestFuzzer::Fuzz();
9328 if (++interceptor_ic_exception_set_count > 20) {
9329 return v8::ThrowException(v8_num(42));
9330 }
9331 // Do not actually handle setting.
9332 return v8::Handle<Value>();
9333}
9334
9335// Test interceptor store IC where the interceptor throws an exception
9336// once in a while.
9337THREADED_TEST(InterceptorICSetterExceptions) {
9338 interceptor_ic_exception_set_count = 0;
9339 v8::HandleScope scope;
9340 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9341 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
9342 LocalContext context(0, templ, v8::Handle<Value>());
9343 v8::Handle<Value> value = CompileRun(
9344 "function f() {"
9345 " for (var i = 0; i < 100; i++) {"
9346 " try { x = 42; } catch(e) { return true; }"
9347 " }"
9348 " return false;"
9349 "};"
9350 "f();");
9351 CHECK_EQ(true, value->BooleanValue());
9352}
9353
9354
9355// Test that we ignore null interceptors.
9356THREADED_TEST(NullNamedInterceptor) {
9357 v8::HandleScope scope;
9358 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9359 templ->SetNamedPropertyHandler(0);
9360 LocalContext context;
9361 templ->Set("x", v8_num(42));
9362 v8::Handle<v8::Object> obj = templ->NewInstance();
9363 context->Global()->Set(v8_str("obj"), obj);
9364 v8::Handle<Value> value = CompileRun("obj.x");
9365 CHECK(value->IsInt32());
9366 CHECK_EQ(42, value->Int32Value());
9367}
9368
9369
9370// Test that we ignore null interceptors.
9371THREADED_TEST(NullIndexedInterceptor) {
9372 v8::HandleScope scope;
9373 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9374 templ->SetIndexedPropertyHandler(0);
9375 LocalContext context;
9376 templ->Set("42", v8_num(42));
9377 v8::Handle<v8::Object> obj = templ->NewInstance();
9378 context->Global()->Set(v8_str("obj"), obj);
9379 v8::Handle<Value> value = CompileRun("obj[42]");
9380 CHECK(value->IsInt32());
9381 CHECK_EQ(42, value->Int32Value());
9382}
9383
9384
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009385THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
9386 v8::HandleScope scope;
9387 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9388 templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9389 LocalContext env;
9390 env->Global()->Set(v8_str("obj"),
9391 templ->GetFunction()->NewInstance());
9392 ExpectTrue("obj.x === 42");
9393 ExpectTrue("!obj.propertyIsEnumerable('x')");
9394}
9395
9396
Ben Murdoch8b112d22011-06-08 16:22:53 +01009397static Handle<Value> ThrowingGetter(Local<String> name,
9398 const AccessorInfo& info) {
9399 ApiTestFuzzer::Fuzz();
9400 ThrowException(Handle<Value>());
9401 return Undefined();
9402}
9403
9404
9405THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
9406 HandleScope scope;
9407 LocalContext context;
9408
9409 Local<FunctionTemplate> templ = FunctionTemplate::New();
9410 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
9411 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
9412
9413 Local<Object> instance = templ->GetFunction()->NewInstance();
9414
9415 Local<Object> another = Object::New();
9416 another->SetPrototype(instance);
9417
9418 Local<Object> with_js_getter = CompileRun(
9419 "o = {};\n"
9420 "o.__defineGetter__('f', function() { throw undefined; });\n"
9421 "o\n").As<Object>();
9422 CHECK(!with_js_getter.IsEmpty());
9423
9424 TryCatch try_catch;
9425
9426 Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
9427 CHECK(try_catch.HasCaught());
9428 try_catch.Reset();
9429 CHECK(result.IsEmpty());
9430
9431 result = another->GetRealNamedProperty(v8_str("f"));
9432 CHECK(try_catch.HasCaught());
9433 try_catch.Reset();
9434 CHECK(result.IsEmpty());
9435
9436 result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
9437 CHECK(try_catch.HasCaught());
9438 try_catch.Reset();
9439 CHECK(result.IsEmpty());
9440
9441 result = another->Get(v8_str("f"));
9442 CHECK(try_catch.HasCaught());
9443 try_catch.Reset();
9444 CHECK(result.IsEmpty());
9445
9446 result = with_js_getter->GetRealNamedProperty(v8_str("f"));
9447 CHECK(try_catch.HasCaught());
9448 try_catch.Reset();
9449 CHECK(result.IsEmpty());
9450
9451 result = with_js_getter->Get(v8_str("f"));
9452 CHECK(try_catch.HasCaught());
9453 try_catch.Reset();
9454 CHECK(result.IsEmpty());
9455}
9456
9457
9458static Handle<Value> ThrowingCallbackWithTryCatch(const Arguments& args) {
9459 TryCatch try_catch;
9460 // Verboseness is important: it triggers message delivery which can call into
9461 // external code.
9462 try_catch.SetVerbose(true);
9463 CompileRun("throw 'from JS';");
9464 CHECK(try_catch.HasCaught());
9465 CHECK(!i::Isolate::Current()->has_pending_exception());
9466 CHECK(!i::Isolate::Current()->has_scheduled_exception());
9467 return Undefined();
9468}
9469
9470
9471static int call_depth;
9472
9473
9474static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
9475 TryCatch try_catch;
9476}
9477
9478
9479static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
9480 if (--call_depth) CompileRun("throw 'ThrowInJS';");
9481}
9482
9483
9484static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
9485 if (--call_depth) ThrowException(v8_str("ThrowViaApi"));
9486}
9487
9488
9489static void WebKitLike(Handle<Message> message, Handle<Value> data) {
9490 Handle<String> errorMessageString = message->Get();
9491 CHECK(!errorMessageString.IsEmpty());
9492 message->GetStackTrace();
9493 message->GetScriptResourceName();
9494}
9495
9496THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
9497 HandleScope scope;
9498 LocalContext context;
9499
9500 Local<Function> func =
9501 FunctionTemplate::New(ThrowingCallbackWithTryCatch)->GetFunction();
9502 context->Global()->Set(v8_str("func"), func);
9503
9504 MessageCallback callbacks[] =
9505 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
9506 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
9507 MessageCallback callback = callbacks[i];
9508 if (callback != NULL) {
9509 V8::AddMessageListener(callback);
9510 }
Ben Murdoch257744e2011-11-30 15:57:28 +00009511 // Some small number to control number of times message handler should
9512 // throw an exception.
Ben Murdoch8b112d22011-06-08 16:22:53 +01009513 call_depth = 5;
9514 ExpectFalse(
9515 "var thrown = false;\n"
9516 "try { func(); } catch(e) { thrown = true; }\n"
9517 "thrown\n");
9518 if (callback != NULL) {
9519 V8::RemoveMessageListeners(callback);
9520 }
9521 }
9522}
9523
9524
Steve Blocka7e24c12009-10-30 11:49:00 +00009525static v8::Handle<Value> ParentGetter(Local<String> name,
9526 const AccessorInfo& info) {
9527 ApiTestFuzzer::Fuzz();
9528 return v8_num(1);
9529}
9530
9531
9532static v8::Handle<Value> ChildGetter(Local<String> name,
9533 const AccessorInfo& info) {
9534 ApiTestFuzzer::Fuzz();
9535 return v8_num(42);
9536}
9537
9538
9539THREADED_TEST(Overriding) {
9540 v8::HandleScope scope;
9541 LocalContext context;
9542
9543 // Parent template.
9544 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
9545 Local<ObjectTemplate> parent_instance_templ =
9546 parent_templ->InstanceTemplate();
9547 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
9548
9549 // Template that inherits from the parent template.
9550 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
9551 Local<ObjectTemplate> child_instance_templ =
9552 child_templ->InstanceTemplate();
9553 child_templ->Inherit(parent_templ);
9554 // Override 'f'. The child version of 'f' should get called for child
9555 // instances.
9556 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
9557 // Add 'g' twice. The 'g' added last should get called for instances.
9558 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
9559 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
9560
9561 // Add 'h' as an accessor to the proto template with ReadOnly attributes
9562 // so 'h' can be shadowed on the instance object.
9563 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
9564 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
9565 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
9566
9567 // Add 'i' as an accessor to the instance template with ReadOnly attributes
9568 // but the attribute does not have effect because it is duplicated with
9569 // NULL setter.
9570 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
9571 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
9572
9573
9574
9575 // Instantiate the child template.
9576 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
9577
9578 // Check that the child function overrides the parent one.
9579 context->Global()->Set(v8_str("o"), instance);
9580 Local<Value> value = v8_compile("o.f")->Run();
9581 // Check that the 'g' that was added last is hit.
9582 CHECK_EQ(42, value->Int32Value());
9583 value = v8_compile("o.g")->Run();
9584 CHECK_EQ(42, value->Int32Value());
9585
9586 // Check 'h' can be shadowed.
9587 value = v8_compile("o.h = 3; o.h")->Run();
9588 CHECK_EQ(3, value->Int32Value());
9589
9590 // Check 'i' is cannot be shadowed or changed.
9591 value = v8_compile("o.i = 3; o.i")->Run();
9592 CHECK_EQ(42, value->Int32Value());
9593}
9594
9595
9596static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
9597 ApiTestFuzzer::Fuzz();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009598 return v8::Boolean::New(args.IsConstructCall());
Steve Blocka7e24c12009-10-30 11:49:00 +00009599}
9600
9601
9602THREADED_TEST(IsConstructCall) {
9603 v8::HandleScope scope;
9604
9605 // Function template with call handler.
9606 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9607 templ->SetCallHandler(IsConstructHandler);
9608
9609 LocalContext context;
9610
9611 context->Global()->Set(v8_str("f"), templ->GetFunction());
9612 Local<Value> value = v8_compile("f()")->Run();
9613 CHECK(!value->BooleanValue());
9614 value = v8_compile("new f()")->Run();
9615 CHECK(value->BooleanValue());
9616}
9617
9618
9619THREADED_TEST(ObjectProtoToString) {
9620 v8::HandleScope scope;
9621 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9622 templ->SetClassName(v8_str("MyClass"));
9623
9624 LocalContext context;
9625
9626 Local<String> customized_tostring = v8_str("customized toString");
9627
9628 // Replace Object.prototype.toString
9629 v8_compile("Object.prototype.toString = function() {"
9630 " return 'customized toString';"
9631 "}")->Run();
9632
9633 // Normal ToString call should call replaced Object.prototype.toString
9634 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
9635 Local<String> value = instance->ToString();
9636 CHECK(value->IsString() && value->Equals(customized_tostring));
9637
9638 // ObjectProtoToString should not call replace toString function.
9639 value = instance->ObjectProtoToString();
9640 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
9641
9642 // Check global
9643 value = context->Global()->ObjectProtoToString();
9644 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
9645
9646 // Check ordinary object
9647 Local<Value> object = v8_compile("new Object()")->Run();
Steve Block6ded16b2010-05-10 14:33:55 +01009648 value = object.As<v8::Object>()->ObjectProtoToString();
Steve Blocka7e24c12009-10-30 11:49:00 +00009649 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
9650}
9651
9652
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08009653THREADED_TEST(ObjectGetConstructorName) {
9654 v8::HandleScope scope;
9655 LocalContext context;
9656 v8_compile("function Parent() {};"
9657 "function Child() {};"
9658 "Child.prototype = new Parent();"
9659 "var outer = { inner: function() { } };"
9660 "var p = new Parent();"
9661 "var c = new Child();"
9662 "var x = new outer.inner();")->Run();
9663
9664 Local<v8::Value> p = context->Global()->Get(v8_str("p"));
9665 CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
9666 v8_str("Parent")));
9667
9668 Local<v8::Value> c = context->Global()->Get(v8_str("c"));
9669 CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
9670 v8_str("Child")));
9671
9672 Local<v8::Value> x = context->Global()->Get(v8_str("x"));
9673 CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
9674 v8_str("outer.inner")));
9675}
9676
9677
Steve Blocka7e24c12009-10-30 11:49:00 +00009678bool ApiTestFuzzer::fuzzing_ = false;
Steve Block8defd9f2010-07-08 12:39:36 +01009679i::Semaphore* ApiTestFuzzer::all_tests_done_=
9680 i::OS::CreateSemaphore(0);
Steve Blocka7e24c12009-10-30 11:49:00 +00009681int ApiTestFuzzer::active_tests_;
9682int ApiTestFuzzer::tests_being_run_;
9683int ApiTestFuzzer::current_;
9684
9685
9686// We are in a callback and want to switch to another thread (if we
9687// are currently running the thread fuzzing test).
9688void ApiTestFuzzer::Fuzz() {
9689 if (!fuzzing_) return;
9690 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
9691 test->ContextSwitch();
9692}
9693
9694
9695// Let the next thread go. Since it is also waiting on the V8 lock it may
9696// not start immediately.
9697bool ApiTestFuzzer::NextThread() {
9698 int test_position = GetNextTestNumber();
Steve Blockd0582a62009-12-15 09:54:21 +00009699 const char* test_name = RegisterThreadedTest::nth(current_)->name();
Steve Blocka7e24c12009-10-30 11:49:00 +00009700 if (test_position == current_) {
Steve Blockd0582a62009-12-15 09:54:21 +00009701 if (kLogThreading)
9702 printf("Stay with %s\n", test_name);
Steve Blocka7e24c12009-10-30 11:49:00 +00009703 return false;
9704 }
Steve Blockd0582a62009-12-15 09:54:21 +00009705 if (kLogThreading) {
9706 printf("Switch from %s to %s\n",
9707 test_name,
9708 RegisterThreadedTest::nth(test_position)->name());
9709 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009710 current_ = test_position;
9711 RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
9712 return true;
9713}
9714
9715
9716void ApiTestFuzzer::Run() {
9717 // When it is our turn...
9718 gate_->Wait();
9719 {
9720 // ... get the V8 lock and start running the test.
9721 v8::Locker locker;
9722 CallTest();
9723 }
9724 // This test finished.
9725 active_ = false;
9726 active_tests_--;
9727 // If it was the last then signal that fact.
9728 if (active_tests_ == 0) {
9729 all_tests_done_->Signal();
9730 } else {
9731 // Otherwise select a new test and start that.
9732 NextThread();
9733 }
9734}
9735
9736
9737static unsigned linear_congruential_generator;
9738
9739
9740void ApiTestFuzzer::Setup(PartOfTest part) {
9741 linear_congruential_generator = i::FLAG_testing_prng_seed;
9742 fuzzing_ = true;
Ben Murdoch257744e2011-11-30 15:57:28 +00009743 int count = RegisterThreadedTest::count();
9744 int start = count * part / (LAST_PART + 1);
9745 int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
9746 active_tests_ = tests_being_run_ = end - start + 1;
Steve Blocka7e24c12009-10-30 11:49:00 +00009747 for (int i = 0; i < tests_being_run_; i++) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009748 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
Steve Blocka7e24c12009-10-30 11:49:00 +00009749 }
9750 for (int i = 0; i < active_tests_; i++) {
9751 RegisterThreadedTest::nth(i)->fuzzer_->Start();
9752 }
9753}
9754
9755
9756static void CallTestNumber(int test_number) {
9757 (RegisterThreadedTest::nth(test_number)->callback())();
9758}
9759
9760
9761void ApiTestFuzzer::RunAllTests() {
9762 // Set off the first test.
9763 current_ = -1;
9764 NextThread();
9765 // Wait till they are all done.
9766 all_tests_done_->Wait();
9767}
9768
9769
9770int ApiTestFuzzer::GetNextTestNumber() {
9771 int next_test;
9772 do {
9773 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
9774 linear_congruential_generator *= 1664525u;
9775 linear_congruential_generator += 1013904223u;
9776 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
9777 return next_test;
9778}
9779
9780
9781void ApiTestFuzzer::ContextSwitch() {
9782 // If the new thread is the same as the current thread there is nothing to do.
9783 if (NextThread()) {
9784 // Now it can start.
9785 v8::Unlocker unlocker;
9786 // Wait till someone starts us again.
9787 gate_->Wait();
9788 // And we're off.
9789 }
9790}
9791
9792
9793void ApiTestFuzzer::TearDown() {
9794 fuzzing_ = false;
9795 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
9796 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
9797 if (fuzzer != NULL) fuzzer->Join();
9798 }
9799}
9800
9801
9802// Lets not be needlessly self-referential.
9803TEST(Threading) {
9804 ApiTestFuzzer::Setup(ApiTestFuzzer::FIRST_PART);
9805 ApiTestFuzzer::RunAllTests();
9806 ApiTestFuzzer::TearDown();
9807}
9808
9809TEST(Threading2) {
9810 ApiTestFuzzer::Setup(ApiTestFuzzer::SECOND_PART);
9811 ApiTestFuzzer::RunAllTests();
9812 ApiTestFuzzer::TearDown();
9813}
9814
Ben Murdoch257744e2011-11-30 15:57:28 +00009815TEST(Threading3) {
9816 ApiTestFuzzer::Setup(ApiTestFuzzer::THIRD_PART);
9817 ApiTestFuzzer::RunAllTests();
9818 ApiTestFuzzer::TearDown();
9819}
9820
9821TEST(Threading4) {
9822 ApiTestFuzzer::Setup(ApiTestFuzzer::FOURTH_PART);
9823 ApiTestFuzzer::RunAllTests();
9824 ApiTestFuzzer::TearDown();
9825}
Steve Blocka7e24c12009-10-30 11:49:00 +00009826
9827void ApiTestFuzzer::CallTest() {
Steve Blockd0582a62009-12-15 09:54:21 +00009828 if (kLogThreading)
9829 printf("Start test %d\n", test_number_);
Steve Blocka7e24c12009-10-30 11:49:00 +00009830 CallTestNumber(test_number_);
Steve Blockd0582a62009-12-15 09:54:21 +00009831 if (kLogThreading)
9832 printf("End test %d\n", test_number_);
Steve Blocka7e24c12009-10-30 11:49:00 +00009833}
9834
9835
9836static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
9837 CHECK(v8::Locker::IsLocked());
9838 ApiTestFuzzer::Fuzz();
9839 v8::Unlocker unlocker;
9840 const char* code = "throw 7;";
9841 {
9842 v8::Locker nested_locker;
9843 v8::HandleScope scope;
9844 v8::Handle<Value> exception;
9845 { v8::TryCatch try_catch;
9846 v8::Handle<Value> value = CompileRun(code);
9847 CHECK(value.IsEmpty());
9848 CHECK(try_catch.HasCaught());
9849 // Make sure to wrap the exception in a new handle because
9850 // the handle returned from the TryCatch is destroyed
9851 // when the TryCatch is destroyed.
9852 exception = Local<Value>::New(try_catch.Exception());
9853 }
9854 return v8::ThrowException(exception);
9855 }
9856}
9857
9858
9859static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
9860 CHECK(v8::Locker::IsLocked());
9861 ApiTestFuzzer::Fuzz();
9862 v8::Unlocker unlocker;
9863 const char* code = "throw 7;";
9864 {
9865 v8::Locker nested_locker;
9866 v8::HandleScope scope;
9867 v8::Handle<Value> value = CompileRun(code);
9868 CHECK(value.IsEmpty());
9869 return v8_str("foo");
9870 }
9871}
9872
9873
9874// These are locking tests that don't need to be run again
9875// as part of the locking aggregation tests.
9876TEST(NestedLockers) {
9877 v8::Locker locker;
9878 CHECK(v8::Locker::IsLocked());
9879 v8::HandleScope scope;
9880 LocalContext env;
9881 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
9882 Local<Function> fun = fun_templ->GetFunction();
9883 env->Global()->Set(v8_str("throw_in_js"), fun);
9884 Local<Script> script = v8_compile("(function () {"
9885 " try {"
9886 " throw_in_js();"
9887 " return 42;"
9888 " } catch (e) {"
9889 " return e * 13;"
9890 " }"
9891 "})();");
9892 CHECK_EQ(91, script->Run()->Int32Value());
9893}
9894
9895
9896// These are locking tests that don't need to be run again
9897// as part of the locking aggregation tests.
9898TEST(NestedLockersNoTryCatch) {
9899 v8::Locker locker;
9900 v8::HandleScope scope;
9901 LocalContext env;
9902 Local<v8::FunctionTemplate> fun_templ =
9903 v8::FunctionTemplate::New(ThrowInJSNoCatch);
9904 Local<Function> fun = fun_templ->GetFunction();
9905 env->Global()->Set(v8_str("throw_in_js"), fun);
9906 Local<Script> script = v8_compile("(function () {"
9907 " try {"
9908 " throw_in_js();"
9909 " return 42;"
9910 " } catch (e) {"
9911 " return e * 13;"
9912 " }"
9913 "})();");
9914 CHECK_EQ(91, script->Run()->Int32Value());
9915}
9916
9917
9918THREADED_TEST(RecursiveLocking) {
9919 v8::Locker locker;
9920 {
9921 v8::Locker locker2;
9922 CHECK(v8::Locker::IsLocked());
9923 }
9924}
9925
9926
9927static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
9928 ApiTestFuzzer::Fuzz();
9929 v8::Unlocker unlocker;
9930 return v8::Undefined();
9931}
9932
9933
9934THREADED_TEST(LockUnlockLock) {
9935 {
9936 v8::Locker locker;
9937 v8::HandleScope scope;
9938 LocalContext env;
9939 Local<v8::FunctionTemplate> fun_templ =
9940 v8::FunctionTemplate::New(UnlockForAMoment);
9941 Local<Function> fun = fun_templ->GetFunction();
9942 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
9943 Local<Script> script = v8_compile("(function () {"
9944 " unlock_for_a_moment();"
9945 " return 42;"
9946 "})();");
9947 CHECK_EQ(42, script->Run()->Int32Value());
9948 }
9949 {
9950 v8::Locker locker;
9951 v8::HandleScope scope;
9952 LocalContext env;
9953 Local<v8::FunctionTemplate> fun_templ =
9954 v8::FunctionTemplate::New(UnlockForAMoment);
9955 Local<Function> fun = fun_templ->GetFunction();
9956 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
9957 Local<Script> script = v8_compile("(function () {"
9958 " unlock_for_a_moment();"
9959 " return 42;"
9960 "})();");
9961 CHECK_EQ(42, script->Run()->Int32Value());
9962 }
9963}
9964
9965
Leon Clarked91b9f72010-01-27 17:25:45 +00009966static int GetGlobalObjectsCount() {
Leon Clarkeeab96aa2010-01-27 16:31:12 +00009967 int count = 0;
Steve Block8defd9f2010-07-08 12:39:36 +01009968 i::HeapIterator it;
Leon Clarked91b9f72010-01-27 17:25:45 +00009969 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
9970 if (object->IsJSGlobalObject()) count++;
9971 return count;
9972}
9973
9974
Ben Murdochf87a2032010-10-22 12:50:53 +01009975static void CheckSurvivingGlobalObjectsCount(int expected) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009976 // We need to collect all garbage twice to be sure that everything
9977 // has been collected. This is because inline caches are cleared in
9978 // the first garbage collection but some of the maps have already
9979 // been marked at that point. Therefore some of the maps are not
9980 // collected until the second garbage collection.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009981 HEAP->global_context_map();
Steve Block44f0eee2011-05-26 01:26:41 +01009982 HEAP->CollectAllGarbage(false);
9983 HEAP->CollectAllGarbage(false);
Leon Clarked91b9f72010-01-27 17:25:45 +00009984 int count = GetGlobalObjectsCount();
Steve Blocka7e24c12009-10-30 11:49:00 +00009985#ifdef DEBUG
Steve Block44f0eee2011-05-26 01:26:41 +01009986 if (count != expected) HEAP->TracePathToGlobal();
Steve Blocka7e24c12009-10-30 11:49:00 +00009987#endif
Ben Murdochf87a2032010-10-22 12:50:53 +01009988 CHECK_EQ(expected, count);
Steve Blocka7e24c12009-10-30 11:49:00 +00009989}
9990
9991
9992TEST(DontLeakGlobalObjects) {
9993 // Regression test for issues 1139850 and 1174891.
9994
9995 v8::V8::Initialize();
9996
Steve Blocka7e24c12009-10-30 11:49:00 +00009997 for (int i = 0; i < 5; i++) {
9998 { v8::HandleScope scope;
9999 LocalContext context;
10000 }
Ben Murdochf87a2032010-10-22 12:50:53 +010010001 CheckSurvivingGlobalObjectsCount(0);
Steve Blocka7e24c12009-10-30 11:49:00 +000010002
10003 { v8::HandleScope scope;
10004 LocalContext context;
10005 v8_compile("Date")->Run();
10006 }
Ben Murdochf87a2032010-10-22 12:50:53 +010010007 CheckSurvivingGlobalObjectsCount(0);
Steve Blocka7e24c12009-10-30 11:49:00 +000010008
10009 { v8::HandleScope scope;
10010 LocalContext context;
10011 v8_compile("/aaa/")->Run();
10012 }
Ben Murdochf87a2032010-10-22 12:50:53 +010010013 CheckSurvivingGlobalObjectsCount(0);
Steve Blocka7e24c12009-10-30 11:49:00 +000010014
10015 { v8::HandleScope scope;
10016 const char* extension_list[] = { "v8/gc" };
10017 v8::ExtensionConfiguration extensions(1, extension_list);
10018 LocalContext context(&extensions);
10019 v8_compile("gc();")->Run();
10020 }
Ben Murdochf87a2032010-10-22 12:50:53 +010010021 CheckSurvivingGlobalObjectsCount(0);
Steve Blocka7e24c12009-10-30 11:49:00 +000010022 }
10023}
10024
10025
10026v8::Persistent<v8::Object> some_object;
10027v8::Persistent<v8::Object> bad_handle;
10028
Kristian Monsen50ef84f2010-07-29 15:18:00 +010010029void NewPersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010030 v8::HandleScope scope;
10031 bad_handle = v8::Persistent<v8::Object>::New(some_object);
Kristian Monsen50ef84f2010-07-29 15:18:00 +010010032 handle.Dispose();
Steve Blocka7e24c12009-10-30 11:49:00 +000010033}
10034
10035
10036THREADED_TEST(NewPersistentHandleFromWeakCallback) {
10037 LocalContext context;
10038
10039 v8::Persistent<v8::Object> handle1, handle2;
10040 {
10041 v8::HandleScope scope;
10042 some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
10043 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
10044 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
10045 }
10046 // Note: order is implementation dependent alas: currently
10047 // global handle nodes are processed by PostGarbageCollectionProcessing
10048 // in reverse allocation order, so if second allocated handle is deleted,
10049 // weak callback of the first handle would be able to 'reallocate' it.
10050 handle1.MakeWeak(NULL, NewPersistentHandleCallback);
10051 handle2.Dispose();
Steve Block44f0eee2011-05-26 01:26:41 +010010052 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +000010053}
10054
10055
10056v8::Persistent<v8::Object> to_be_disposed;
10057
10058void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
10059 to_be_disposed.Dispose();
Steve Block44f0eee2011-05-26 01:26:41 +010010060 HEAP->CollectAllGarbage(false);
Kristian Monsen50ef84f2010-07-29 15:18:00 +010010061 handle.Dispose();
Steve Blocka7e24c12009-10-30 11:49:00 +000010062}
10063
10064
10065THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
10066 LocalContext context;
10067
10068 v8::Persistent<v8::Object> handle1, handle2;
10069 {
10070 v8::HandleScope scope;
10071 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
10072 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
10073 }
10074 handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
10075 to_be_disposed = handle2;
Steve Block44f0eee2011-05-26 01:26:41 +010010076 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +000010077}
10078
Steve Blockd0582a62009-12-15 09:54:21 +000010079void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
10080 handle.Dispose();
10081}
10082
10083void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
10084 v8::HandleScope scope;
10085 v8::Persistent<v8::Object>::New(v8::Object::New());
Kristian Monsen50ef84f2010-07-29 15:18:00 +010010086 handle.Dispose();
Steve Blockd0582a62009-12-15 09:54:21 +000010087}
10088
10089
10090THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
10091 LocalContext context;
10092
10093 v8::Persistent<v8::Object> handle1, handle2, handle3;
10094 {
10095 v8::HandleScope scope;
10096 handle3 = v8::Persistent<v8::Object>::New(v8::Object::New());
10097 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
10098 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
10099 }
10100 handle2.MakeWeak(NULL, DisposingCallback);
10101 handle3.MakeWeak(NULL, HandleCreatingCallback);
Steve Block44f0eee2011-05-26 01:26:41 +010010102 HEAP->CollectAllGarbage(false);
Steve Blockd0582a62009-12-15 09:54:21 +000010103}
10104
Steve Blocka7e24c12009-10-30 11:49:00 +000010105
10106THREADED_TEST(CheckForCrossContextObjectLiterals) {
10107 v8::V8::Initialize();
10108
10109 const int nof = 2;
10110 const char* sources[nof] = {
10111 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
10112 "Object()"
10113 };
10114
10115 for (int i = 0; i < nof; i++) {
10116 const char* source = sources[i];
10117 { v8::HandleScope scope;
10118 LocalContext context;
10119 CompileRun(source);
10120 }
10121 { v8::HandleScope scope;
10122 LocalContext context;
10123 CompileRun(source);
10124 }
10125 }
10126}
10127
10128
10129static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
10130 v8::HandleScope inner;
10131 env->Enter();
10132 v8::Handle<Value> three = v8_num(3);
10133 v8::Handle<Value> value = inner.Close(three);
10134 env->Exit();
10135 return value;
10136}
10137
10138
10139THREADED_TEST(NestedHandleScopeAndContexts) {
10140 v8::HandleScope outer;
10141 v8::Persistent<Context> env = Context::New();
10142 env->Enter();
10143 v8::Handle<Value> value = NestedScope(env);
10144 v8::Handle<String> str = value->ToString();
10145 env->Exit();
10146 env.Dispose();
10147}
10148
10149
10150THREADED_TEST(ExternalAllocatedMemory) {
10151 v8::HandleScope outer;
10152 v8::Persistent<Context> env = Context::New();
10153 const int kSize = 1024*1024;
10154 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
10155 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
10156}
10157
10158
10159THREADED_TEST(DisposeEnteredContext) {
10160 v8::HandleScope scope;
10161 LocalContext outer;
10162 { v8::Persistent<v8::Context> inner = v8::Context::New();
10163 inner->Enter();
10164 inner.Dispose();
10165 inner.Clear();
10166 inner->Exit();
10167 }
10168}
10169
10170
10171// Regression test for issue 54, object templates with internal fields
10172// but no accessors or interceptors did not get their internal field
10173// count set on instances.
10174THREADED_TEST(Regress54) {
10175 v8::HandleScope outer;
10176 LocalContext context;
10177 static v8::Persistent<v8::ObjectTemplate> templ;
10178 if (templ.IsEmpty()) {
10179 v8::HandleScope inner;
10180 v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
10181 local->SetInternalFieldCount(1);
10182 templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
10183 }
10184 v8::Handle<v8::Object> result = templ->NewInstance();
10185 CHECK_EQ(1, result->InternalFieldCount());
10186}
10187
10188
10189// If part of the threaded tests, this test makes ThreadingTest fail
10190// on mac.
10191TEST(CatchStackOverflow) {
10192 v8::HandleScope scope;
10193 LocalContext context;
10194 v8::TryCatch try_catch;
10195 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
10196 "function f() {"
10197 " return f();"
10198 "}"
10199 ""
10200 "f();"));
10201 v8::Handle<v8::Value> result = script->Run();
10202 CHECK(result.IsEmpty());
10203}
10204
10205
10206static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
10207 const char* resource_name,
10208 int line_offset) {
10209 v8::HandleScope scope;
10210 v8::TryCatch try_catch;
10211 v8::Handle<v8::Value> result = script->Run();
10212 CHECK(result.IsEmpty());
10213 CHECK(try_catch.HasCaught());
10214 v8::Handle<v8::Message> message = try_catch.Message();
10215 CHECK(!message.IsEmpty());
10216 CHECK_EQ(10 + line_offset, message->GetLineNumber());
10217 CHECK_EQ(91, message->GetStartPosition());
10218 CHECK_EQ(92, message->GetEndPosition());
10219 CHECK_EQ(2, message->GetStartColumn());
10220 CHECK_EQ(3, message->GetEndColumn());
10221 v8::String::AsciiValue line(message->GetSourceLine());
10222 CHECK_EQ(" throw 'nirk';", *line);
10223 v8::String::AsciiValue name(message->GetScriptResourceName());
10224 CHECK_EQ(resource_name, *name);
10225}
10226
10227
10228THREADED_TEST(TryCatchSourceInfo) {
10229 v8::HandleScope scope;
10230 LocalContext context;
10231 v8::Handle<v8::String> source = v8::String::New(
10232 "function Foo() {\n"
10233 " return Bar();\n"
10234 "}\n"
10235 "\n"
10236 "function Bar() {\n"
10237 " return Baz();\n"
10238 "}\n"
10239 "\n"
10240 "function Baz() {\n"
10241 " throw 'nirk';\n"
10242 "}\n"
10243 "\n"
10244 "Foo();\n");
10245
10246 const char* resource_name;
10247 v8::Handle<v8::Script> script;
10248 resource_name = "test.js";
10249 script = v8::Script::Compile(source, v8::String::New(resource_name));
10250 CheckTryCatchSourceInfo(script, resource_name, 0);
10251
10252 resource_name = "test1.js";
10253 v8::ScriptOrigin origin1(v8::String::New(resource_name));
10254 script = v8::Script::Compile(source, &origin1);
10255 CheckTryCatchSourceInfo(script, resource_name, 0);
10256
10257 resource_name = "test2.js";
10258 v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
10259 script = v8::Script::Compile(source, &origin2);
10260 CheckTryCatchSourceInfo(script, resource_name, 7);
10261}
10262
10263
10264THREADED_TEST(CompilationCache) {
10265 v8::HandleScope scope;
10266 LocalContext context;
10267 v8::Handle<v8::String> source0 = v8::String::New("1234");
10268 v8::Handle<v8::String> source1 = v8::String::New("1234");
10269 v8::Handle<v8::Script> script0 =
10270 v8::Script::Compile(source0, v8::String::New("test.js"));
10271 v8::Handle<v8::Script> script1 =
10272 v8::Script::Compile(source1, v8::String::New("test.js"));
10273 v8::Handle<v8::Script> script2 =
10274 v8::Script::Compile(source0); // different origin
10275 CHECK_EQ(1234, script0->Run()->Int32Value());
10276 CHECK_EQ(1234, script1->Run()->Int32Value());
10277 CHECK_EQ(1234, script2->Run()->Int32Value());
10278}
10279
10280
10281static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
10282 ApiTestFuzzer::Fuzz();
10283 return v8_num(42);
10284}
10285
10286
10287THREADED_TEST(CallbackFunctionName) {
10288 v8::HandleScope scope;
10289 LocalContext context;
10290 Local<ObjectTemplate> t = ObjectTemplate::New();
10291 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
10292 context->Global()->Set(v8_str("obj"), t->NewInstance());
10293 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
10294 CHECK(value->IsString());
10295 v8::String::AsciiValue name(value);
10296 CHECK_EQ("asdf", *name);
10297}
10298
10299
10300THREADED_TEST(DateAccess) {
10301 v8::HandleScope scope;
10302 LocalContext context;
10303 v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
10304 CHECK(date->IsDate());
Steve Block6ded16b2010-05-10 14:33:55 +010010305 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue());
Steve Blocka7e24c12009-10-30 11:49:00 +000010306}
10307
10308
10309void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
Steve Block6ded16b2010-05-10 14:33:55 +010010310 v8::Handle<v8::Object> obj = val.As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +000010311 v8::Handle<v8::Array> props = obj->GetPropertyNames();
10312 CHECK_EQ(elmc, props->Length());
10313 for (int i = 0; i < elmc; i++) {
10314 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
10315 CHECK_EQ(elmv[i], *elm);
10316 }
10317}
10318
10319
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010320void CheckOwnProperties(v8::Handle<v8::Value> val,
10321 int elmc,
10322 const char* elmv[]) {
10323 v8::Handle<v8::Object> obj = val.As<v8::Object>();
10324 v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
10325 CHECK_EQ(elmc, props->Length());
10326 for (int i = 0; i < elmc; i++) {
10327 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
10328 CHECK_EQ(elmv[i], *elm);
10329 }
10330}
10331
10332
Steve Blocka7e24c12009-10-30 11:49:00 +000010333THREADED_TEST(PropertyEnumeration) {
10334 v8::HandleScope scope;
10335 LocalContext context;
10336 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
10337 "var result = [];"
10338 "result[0] = {};"
10339 "result[1] = {a: 1, b: 2};"
10340 "result[2] = [1, 2, 3];"
10341 "var proto = {x: 1, y: 2, z: 3};"
10342 "var x = { __proto__: proto, w: 0, z: 1 };"
10343 "result[3] = x;"
10344 "result;"))->Run();
Steve Block6ded16b2010-05-10 14:33:55 +010010345 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +000010346 CHECK_EQ(4, elms->Length());
10347 int elmc0 = 0;
10348 const char** elmv0 = NULL;
10349 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010350 CheckOwnProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
Steve Blocka7e24c12009-10-30 11:49:00 +000010351 int elmc1 = 2;
10352 const char* elmv1[] = {"a", "b"};
10353 CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010354 CheckOwnProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
Steve Blocka7e24c12009-10-30 11:49:00 +000010355 int elmc2 = 3;
10356 const char* elmv2[] = {"0", "1", "2"};
10357 CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010358 CheckOwnProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
Steve Blocka7e24c12009-10-30 11:49:00 +000010359 int elmc3 = 4;
10360 const char* elmv3[] = {"w", "z", "x", "y"};
10361 CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010362 int elmc4 = 2;
10363 const char* elmv4[] = {"w", "z"};
10364 CheckOwnProperties(elms->Get(v8::Integer::New(3)), elmc4, elmv4);
Steve Blocka7e24c12009-10-30 11:49:00 +000010365}
10366
Steve Block44f0eee2011-05-26 01:26:41 +010010367THREADED_TEST(PropertyEnumeration2) {
10368 v8::HandleScope scope;
10369 LocalContext context;
10370 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
10371 "var result = [];"
10372 "result[0] = {};"
10373 "result[1] = {a: 1, b: 2};"
10374 "result[2] = [1, 2, 3];"
10375 "var proto = {x: 1, y: 2, z: 3};"
10376 "var x = { __proto__: proto, w: 0, z: 1 };"
10377 "result[3] = x;"
10378 "result;"))->Run();
10379 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
10380 CHECK_EQ(4, elms->Length());
10381 int elmc0 = 0;
10382 const char** elmv0 = NULL;
10383 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
10384
10385 v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(0));
10386 v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
10387 CHECK_EQ(0, props->Length());
10388 for (uint32_t i = 0; i < props->Length(); i++) {
10389 printf("p[%d]\n", i);
10390 }
10391}
Steve Blocka7e24c12009-10-30 11:49:00 +000010392
Steve Blocka7e24c12009-10-30 11:49:00 +000010393static bool NamedSetAccessBlocker(Local<v8::Object> obj,
10394 Local<Value> name,
10395 v8::AccessType type,
10396 Local<Value> data) {
10397 return type != v8::ACCESS_SET;
10398}
10399
10400
10401static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
10402 uint32_t key,
10403 v8::AccessType type,
10404 Local<Value> data) {
10405 return type != v8::ACCESS_SET;
10406}
10407
10408
10409THREADED_TEST(DisableAccessChecksWhileConfiguring) {
10410 v8::HandleScope scope;
10411 LocalContext context;
10412 Local<ObjectTemplate> templ = ObjectTemplate::New();
10413 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
10414 IndexedSetAccessBlocker);
10415 templ->Set(v8_str("x"), v8::True());
10416 Local<v8::Object> instance = templ->NewInstance();
10417 context->Global()->Set(v8_str("obj"), instance);
10418 Local<Value> value = CompileRun("obj.x");
10419 CHECK(value->BooleanValue());
10420}
10421
10422
10423static bool NamedGetAccessBlocker(Local<v8::Object> obj,
10424 Local<Value> name,
10425 v8::AccessType type,
10426 Local<Value> data) {
10427 return false;
10428}
10429
10430
10431static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
10432 uint32_t key,
10433 v8::AccessType type,
10434 Local<Value> data) {
10435 return false;
10436}
10437
10438
10439
10440THREADED_TEST(AccessChecksReenabledCorrectly) {
10441 v8::HandleScope scope;
10442 LocalContext context;
10443 Local<ObjectTemplate> templ = ObjectTemplate::New();
10444 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
10445 IndexedGetAccessBlocker);
10446 templ->Set(v8_str("a"), v8_str("a"));
10447 // Add more than 8 (see kMaxFastProperties) properties
10448 // so that the constructor will force copying map.
10449 // Cannot sprintf, gcc complains unsafety.
10450 char buf[4];
10451 for (char i = '0'; i <= '9' ; i++) {
10452 buf[0] = i;
10453 for (char j = '0'; j <= '9'; j++) {
10454 buf[1] = j;
10455 for (char k = '0'; k <= '9'; k++) {
10456 buf[2] = k;
10457 buf[3] = 0;
10458 templ->Set(v8_str(buf), v8::Number::New(k));
10459 }
10460 }
10461 }
10462
10463 Local<v8::Object> instance_1 = templ->NewInstance();
10464 context->Global()->Set(v8_str("obj_1"), instance_1);
10465
10466 Local<Value> value_1 = CompileRun("obj_1.a");
10467 CHECK(value_1->IsUndefined());
10468
10469 Local<v8::Object> instance_2 = templ->NewInstance();
10470 context->Global()->Set(v8_str("obj_2"), instance_2);
10471
10472 Local<Value> value_2 = CompileRun("obj_2.a");
10473 CHECK(value_2->IsUndefined());
10474}
10475
10476
10477// This tests that access check information remains on the global
10478// object template when creating contexts.
10479THREADED_TEST(AccessControlRepeatedContextCreation) {
10480 v8::HandleScope handle_scope;
10481 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
10482 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
10483 IndexedSetAccessBlocker);
10484 i::Handle<i::ObjectTemplateInfo> internal_template =
10485 v8::Utils::OpenHandle(*global_template);
10486 CHECK(!internal_template->constructor()->IsUndefined());
10487 i::Handle<i::FunctionTemplateInfo> constructor(
10488 i::FunctionTemplateInfo::cast(internal_template->constructor()));
10489 CHECK(!constructor->access_check_info()->IsUndefined());
10490 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
10491 CHECK(!constructor->access_check_info()->IsUndefined());
10492}
10493
10494
10495THREADED_TEST(TurnOnAccessCheck) {
10496 v8::HandleScope handle_scope;
10497
10498 // Create an environment with access check to the global object disabled by
10499 // default.
10500 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
10501 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
10502 IndexedGetAccessBlocker,
10503 v8::Handle<v8::Value>(),
10504 false);
10505 v8::Persistent<Context> context = Context::New(NULL, global_template);
10506 Context::Scope context_scope(context);
10507
10508 // Set up a property and a number of functions.
10509 context->Global()->Set(v8_str("a"), v8_num(1));
10510 CompileRun("function f1() {return a;}"
10511 "function f2() {return a;}"
10512 "function g1() {return h();}"
10513 "function g2() {return h();}"
10514 "function h() {return 1;}");
10515 Local<Function> f1 =
10516 Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
10517 Local<Function> f2 =
10518 Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
10519 Local<Function> g1 =
10520 Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
10521 Local<Function> g2 =
10522 Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
10523 Local<Function> h =
10524 Local<Function>::Cast(context->Global()->Get(v8_str("h")));
10525
10526 // Get the global object.
10527 v8::Handle<v8::Object> global = context->Global();
10528
10529 // Call f1 one time and f2 a number of times. This will ensure that f1 still
10530 // uses the runtime system to retreive property a whereas f2 uses global load
10531 // inline cache.
10532 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
10533 for (int i = 0; i < 4; i++) {
10534 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
10535 }
10536
10537 // Same for g1 and g2.
10538 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
10539 for (int i = 0; i < 4; i++) {
10540 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
10541 }
10542
10543 // Detach the global and turn on access check.
10544 context->DetachGlobal();
10545 context->Global()->TurnOnAccessCheck();
10546
10547 // Failing access check to property get results in undefined.
10548 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
10549 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
10550
10551 // Failing access check to function call results in exception.
10552 CHECK(g1->Call(global, 0, NULL).IsEmpty());
10553 CHECK(g2->Call(global, 0, NULL).IsEmpty());
10554
10555 // No failing access check when just returning a constant.
10556 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
10557}
10558
10559
Ben Murdochb0fe1622011-05-05 13:52:32 +010010560v8::Handle<v8::String> a;
10561v8::Handle<v8::String> h;
10562
10563static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
10564 Local<Value> name,
10565 v8::AccessType type,
10566 Local<Value> data) {
10567 return !(name->Equals(a) || name->Equals(h));
10568}
10569
10570
10571THREADED_TEST(TurnOnAccessCheckAndRecompile) {
10572 v8::HandleScope handle_scope;
10573
10574 // Create an environment with access check to the global object disabled by
10575 // default. When the registered access checker will block access to properties
10576 // a and h
10577 a = v8_str("a");
10578 h = v8_str("h");
10579 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
10580 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
10581 IndexedGetAccessBlocker,
10582 v8::Handle<v8::Value>(),
10583 false);
10584 v8::Persistent<Context> context = Context::New(NULL, global_template);
10585 Context::Scope context_scope(context);
10586
10587 // Set up a property and a number of functions.
10588 context->Global()->Set(v8_str("a"), v8_num(1));
10589 static const char* source = "function f1() {return a;}"
10590 "function f2() {return a;}"
10591 "function g1() {return h();}"
10592 "function g2() {return h();}"
10593 "function h() {return 1;}";
10594
10595 CompileRun(source);
10596 Local<Function> f1;
10597 Local<Function> f2;
10598 Local<Function> g1;
10599 Local<Function> g2;
10600 Local<Function> h;
10601 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
10602 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
10603 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
10604 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
10605 h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
10606
10607 // Get the global object.
10608 v8::Handle<v8::Object> global = context->Global();
10609
10610 // Call f1 one time and f2 a number of times. This will ensure that f1 still
10611 // uses the runtime system to retreive property a whereas f2 uses global load
10612 // inline cache.
10613 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
10614 for (int i = 0; i < 4; i++) {
10615 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
10616 }
10617
10618 // Same for g1 and g2.
10619 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
10620 for (int i = 0; i < 4; i++) {
10621 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
10622 }
10623
10624 // Detach the global and turn on access check now blocking access to property
10625 // a and function h.
10626 context->DetachGlobal();
10627 context->Global()->TurnOnAccessCheck();
10628
10629 // Failing access check to property get results in undefined.
10630 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
10631 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
10632
10633 // Failing access check to function call results in exception.
10634 CHECK(g1->Call(global, 0, NULL).IsEmpty());
10635 CHECK(g2->Call(global, 0, NULL).IsEmpty());
10636
10637 // No failing access check when just returning a constant.
10638 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
10639
10640 // Now compile the source again. And get the newly compiled functions, except
10641 // for h for which access is blocked.
10642 CompileRun(source);
10643 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
10644 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
10645 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
10646 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
10647 CHECK(context->Global()->Get(v8_str("h"))->IsUndefined());
10648
10649 // Failing access check to property get results in undefined.
10650 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
10651 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
10652
10653 // Failing access check to function call results in exception.
10654 CHECK(g1->Call(global, 0, NULL).IsEmpty());
10655 CHECK(g2->Call(global, 0, NULL).IsEmpty());
10656}
10657
10658
Steve Blocka7e24c12009-10-30 11:49:00 +000010659// This test verifies that pre-compilation (aka preparsing) can be called
10660// without initializing the whole VM. Thus we cannot run this test in a
10661// multi-threaded setup.
10662TEST(PreCompile) {
10663 // TODO(155): This test would break without the initialization of V8. This is
10664 // a workaround for now to make this test not fail.
10665 v8::V8::Initialize();
Leon Clarkef7060e22010-06-03 12:02:55 +010010666 const char* script = "function foo(a) { return a+1; }";
10667 v8::ScriptData* sd =
Steve Blockd0582a62009-12-15 09:54:21 +000010668 v8::ScriptData::PreCompile(script, i::StrLength(script));
Steve Blocka7e24c12009-10-30 11:49:00 +000010669 CHECK_NE(sd->Length(), 0);
10670 CHECK_NE(sd->Data(), NULL);
Leon Clarkee46be812010-01-19 14:06:41 +000010671 CHECK(!sd->HasError());
10672 delete sd;
10673}
10674
10675
10676TEST(PreCompileWithError) {
10677 v8::V8::Initialize();
Leon Clarkef7060e22010-06-03 12:02:55 +010010678 const char* script = "function foo(a) { return 1 * * 2; }";
10679 v8::ScriptData* sd =
Leon Clarkee46be812010-01-19 14:06:41 +000010680 v8::ScriptData::PreCompile(script, i::StrLength(script));
10681 CHECK(sd->HasError());
10682 delete sd;
10683}
10684
10685
10686TEST(Regress31661) {
10687 v8::V8::Initialize();
Leon Clarkef7060e22010-06-03 12:02:55 +010010688 const char* script = " The Definintive Guide";
10689 v8::ScriptData* sd =
Leon Clarkee46be812010-01-19 14:06:41 +000010690 v8::ScriptData::PreCompile(script, i::StrLength(script));
10691 CHECK(sd->HasError());
Steve Blocka7e24c12009-10-30 11:49:00 +000010692 delete sd;
10693}
10694
10695
Leon Clarkef7060e22010-06-03 12:02:55 +010010696// Tests that ScriptData can be serialized and deserialized.
10697TEST(PreCompileSerialization) {
10698 v8::V8::Initialize();
10699 const char* script = "function foo(a) { return a+1; }";
10700 v8::ScriptData* sd =
10701 v8::ScriptData::PreCompile(script, i::StrLength(script));
10702
10703 // Serialize.
10704 int serialized_data_length = sd->Length();
10705 char* serialized_data = i::NewArray<char>(serialized_data_length);
10706 memcpy(serialized_data, sd->Data(), serialized_data_length);
10707
10708 // Deserialize.
10709 v8::ScriptData* deserialized_sd =
10710 v8::ScriptData::New(serialized_data, serialized_data_length);
10711
10712 // Verify that the original is the same as the deserialized.
10713 CHECK_EQ(sd->Length(), deserialized_sd->Length());
10714 CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
10715 CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
10716
10717 delete sd;
10718 delete deserialized_sd;
10719}
10720
10721
10722// Attempts to deserialize bad data.
10723TEST(PreCompileDeserializationError) {
10724 v8::V8::Initialize();
10725 const char* data = "DONT CARE";
10726 int invalid_size = 3;
10727 v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
10728
10729 CHECK_EQ(0, sd->Length());
10730
10731 delete sd;
10732}
10733
10734
Leon Clarkeac952652010-07-15 11:15:24 +010010735// Attempts to deserialize bad data.
10736TEST(PreCompileInvalidPreparseDataError) {
10737 v8::V8::Initialize();
10738 v8::HandleScope scope;
10739 LocalContext context;
10740
10741 const char* script = "function foo(){ return 5;}\n"
10742 "function bar(){ return 6 + 7;} foo();";
10743 v8::ScriptData* sd =
10744 v8::ScriptData::PreCompile(script, i::StrLength(script));
10745 CHECK(!sd->HasError());
10746 // ScriptDataImpl private implementation details
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -080010747 const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
Iain Merrick9ac36c92010-09-13 15:29:50 +010010748 const int kFunctionEntrySize = i::FunctionEntry::kSize;
Leon Clarkeac952652010-07-15 11:15:24 +010010749 const int kFunctionEntryStartOffset = 0;
10750 const int kFunctionEntryEndOffset = 1;
10751 unsigned* sd_data =
10752 reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
Leon Clarkeac952652010-07-15 11:15:24 +010010753
10754 // Overwrite function bar's end position with 0.
10755 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
10756 v8::TryCatch try_catch;
10757
10758 Local<String> source = String::New(script);
10759 Local<Script> compiled_script = Script::New(source, NULL, sd);
10760 CHECK(try_catch.HasCaught());
10761 String::AsciiValue exception_value(try_catch.Message()->Get());
10762 CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
10763 *exception_value);
10764
10765 try_catch.Reset();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010766
Leon Clarkeac952652010-07-15 11:15:24 +010010767 // Overwrite function bar's start position with 200. The function entry
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010768 // will not be found when searching for it by position and we should fall
10769 // back on eager compilation.
Kristian Monsen80d68ea2010-09-08 11:05:35 +010010770 sd = v8::ScriptData::PreCompile(script, i::StrLength(script));
10771 sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
Leon Clarkeac952652010-07-15 11:15:24 +010010772 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
10773 200;
10774 compiled_script = Script::New(source, NULL, sd);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010775 CHECK(!try_catch.HasCaught());
Leon Clarkeac952652010-07-15 11:15:24 +010010776
10777 delete sd;
10778}
10779
10780
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010010781// Verifies that the Handle<String> and const char* versions of the API produce
10782// the same results (at least for one trivial case).
10783TEST(PreCompileAPIVariationsAreSame) {
10784 v8::V8::Initialize();
10785 v8::HandleScope scope;
10786
10787 const char* cstring = "function foo(a) { return a+1; }";
Ben Murdoch3bec4d22010-07-22 14:51:16 +010010788
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010010789 v8::ScriptData* sd_from_cstring =
10790 v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
10791
10792 TestAsciiResource* resource = new TestAsciiResource(cstring);
Ben Murdoch3bec4d22010-07-22 14:51:16 +010010793 v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile(
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010010794 v8::String::NewExternal(resource));
10795
Ben Murdoch3bec4d22010-07-22 14:51:16 +010010796 v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile(
10797 v8::String::New(cstring));
10798
10799 CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010010800 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
Ben Murdoch3bec4d22010-07-22 14:51:16 +010010801 sd_from_external_string->Data(),
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010010802 sd_from_cstring->Length()));
10803
Ben Murdoch3bec4d22010-07-22 14:51:16 +010010804 CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length());
10805 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
10806 sd_from_string->Data(),
10807 sd_from_cstring->Length()));
10808
10809
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010010810 delete sd_from_cstring;
Ben Murdoch3bec4d22010-07-22 14:51:16 +010010811 delete sd_from_external_string;
10812 delete sd_from_string;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010010813}
10814
10815
Steve Blocka7e24c12009-10-30 11:49:00 +000010816// This tests that we do not allow dictionary load/call inline caches
10817// to use functions that have not yet been compiled. The potential
10818// problem of loading a function that has not yet been compiled can
10819// arise because we share code between contexts via the compilation
10820// cache.
10821THREADED_TEST(DictionaryICLoadedFunction) {
10822 v8::HandleScope scope;
10823 // Test LoadIC.
10824 for (int i = 0; i < 2; i++) {
10825 LocalContext context;
10826 context->Global()->Set(v8_str("tmp"), v8::True());
10827 context->Global()->Delete(v8_str("tmp"));
10828 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
10829 }
10830 // Test CallIC.
10831 for (int i = 0; i < 2; i++) {
10832 LocalContext context;
10833 context->Global()->Set(v8_str("tmp"), v8::True());
10834 context->Global()->Delete(v8_str("tmp"));
10835 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
10836 }
10837}
10838
10839
10840// Test that cross-context new calls use the context of the callee to
10841// create the new JavaScript object.
10842THREADED_TEST(CrossContextNew) {
10843 v8::HandleScope scope;
10844 v8::Persistent<Context> context0 = Context::New();
10845 v8::Persistent<Context> context1 = Context::New();
10846
10847 // Allow cross-domain access.
10848 Local<String> token = v8_str("<security token>");
10849 context0->SetSecurityToken(token);
10850 context1->SetSecurityToken(token);
10851
10852 // Set an 'x' property on the Object prototype and define a
10853 // constructor function in context0.
10854 context0->Enter();
10855 CompileRun("Object.prototype.x = 42; function C() {};");
10856 context0->Exit();
10857
10858 // Call the constructor function from context0 and check that the
10859 // result has the 'x' property.
10860 context1->Enter();
10861 context1->Global()->Set(v8_str("other"), context0->Global());
10862 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
10863 CHECK(value->IsInt32());
10864 CHECK_EQ(42, value->Int32Value());
10865 context1->Exit();
10866
10867 // Dispose the contexts to allow them to be garbage collected.
10868 context0.Dispose();
10869 context1.Dispose();
10870}
10871
10872
10873class RegExpInterruptTest {
10874 public:
10875 RegExpInterruptTest() : block_(NULL) {}
10876 ~RegExpInterruptTest() { delete block_; }
10877 void RunTest() {
10878 block_ = i::OS::CreateSemaphore(0);
10879 gc_count_ = 0;
10880 gc_during_regexp_ = 0;
10881 regexp_success_ = false;
10882 gc_success_ = false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010883 GCThread gc_thread(this);
Steve Blocka7e24c12009-10-30 11:49:00 +000010884 gc_thread.Start();
10885 v8::Locker::StartPreemption(1);
10886
10887 LongRunningRegExp();
10888 {
10889 v8::Unlocker unlock;
10890 gc_thread.Join();
10891 }
10892 v8::Locker::StopPreemption();
10893 CHECK(regexp_success_);
10894 CHECK(gc_success_);
10895 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010896
Steve Blocka7e24c12009-10-30 11:49:00 +000010897 private:
10898 // Number of garbage collections required.
10899 static const int kRequiredGCs = 5;
10900
10901 class GCThread : public i::Thread {
10902 public:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010903 explicit GCThread(RegExpInterruptTest* test)
10904 : Thread("GCThread"), test_(test) {}
Steve Blocka7e24c12009-10-30 11:49:00 +000010905 virtual void Run() {
10906 test_->CollectGarbage();
10907 }
10908 private:
10909 RegExpInterruptTest* test_;
10910 };
10911
10912 void CollectGarbage() {
10913 block_->Wait();
10914 while (gc_during_regexp_ < kRequiredGCs) {
10915 {
10916 v8::Locker lock;
10917 // TODO(lrn): Perhaps create some garbage before collecting.
Steve Block44f0eee2011-05-26 01:26:41 +010010918 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +000010919 gc_count_++;
10920 }
10921 i::OS::Sleep(1);
10922 }
10923 gc_success_ = true;
10924 }
10925
10926 void LongRunningRegExp() {
10927 block_->Signal(); // Enable garbage collection thread on next preemption.
10928 int rounds = 0;
10929 while (gc_during_regexp_ < kRequiredGCs) {
10930 int gc_before = gc_count_;
10931 {
10932 // Match 15-30 "a"'s against 14 and a "b".
10933 const char* c_source =
10934 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
10935 ".exec('aaaaaaaaaaaaaaab') === null";
10936 Local<String> source = String::New(c_source);
10937 Local<Script> script = Script::Compile(source);
10938 Local<Value> result = script->Run();
10939 if (!result->BooleanValue()) {
10940 gc_during_regexp_ = kRequiredGCs; // Allow gc thread to exit.
10941 return;
10942 }
10943 }
10944 {
10945 // Match 15-30 "a"'s against 15 and a "b".
10946 const char* c_source =
10947 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
10948 ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
10949 Local<String> source = String::New(c_source);
10950 Local<Script> script = Script::Compile(source);
10951 Local<Value> result = script->Run();
10952 if (!result->BooleanValue()) {
10953 gc_during_regexp_ = kRequiredGCs;
10954 return;
10955 }
10956 }
10957 int gc_after = gc_count_;
10958 gc_during_regexp_ += gc_after - gc_before;
10959 rounds++;
10960 i::OS::Sleep(1);
10961 }
10962 regexp_success_ = true;
10963 }
10964
10965 i::Semaphore* block_;
10966 int gc_count_;
10967 int gc_during_regexp_;
10968 bool regexp_success_;
10969 bool gc_success_;
10970};
10971
10972
10973// Test that a regular expression execution can be interrupted and
10974// survive a garbage collection.
10975TEST(RegExpInterruption) {
10976 v8::Locker lock;
10977 v8::V8::Initialize();
10978 v8::HandleScope scope;
10979 Local<Context> local_env;
10980 {
10981 LocalContext env;
10982 local_env = env.local();
10983 }
10984
10985 // Local context should still be live.
10986 CHECK(!local_env.IsEmpty());
10987 local_env->Enter();
10988
10989 // Should complete without problems.
10990 RegExpInterruptTest().RunTest();
10991
10992 local_env->Exit();
10993}
10994
10995
10996class ApplyInterruptTest {
10997 public:
10998 ApplyInterruptTest() : block_(NULL) {}
10999 ~ApplyInterruptTest() { delete block_; }
11000 void RunTest() {
11001 block_ = i::OS::CreateSemaphore(0);
11002 gc_count_ = 0;
11003 gc_during_apply_ = 0;
11004 apply_success_ = false;
11005 gc_success_ = false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011006 GCThread gc_thread(this);
Steve Blocka7e24c12009-10-30 11:49:00 +000011007 gc_thread.Start();
11008 v8::Locker::StartPreemption(1);
11009
11010 LongRunningApply();
11011 {
11012 v8::Unlocker unlock;
11013 gc_thread.Join();
11014 }
11015 v8::Locker::StopPreemption();
11016 CHECK(apply_success_);
11017 CHECK(gc_success_);
11018 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011019
Steve Blocka7e24c12009-10-30 11:49:00 +000011020 private:
11021 // Number of garbage collections required.
11022 static const int kRequiredGCs = 2;
11023
11024 class GCThread : public i::Thread {
11025 public:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011026 explicit GCThread(ApplyInterruptTest* test)
11027 : Thread("GCThread"), test_(test) {}
Steve Blocka7e24c12009-10-30 11:49:00 +000011028 virtual void Run() {
11029 test_->CollectGarbage();
11030 }
11031 private:
11032 ApplyInterruptTest* test_;
11033 };
11034
11035 void CollectGarbage() {
11036 block_->Wait();
11037 while (gc_during_apply_ < kRequiredGCs) {
11038 {
11039 v8::Locker lock;
Steve Block44f0eee2011-05-26 01:26:41 +010011040 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +000011041 gc_count_++;
11042 }
11043 i::OS::Sleep(1);
11044 }
11045 gc_success_ = true;
11046 }
11047
11048 void LongRunningApply() {
11049 block_->Signal();
11050 int rounds = 0;
11051 while (gc_during_apply_ < kRequiredGCs) {
11052 int gc_before = gc_count_;
11053 {
11054 const char* c_source =
11055 "function do_very_little(bar) {"
11056 " this.foo = bar;"
11057 "}"
11058 "for (var i = 0; i < 100000; i++) {"
11059 " do_very_little.apply(this, ['bar']);"
11060 "}";
11061 Local<String> source = String::New(c_source);
11062 Local<Script> script = Script::Compile(source);
11063 Local<Value> result = script->Run();
11064 // Check that no exception was thrown.
11065 CHECK(!result.IsEmpty());
11066 }
11067 int gc_after = gc_count_;
11068 gc_during_apply_ += gc_after - gc_before;
11069 rounds++;
11070 }
11071 apply_success_ = true;
11072 }
11073
11074 i::Semaphore* block_;
11075 int gc_count_;
11076 int gc_during_apply_;
11077 bool apply_success_;
11078 bool gc_success_;
11079};
11080
11081
11082// Test that nothing bad happens if we get a preemption just when we were
11083// about to do an apply().
11084TEST(ApplyInterruption) {
11085 v8::Locker lock;
11086 v8::V8::Initialize();
11087 v8::HandleScope scope;
11088 Local<Context> local_env;
11089 {
11090 LocalContext env;
11091 local_env = env.local();
11092 }
11093
11094 // Local context should still be live.
11095 CHECK(!local_env.IsEmpty());
11096 local_env->Enter();
11097
11098 // Should complete without problems.
11099 ApplyInterruptTest().RunTest();
11100
11101 local_env->Exit();
11102}
11103
11104
11105// Verify that we can clone an object
11106TEST(ObjectClone) {
11107 v8::HandleScope scope;
11108 LocalContext env;
11109
11110 const char* sample =
11111 "var rv = {};" \
11112 "rv.alpha = 'hello';" \
11113 "rv.beta = 123;" \
11114 "rv;";
11115
11116 // Create an object, verify basics.
11117 Local<Value> val = CompileRun(sample);
11118 CHECK(val->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +010011119 Local<v8::Object> obj = val.As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +000011120 obj->Set(v8_str("gamma"), v8_str("cloneme"));
11121
11122 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
11123 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
11124 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
11125
11126 // Clone it.
11127 Local<v8::Object> clone = obj->Clone();
11128 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
11129 CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
11130 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
11131
11132 // Set a property on the clone, verify each object.
11133 clone->Set(v8_str("beta"), v8::Integer::New(456));
11134 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
11135 CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
11136}
11137
11138
11139class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
11140 public:
11141 explicit AsciiVectorResource(i::Vector<const char> vector)
11142 : data_(vector) {}
11143 virtual ~AsciiVectorResource() {}
11144 virtual size_t length() const { return data_.length(); }
11145 virtual const char* data() const { return data_.start(); }
11146 private:
11147 i::Vector<const char> data_;
11148};
11149
11150
11151class UC16VectorResource : public v8::String::ExternalStringResource {
11152 public:
11153 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
11154 : data_(vector) {}
11155 virtual ~UC16VectorResource() {}
11156 virtual size_t length() const { return data_.length(); }
11157 virtual const i::uc16* data() const { return data_.start(); }
11158 private:
11159 i::Vector<const i::uc16> data_;
11160};
11161
11162
11163static void MorphAString(i::String* string,
11164 AsciiVectorResource* ascii_resource,
11165 UC16VectorResource* uc16_resource) {
11166 CHECK(i::StringShape(string).IsExternal());
11167 if (string->IsAsciiRepresentation()) {
11168 // Check old map is not symbol or long.
Steve Block44f0eee2011-05-26 01:26:41 +010011169 CHECK(string->map() == HEAP->external_ascii_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +000011170 // Morph external string to be TwoByte string.
Steve Block44f0eee2011-05-26 01:26:41 +010011171 string->set_map(HEAP->external_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +000011172 i::ExternalTwoByteString* morphed =
11173 i::ExternalTwoByteString::cast(string);
11174 morphed->set_resource(uc16_resource);
11175 } else {
11176 // Check old map is not symbol or long.
Steve Block44f0eee2011-05-26 01:26:41 +010011177 CHECK(string->map() == HEAP->external_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +000011178 // Morph external string to be ASCII string.
Steve Block44f0eee2011-05-26 01:26:41 +010011179 string->set_map(HEAP->external_ascii_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +000011180 i::ExternalAsciiString* morphed =
11181 i::ExternalAsciiString::cast(string);
11182 morphed->set_resource(ascii_resource);
11183 }
11184}
11185
11186
11187// Test that we can still flatten a string if the components it is built up
11188// from have been turned into 16 bit strings in the mean time.
11189THREADED_TEST(MorphCompositeStringTest) {
11190 const char* c_string = "Now is the time for all good men"
11191 " to come to the aid of the party";
11192 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
11193 {
11194 v8::HandleScope scope;
11195 LocalContext env;
11196 AsciiVectorResource ascii_resource(
Steve Blockd0582a62009-12-15 09:54:21 +000011197 i::Vector<const char>(c_string, i::StrLength(c_string)));
Steve Blocka7e24c12009-10-30 11:49:00 +000011198 UC16VectorResource uc16_resource(
Steve Blockd0582a62009-12-15 09:54:21 +000011199 i::Vector<const uint16_t>(two_byte_string,
11200 i::StrLength(c_string)));
Steve Blocka7e24c12009-10-30 11:49:00 +000011201
11202 Local<String> lhs(v8::Utils::ToLocal(
Steve Block44f0eee2011-05-26 01:26:41 +010011203 FACTORY->NewExternalStringFromAscii(&ascii_resource)));
Steve Blocka7e24c12009-10-30 11:49:00 +000011204 Local<String> rhs(v8::Utils::ToLocal(
Steve Block44f0eee2011-05-26 01:26:41 +010011205 FACTORY->NewExternalStringFromAscii(&ascii_resource)));
Steve Blocka7e24c12009-10-30 11:49:00 +000011206
11207 env->Global()->Set(v8_str("lhs"), lhs);
11208 env->Global()->Set(v8_str("rhs"), rhs);
11209
11210 CompileRun(
11211 "var cons = lhs + rhs;"
11212 "var slice = lhs.substring(1, lhs.length - 1);"
11213 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
11214
11215 MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
11216 MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
11217
11218 // Now do some stuff to make sure the strings are flattened, etc.
11219 CompileRun(
11220 "/[^a-z]/.test(cons);"
11221 "/[^a-z]/.test(slice);"
11222 "/[^a-z]/.test(slice_on_cons);");
11223 const char* expected_cons =
11224 "Now is the time for all good men to come to the aid of the party"
11225 "Now is the time for all good men to come to the aid of the party";
11226 const char* expected_slice =
11227 "ow is the time for all good men to come to the aid of the part";
11228 const char* expected_slice_on_cons =
11229 "ow is the time for all good men to come to the aid of the party"
11230 "Now is the time for all good men to come to the aid of the part";
11231 CHECK_EQ(String::New(expected_cons),
11232 env->Global()->Get(v8_str("cons")));
11233 CHECK_EQ(String::New(expected_slice),
11234 env->Global()->Get(v8_str("slice")));
11235 CHECK_EQ(String::New(expected_slice_on_cons),
11236 env->Global()->Get(v8_str("slice_on_cons")));
11237 }
Ben Murdoch3bec4d22010-07-22 14:51:16 +010011238 i::DeleteArray(two_byte_string);
Steve Blocka7e24c12009-10-30 11:49:00 +000011239}
11240
11241
11242TEST(CompileExternalTwoByteSource) {
11243 v8::HandleScope scope;
11244 LocalContext context;
11245
11246 // This is a very short list of sources, which currently is to check for a
11247 // regression caused by r2703.
11248 const char* ascii_sources[] = {
11249 "0.5",
11250 "-0.5", // This mainly testes PushBack in the Scanner.
11251 "--0.5", // This mainly testes PushBack in the Scanner.
11252 NULL
11253 };
11254
11255 // Compile the sources as external two byte strings.
11256 for (int i = 0; ascii_sources[i] != NULL; i++) {
11257 uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
11258 UC16VectorResource uc16_resource(
Steve Blockd0582a62009-12-15 09:54:21 +000011259 i::Vector<const uint16_t>(two_byte_string,
11260 i::StrLength(ascii_sources[i])));
Steve Blocka7e24c12009-10-30 11:49:00 +000011261 v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
11262 v8::Script::Compile(source);
Ben Murdoch3bec4d22010-07-22 14:51:16 +010011263 i::DeleteArray(two_byte_string);
Steve Blocka7e24c12009-10-30 11:49:00 +000011264 }
11265}
11266
11267
11268class RegExpStringModificationTest {
11269 public:
11270 RegExpStringModificationTest()
11271 : block_(i::OS::CreateSemaphore(0)),
11272 morphs_(0),
11273 morphs_during_regexp_(0),
11274 ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
11275 uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
11276 ~RegExpStringModificationTest() { delete block_; }
11277 void RunTest() {
11278 regexp_success_ = false;
11279 morph_success_ = false;
11280
11281 // Initialize the contents of two_byte_content_ to be a uc16 representation
11282 // of "aaaaaaaaaaaaaab".
11283 for (int i = 0; i < 14; i++) {
11284 two_byte_content_[i] = 'a';
11285 }
11286 two_byte_content_[14] = 'b';
11287
11288 // Create the input string for the regexp - the one we are going to change
11289 // properties of.
Steve Block44f0eee2011-05-26 01:26:41 +010011290 input_ = FACTORY->NewExternalStringFromAscii(&ascii_resource_);
Steve Blocka7e24c12009-10-30 11:49:00 +000011291
11292 // Inject the input as a global variable.
11293 i::Handle<i::String> input_name =
Steve Block44f0eee2011-05-26 01:26:41 +010011294 FACTORY->NewStringFromAscii(i::Vector<const char>("input", 5));
11295 i::Isolate::Current()->global_context()->global()->SetProperty(
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011296 *input_name,
11297 *input_,
11298 NONE,
11299 i::kNonStrictMode)->ToObjectChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +000011300
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011301 MorphThread morph_thread(this);
Steve Blocka7e24c12009-10-30 11:49:00 +000011302 morph_thread.Start();
11303 v8::Locker::StartPreemption(1);
11304 LongRunningRegExp();
11305 {
11306 v8::Unlocker unlock;
11307 morph_thread.Join();
11308 }
11309 v8::Locker::StopPreemption();
11310 CHECK(regexp_success_);
11311 CHECK(morph_success_);
11312 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011313
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011314 private:
Steve Blocka7e24c12009-10-30 11:49:00 +000011315 // Number of string modifications required.
11316 static const int kRequiredModifications = 5;
11317 static const int kMaxModifications = 100;
11318
11319 class MorphThread : public i::Thread {
11320 public:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011321 explicit MorphThread(RegExpStringModificationTest* test)
11322 : Thread("MorphThread"), test_(test) {}
Steve Blocka7e24c12009-10-30 11:49:00 +000011323 virtual void Run() {
11324 test_->MorphString();
11325 }
11326 private:
11327 RegExpStringModificationTest* test_;
11328 };
11329
11330 void MorphString() {
11331 block_->Wait();
11332 while (morphs_during_regexp_ < kRequiredModifications &&
11333 morphs_ < kMaxModifications) {
11334 {
11335 v8::Locker lock;
11336 // Swap string between ascii and two-byte representation.
11337 i::String* string = *input_;
11338 MorphAString(string, &ascii_resource_, &uc16_resource_);
11339 morphs_++;
11340 }
11341 i::OS::Sleep(1);
11342 }
11343 morph_success_ = true;
11344 }
11345
11346 void LongRunningRegExp() {
11347 block_->Signal(); // Enable morphing thread on next preemption.
11348 while (morphs_during_regexp_ < kRequiredModifications &&
11349 morphs_ < kMaxModifications) {
11350 int morphs_before = morphs_;
11351 {
Steve Block791712a2010-08-27 10:21:07 +010011352 v8::HandleScope scope;
Steve Blocka7e24c12009-10-30 11:49:00 +000011353 // Match 15-30 "a"'s against 14 and a "b".
11354 const char* c_source =
11355 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
11356 ".exec(input) === null";
11357 Local<String> source = String::New(c_source);
11358 Local<Script> script = Script::Compile(source);
11359 Local<Value> result = script->Run();
11360 CHECK(result->IsTrue());
11361 }
11362 int morphs_after = morphs_;
11363 morphs_during_regexp_ += morphs_after - morphs_before;
11364 }
11365 regexp_success_ = true;
11366 }
11367
11368 i::uc16 two_byte_content_[15];
11369 i::Semaphore* block_;
11370 int morphs_;
11371 int morphs_during_regexp_;
11372 bool regexp_success_;
11373 bool morph_success_;
11374 i::Handle<i::String> input_;
11375 AsciiVectorResource ascii_resource_;
11376 UC16VectorResource uc16_resource_;
11377};
11378
11379
11380// Test that a regular expression execution can be interrupted and
11381// the string changed without failing.
11382TEST(RegExpStringModification) {
11383 v8::Locker lock;
11384 v8::V8::Initialize();
11385 v8::HandleScope scope;
11386 Local<Context> local_env;
11387 {
11388 LocalContext env;
11389 local_env = env.local();
11390 }
11391
11392 // Local context should still be live.
11393 CHECK(!local_env.IsEmpty());
11394 local_env->Enter();
11395
11396 // Should complete without problems.
11397 RegExpStringModificationTest().RunTest();
11398
11399 local_env->Exit();
11400}
11401
11402
11403// Test that we can set a property on the global object even if there
11404// is a read-only property in the prototype chain.
11405TEST(ReadOnlyPropertyInGlobalProto) {
11406 v8::HandleScope scope;
11407 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11408 LocalContext context(0, templ);
11409 v8::Handle<v8::Object> global = context->Global();
11410 v8::Handle<v8::Object> global_proto =
11411 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
11412 global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
11413 global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
11414 // Check without 'eval' or 'with'.
11415 v8::Handle<v8::Value> res =
11416 CompileRun("function f() { x = 42; return x; }; f()");
11417 // Check with 'eval'.
11418 res = CompileRun("function f() { eval('1'); y = 42; return y; }; f()");
11419 CHECK_EQ(v8::Integer::New(42), res);
11420 // Check with 'with'.
11421 res = CompileRun("function f() { with (this) { y = 42 }; return y; }; f()");
11422 CHECK_EQ(v8::Integer::New(42), res);
11423}
11424
11425static int force_set_set_count = 0;
11426static int force_set_get_count = 0;
11427bool pass_on_get = false;
11428
11429static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
11430 const v8::AccessorInfo& info) {
11431 force_set_get_count++;
11432 if (pass_on_get) {
11433 return v8::Handle<v8::Value>();
11434 } else {
11435 return v8::Int32::New(3);
11436 }
11437}
11438
11439static void ForceSetSetter(v8::Local<v8::String> name,
11440 v8::Local<v8::Value> value,
11441 const v8::AccessorInfo& info) {
11442 force_set_set_count++;
11443}
11444
11445static v8::Handle<v8::Value> ForceSetInterceptSetter(
11446 v8::Local<v8::String> name,
11447 v8::Local<v8::Value> value,
11448 const v8::AccessorInfo& info) {
11449 force_set_set_count++;
11450 return v8::Undefined();
11451}
11452
11453TEST(ForceSet) {
11454 force_set_get_count = 0;
11455 force_set_set_count = 0;
11456 pass_on_get = false;
11457
11458 v8::HandleScope scope;
11459 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11460 v8::Handle<v8::String> access_property = v8::String::New("a");
11461 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
11462 LocalContext context(NULL, templ);
11463 v8::Handle<v8::Object> global = context->Global();
11464
11465 // Ordinary properties
11466 v8::Handle<v8::String> simple_property = v8::String::New("p");
11467 global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
11468 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11469 // This should fail because the property is read-only
11470 global->Set(simple_property, v8::Int32::New(5));
11471 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11472 // This should succeed even though the property is read-only
11473 global->ForceSet(simple_property, v8::Int32::New(6));
11474 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
11475
11476 // Accessors
11477 CHECK_EQ(0, force_set_set_count);
11478 CHECK_EQ(0, force_set_get_count);
11479 CHECK_EQ(3, global->Get(access_property)->Int32Value());
11480 // CHECK_EQ the property shouldn't override it, just call the setter
11481 // which in this case does nothing.
11482 global->Set(access_property, v8::Int32::New(7));
11483 CHECK_EQ(3, global->Get(access_property)->Int32Value());
11484 CHECK_EQ(1, force_set_set_count);
11485 CHECK_EQ(2, force_set_get_count);
11486 // Forcing the property to be set should override the accessor without
11487 // calling it
11488 global->ForceSet(access_property, v8::Int32::New(8));
11489 CHECK_EQ(8, global->Get(access_property)->Int32Value());
11490 CHECK_EQ(1, force_set_set_count);
11491 CHECK_EQ(2, force_set_get_count);
11492}
11493
11494TEST(ForceSetWithInterceptor) {
11495 force_set_get_count = 0;
11496 force_set_set_count = 0;
11497 pass_on_get = false;
11498
11499 v8::HandleScope scope;
11500 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11501 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
11502 LocalContext context(NULL, templ);
11503 v8::Handle<v8::Object> global = context->Global();
11504
11505 v8::Handle<v8::String> some_property = v8::String::New("a");
11506 CHECK_EQ(0, force_set_set_count);
11507 CHECK_EQ(0, force_set_get_count);
11508 CHECK_EQ(3, global->Get(some_property)->Int32Value());
11509 // Setting the property shouldn't override it, just call the setter
11510 // which in this case does nothing.
11511 global->Set(some_property, v8::Int32::New(7));
11512 CHECK_EQ(3, global->Get(some_property)->Int32Value());
11513 CHECK_EQ(1, force_set_set_count);
11514 CHECK_EQ(2, force_set_get_count);
11515 // Getting the property when the interceptor returns an empty handle
11516 // should yield undefined, since the property isn't present on the
11517 // object itself yet.
11518 pass_on_get = true;
11519 CHECK(global->Get(some_property)->IsUndefined());
11520 CHECK_EQ(1, force_set_set_count);
11521 CHECK_EQ(3, force_set_get_count);
11522 // Forcing the property to be set should cause the value to be
11523 // set locally without calling the interceptor.
11524 global->ForceSet(some_property, v8::Int32::New(8));
11525 CHECK_EQ(8, global->Get(some_property)->Int32Value());
11526 CHECK_EQ(1, force_set_set_count);
11527 CHECK_EQ(4, force_set_get_count);
11528 // Reenabling the interceptor should cause it to take precedence over
11529 // the property
11530 pass_on_get = false;
11531 CHECK_EQ(3, global->Get(some_property)->Int32Value());
11532 CHECK_EQ(1, force_set_set_count);
11533 CHECK_EQ(5, force_set_get_count);
11534 // The interceptor should also work for other properties
11535 CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
11536 CHECK_EQ(1, force_set_set_count);
11537 CHECK_EQ(6, force_set_get_count);
11538}
11539
11540
11541THREADED_TEST(ForceDelete) {
11542 v8::HandleScope scope;
11543 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11544 LocalContext context(NULL, templ);
11545 v8::Handle<v8::Object> global = context->Global();
11546
11547 // Ordinary properties
11548 v8::Handle<v8::String> simple_property = v8::String::New("p");
11549 global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
11550 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11551 // This should fail because the property is dont-delete.
11552 CHECK(!global->Delete(simple_property));
11553 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11554 // This should succeed even though the property is dont-delete.
11555 CHECK(global->ForceDelete(simple_property));
11556 CHECK(global->Get(simple_property)->IsUndefined());
11557}
11558
11559
11560static int force_delete_interceptor_count = 0;
11561static bool pass_on_delete = false;
11562
11563
11564static v8::Handle<v8::Boolean> ForceDeleteDeleter(
11565 v8::Local<v8::String> name,
11566 const v8::AccessorInfo& info) {
11567 force_delete_interceptor_count++;
11568 if (pass_on_delete) {
11569 return v8::Handle<v8::Boolean>();
11570 } else {
11571 return v8::True();
11572 }
11573}
11574
11575
11576THREADED_TEST(ForceDeleteWithInterceptor) {
11577 force_delete_interceptor_count = 0;
11578 pass_on_delete = false;
11579
11580 v8::HandleScope scope;
11581 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11582 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
11583 LocalContext context(NULL, templ);
11584 v8::Handle<v8::Object> global = context->Global();
11585
11586 v8::Handle<v8::String> some_property = v8::String::New("a");
11587 global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
11588
11589 // Deleting a property should get intercepted and nothing should
11590 // happen.
11591 CHECK_EQ(0, force_delete_interceptor_count);
11592 CHECK(global->Delete(some_property));
11593 CHECK_EQ(1, force_delete_interceptor_count);
11594 CHECK_EQ(42, global->Get(some_property)->Int32Value());
11595 // Deleting the property when the interceptor returns an empty
11596 // handle should not delete the property since it is DontDelete.
11597 pass_on_delete = true;
11598 CHECK(!global->Delete(some_property));
11599 CHECK_EQ(2, force_delete_interceptor_count);
11600 CHECK_EQ(42, global->Get(some_property)->Int32Value());
11601 // Forcing the property to be deleted should delete the value
11602 // without calling the interceptor.
11603 CHECK(global->ForceDelete(some_property));
11604 CHECK(global->Get(some_property)->IsUndefined());
11605 CHECK_EQ(2, force_delete_interceptor_count);
11606}
11607
11608
11609// Make sure that forcing a delete invalidates any IC stubs, so we
11610// don't read the hole value.
11611THREADED_TEST(ForceDeleteIC) {
11612 v8::HandleScope scope;
11613 LocalContext context;
11614 // Create a DontDelete variable on the global object.
11615 CompileRun("this.__proto__ = { foo: 'horse' };"
11616 "var foo = 'fish';"
11617 "function f() { return foo.length; }");
11618 // Initialize the IC for foo in f.
11619 CompileRun("for (var i = 0; i < 4; i++) f();");
11620 // Make sure the value of foo is correct before the deletion.
11621 CHECK_EQ(4, CompileRun("f()")->Int32Value());
11622 // Force the deletion of foo.
11623 CHECK(context->Global()->ForceDelete(v8_str("foo")));
11624 // Make sure the value for foo is read from the prototype, and that
11625 // we don't get in trouble with reading the deleted cell value
11626 // sentinel.
11627 CHECK_EQ(5, CompileRun("f()")->Int32Value());
11628}
11629
11630
11631v8::Persistent<Context> calling_context0;
11632v8::Persistent<Context> calling_context1;
11633v8::Persistent<Context> calling_context2;
11634
11635
11636// Check that the call to the callback is initiated in
11637// calling_context2, the directly calling context is calling_context1
11638// and the callback itself is in calling_context0.
11639static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
11640 ApiTestFuzzer::Fuzz();
11641 CHECK(Context::GetCurrent() == calling_context0);
11642 CHECK(Context::GetCalling() == calling_context1);
11643 CHECK(Context::GetEntered() == calling_context2);
11644 return v8::Integer::New(42);
11645}
11646
11647
11648THREADED_TEST(GetCallingContext) {
11649 v8::HandleScope scope;
11650
11651 calling_context0 = Context::New();
11652 calling_context1 = Context::New();
11653 calling_context2 = Context::New();
11654
11655 // Allow cross-domain access.
11656 Local<String> token = v8_str("<security token>");
11657 calling_context0->SetSecurityToken(token);
11658 calling_context1->SetSecurityToken(token);
11659 calling_context2->SetSecurityToken(token);
11660
11661 // Create an object with a C++ callback in context0.
11662 calling_context0->Enter();
11663 Local<v8::FunctionTemplate> callback_templ =
11664 v8::FunctionTemplate::New(GetCallingContextCallback);
11665 calling_context0->Global()->Set(v8_str("callback"),
11666 callback_templ->GetFunction());
11667 calling_context0->Exit();
11668
11669 // Expose context0 in context1 and setup a function that calls the
11670 // callback function.
11671 calling_context1->Enter();
11672 calling_context1->Global()->Set(v8_str("context0"),
11673 calling_context0->Global());
11674 CompileRun("function f() { context0.callback() }");
11675 calling_context1->Exit();
11676
11677 // Expose context1 in context2 and call the callback function in
11678 // context0 indirectly through f in context1.
11679 calling_context2->Enter();
11680 calling_context2->Global()->Set(v8_str("context1"),
11681 calling_context1->Global());
11682 CompileRun("context1.f()");
11683 calling_context2->Exit();
11684
11685 // Dispose the contexts to allow them to be garbage collected.
11686 calling_context0.Dispose();
11687 calling_context1.Dispose();
11688 calling_context2.Dispose();
11689 calling_context0.Clear();
11690 calling_context1.Clear();
11691 calling_context2.Clear();
11692}
11693
11694
11695// Check that a variable declaration with no explicit initialization
11696// value does not shadow an existing property in the prototype chain.
11697//
11698// This is consistent with Firefox and Safari.
11699//
11700// See http://crbug.com/12548.
11701THREADED_TEST(InitGlobalVarInProtoChain) {
11702 v8::HandleScope scope;
11703 LocalContext context;
11704 // Introduce a variable in the prototype chain.
11705 CompileRun("__proto__.x = 42");
11706 v8::Handle<v8::Value> result = CompileRun("var x; x");
11707 CHECK(!result->IsUndefined());
11708 CHECK_EQ(42, result->Int32Value());
11709}
11710
11711
11712// Regression test for issue 398.
11713// If a function is added to an object, creating a constant function
11714// field, and the result is cloned, replacing the constant function on the
11715// original should not affect the clone.
11716// See http://code.google.com/p/v8/issues/detail?id=398
11717THREADED_TEST(ReplaceConstantFunction) {
11718 v8::HandleScope scope;
11719 LocalContext context;
11720 v8::Handle<v8::Object> obj = v8::Object::New();
11721 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
11722 v8::Handle<v8::String> foo_string = v8::String::New("foo");
11723 obj->Set(foo_string, func_templ->GetFunction());
11724 v8::Handle<v8::Object> obj_clone = obj->Clone();
11725 obj_clone->Set(foo_string, v8::String::New("Hello"));
11726 CHECK(!obj->Get(foo_string)->IsUndefined());
11727}
11728
11729
11730// Regression test for http://crbug.com/16276.
11731THREADED_TEST(Regress16276) {
11732 v8::HandleScope scope;
11733 LocalContext context;
11734 // Force the IC in f to be a dictionary load IC.
11735 CompileRun("function f(obj) { return obj.x; }\n"
11736 "var obj = { x: { foo: 42 }, y: 87 };\n"
11737 "var x = obj.x;\n"
11738 "delete obj.y;\n"
11739 "for (var i = 0; i < 5; i++) f(obj);");
11740 // Detach the global object to make 'this' refer directly to the
11741 // global object (not the proxy), and make sure that the dictionary
11742 // load IC doesn't mess up loading directly from the global object.
11743 context->DetachGlobal();
11744 CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
11745}
11746
11747
11748THREADED_TEST(PixelArray) {
11749 v8::HandleScope scope;
11750 LocalContext context;
Steve Blockd0582a62009-12-15 09:54:21 +000011751 const int kElementCount = 260;
Steve Blocka7e24c12009-10-30 11:49:00 +000011752 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
Steve Block44f0eee2011-05-26 01:26:41 +010011753 i::Handle<i::ExternalPixelArray> pixels =
11754 i::Handle<i::ExternalPixelArray>::cast(
11755 FACTORY->NewExternalArray(kElementCount,
11756 v8::kExternalPixelArray,
11757 pixel_data));
11758 HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
Steve Blocka7e24c12009-10-30 11:49:00 +000011759 for (int i = 0; i < kElementCount; i++) {
Steve Blockd0582a62009-12-15 09:54:21 +000011760 pixels->set(i, i % 256);
Steve Blocka7e24c12009-10-30 11:49:00 +000011761 }
Steve Block44f0eee2011-05-26 01:26:41 +010011762 HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
Steve Blocka7e24c12009-10-30 11:49:00 +000011763 for (int i = 0; i < kElementCount; i++) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011764 CHECK_EQ(i % 256, pixels->get_scalar(i));
Steve Blockd0582a62009-12-15 09:54:21 +000011765 CHECK_EQ(i % 256, pixel_data[i]);
Steve Blocka7e24c12009-10-30 11:49:00 +000011766 }
11767
11768 v8::Handle<v8::Object> obj = v8::Object::New();
11769 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
11770 // Set the elements to be the pixels.
11771 // jsobj->set_elements(*pixels);
11772 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
John Reck59135872010-11-02 12:39:01 -070011773 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011774 obj->Set(v8_str("field"), v8::Int32::New(1503));
11775 context->Global()->Set(v8_str("pixels"), obj);
11776 v8::Handle<v8::Value> result = CompileRun("pixels.field");
11777 CHECK_EQ(1503, result->Int32Value());
11778 result = CompileRun("pixels[1]");
11779 CHECK_EQ(1, result->Int32Value());
11780
11781 result = CompileRun("var sum = 0;"
11782 "for (var i = 0; i < 8; i++) {"
11783 " sum += pixels[i] = pixels[i] = -i;"
11784 "}"
11785 "sum;");
11786 CHECK_EQ(-28, result->Int32Value());
11787
11788 result = CompileRun("var sum = 0;"
11789 "for (var i = 0; i < 8; i++) {"
11790 " sum += pixels[i] = pixels[i] = 0;"
11791 "}"
11792 "sum;");
11793 CHECK_EQ(0, result->Int32Value());
11794
11795 result = CompileRun("var sum = 0;"
11796 "for (var i = 0; i < 8; i++) {"
11797 " sum += pixels[i] = pixels[i] = 255;"
11798 "}"
11799 "sum;");
11800 CHECK_EQ(8 * 255, result->Int32Value());
11801
11802 result = CompileRun("var sum = 0;"
11803 "for (var i = 0; i < 8; i++) {"
11804 " sum += pixels[i] = pixels[i] = 256 + i;"
11805 "}"
11806 "sum;");
11807 CHECK_EQ(2076, result->Int32Value());
11808
11809 result = CompileRun("var sum = 0;"
11810 "for (var i = 0; i < 8; i++) {"
11811 " sum += pixels[i] = pixels[i] = i;"
11812 "}"
11813 "sum;");
11814 CHECK_EQ(28, result->Int32Value());
11815
11816 result = CompileRun("var sum = 0;"
11817 "for (var i = 0; i < 8; i++) {"
11818 " sum += pixels[i];"
11819 "}"
11820 "sum;");
11821 CHECK_EQ(28, result->Int32Value());
11822
11823 i::Handle<i::Smi> value(i::Smi::FromInt(2));
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011824 i::SetElement(jsobj, 1, value, i::kNonStrictMode);
John Reck59135872010-11-02 12:39:01 -070011825 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011826 *value.location() = i::Smi::FromInt(256);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011827 i::SetElement(jsobj, 1, value, i::kNonStrictMode);
John Reck59135872010-11-02 12:39:01 -070011828 CHECK_EQ(255,
11829 i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011830 *value.location() = i::Smi::FromInt(-1);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011831 i::SetElement(jsobj, 1, value, i::kNonStrictMode);
John Reck59135872010-11-02 12:39:01 -070011832 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011833
11834 result = CompileRun("for (var i = 0; i < 8; i++) {"
11835 " pixels[i] = (i * 65) - 109;"
11836 "}"
11837 "pixels[1] + pixels[6];");
11838 CHECK_EQ(255, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070011839 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
11840 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
11841 CHECK_EQ(21,
11842 i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
11843 CHECK_EQ(86,
11844 i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
11845 CHECK_EQ(151,
11846 i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
11847 CHECK_EQ(216,
11848 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
11849 CHECK_EQ(255,
11850 i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
11851 CHECK_EQ(255,
11852 i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011853 result = CompileRun("var sum = 0;"
11854 "for (var i = 0; i < 8; i++) {"
11855 " sum += pixels[i];"
11856 "}"
11857 "sum;");
11858 CHECK_EQ(984, result->Int32Value());
11859
11860 result = CompileRun("for (var i = 0; i < 8; i++) {"
11861 " pixels[i] = (i * 1.1);"
11862 "}"
11863 "pixels[1] + pixels[6];");
11864 CHECK_EQ(8, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070011865 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
11866 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
11867 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
11868 CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
11869 CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
11870 CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
11871 CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
11872 CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011873
11874 result = CompileRun("for (var i = 0; i < 8; i++) {"
11875 " pixels[7] = undefined;"
11876 "}"
11877 "pixels[7];");
11878 CHECK_EQ(0, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070011879 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011880
11881 result = CompileRun("for (var i = 0; i < 8; i++) {"
11882 " pixels[6] = '2.3';"
11883 "}"
11884 "pixels[6];");
11885 CHECK_EQ(2, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070011886 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011887
11888 result = CompileRun("for (var i = 0; i < 8; i++) {"
11889 " pixels[5] = NaN;"
11890 "}"
11891 "pixels[5];");
11892 CHECK_EQ(0, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070011893 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011894
11895 result = CompileRun("for (var i = 0; i < 8; i++) {"
11896 " pixels[8] = Infinity;"
11897 "}"
11898 "pixels[8];");
11899 CHECK_EQ(255, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070011900 CHECK_EQ(255,
11901 i::Smi::cast(jsobj->GetElement(8)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011902
11903 result = CompileRun("for (var i = 0; i < 8; i++) {"
11904 " pixels[9] = -Infinity;"
11905 "}"
11906 "pixels[9];");
11907 CHECK_EQ(0, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070011908 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011909
11910 result = CompileRun("pixels[3] = 33;"
11911 "delete pixels[3];"
11912 "pixels[3];");
11913 CHECK_EQ(33, result->Int32Value());
11914
11915 result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
11916 "pixels[2] = 12; pixels[3] = 13;"
11917 "pixels.__defineGetter__('2',"
11918 "function() { return 120; });"
11919 "pixels[2];");
11920 CHECK_EQ(12, result->Int32Value());
11921
11922 result = CompileRun("var js_array = new Array(40);"
11923 "js_array[0] = 77;"
11924 "js_array;");
11925 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
11926
11927 result = CompileRun("pixels[1] = 23;"
11928 "pixels.__proto__ = [];"
11929 "js_array.__proto__ = pixels;"
11930 "js_array.concat(pixels);");
11931 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
11932 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
11933
11934 result = CompileRun("pixels[1] = 23;");
11935 CHECK_EQ(23, result->Int32Value());
11936
Steve Blockd0582a62009-12-15 09:54:21 +000011937 // Test for index greater than 255. Regression test for:
11938 // http://code.google.com/p/chromium/issues/detail?id=26337.
11939 result = CompileRun("pixels[256] = 255;");
11940 CHECK_EQ(255, result->Int32Value());
11941 result = CompileRun("var i = 0;"
11942 "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
11943 "i");
11944 CHECK_EQ(255, result->Int32Value());
11945
Steve Block1e0659c2011-05-24 12:43:12 +010011946 // Make sure that pixel array ICs recognize when a non-pixel array
11947 // is passed to it.
11948 result = CompileRun("function pa_load(p) {"
11949 " var sum = 0;"
11950 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
11951 " return sum;"
11952 "}"
11953 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11954 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
11955 "just_ints = new Object();"
11956 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11957 "for (var i = 0; i < 10; ++i) {"
11958 " result = pa_load(just_ints);"
11959 "}"
11960 "result");
11961 CHECK_EQ(32640, result->Int32Value());
11962
11963 // Make sure that pixel array ICs recognize out-of-bound accesses.
11964 result = CompileRun("function pa_load(p, start) {"
11965 " var sum = 0;"
11966 " for (var j = start; j < 256; j++) { sum += p[j]; }"
11967 " return sum;"
11968 "}"
11969 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11970 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
11971 "for (var i = 0; i < 10; ++i) {"
11972 " result = pa_load(pixels,-10);"
11973 "}"
11974 "result");
11975 CHECK_EQ(0, result->Int32Value());
11976
11977 // Make sure that generic ICs properly handles a pixel array.
11978 result = CompileRun("function pa_load(p) {"
11979 " var sum = 0;"
11980 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
11981 " return sum;"
11982 "}"
11983 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11984 "just_ints = new Object();"
11985 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11986 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
11987 "for (var i = 0; i < 10; ++i) {"
11988 " result = pa_load(pixels);"
11989 "}"
11990 "result");
11991 CHECK_EQ(32640, result->Int32Value());
11992
11993 // Make sure that generic load ICs recognize out-of-bound accesses in
11994 // pixel arrays.
11995 result = CompileRun("function pa_load(p, start) {"
11996 " var sum = 0;"
11997 " for (var j = start; j < 256; j++) { sum += p[j]; }"
11998 " return sum;"
11999 "}"
12000 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12001 "just_ints = new Object();"
12002 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12003 "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
12004 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
12005 "for (var i = 0; i < 10; ++i) {"
12006 " result = pa_load(pixels,-10);"
12007 "}"
12008 "result");
12009 CHECK_EQ(0, result->Int32Value());
12010
12011 // Make sure that generic ICs properly handles other types than pixel
12012 // arrays (that the inlined fast pixel array test leaves the right information
12013 // in the right registers).
12014 result = CompileRun("function pa_load(p) {"
12015 " var sum = 0;"
12016 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
12017 " return sum;"
12018 "}"
12019 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12020 "just_ints = new Object();"
12021 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12022 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
12023 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
12024 "sparse_array = new Object();"
12025 "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
12026 "sparse_array[1000000] = 3;"
12027 "for (var i = 0; i < 10; ++i) {"
12028 " result = pa_load(sparse_array);"
12029 "}"
12030 "result");
12031 CHECK_EQ(32640, result->Int32Value());
12032
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012033 // Make sure that pixel array store ICs clamp values correctly.
12034 result = CompileRun("function pa_store(p) {"
12035 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
12036 "}"
12037 "pa_store(pixels);"
12038 "var sum = 0;"
12039 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
12040 "sum");
12041 CHECK_EQ(48896, result->Int32Value());
12042
12043 // Make sure that pixel array stores correctly handle accesses outside
12044 // of the pixel array..
12045 result = CompileRun("function pa_store(p,start) {"
12046 " for (var j = 0; j < 256; j++) {"
12047 " p[j+start] = j * 2;"
12048 " }"
12049 "}"
12050 "pa_store(pixels,0);"
12051 "pa_store(pixels,-128);"
12052 "var sum = 0;"
12053 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
12054 "sum");
12055 CHECK_EQ(65280, result->Int32Value());
12056
12057 // Make sure that the generic store stub correctly handle accesses outside
12058 // of the pixel array..
12059 result = CompileRun("function pa_store(p,start) {"
12060 " for (var j = 0; j < 256; j++) {"
12061 " p[j+start] = j * 2;"
12062 " }"
12063 "}"
12064 "pa_store(pixels,0);"
12065 "just_ints = new Object();"
12066 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12067 "pa_store(just_ints, 0);"
12068 "pa_store(pixels,-128);"
12069 "var sum = 0;"
12070 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
12071 "sum");
12072 CHECK_EQ(65280, result->Int32Value());
12073
12074 // Make sure that the generic keyed store stub clamps pixel array values
12075 // correctly.
12076 result = CompileRun("function pa_store(p) {"
12077 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
12078 "}"
12079 "pa_store(pixels);"
12080 "just_ints = new Object();"
12081 "pa_store(just_ints);"
12082 "pa_store(pixels);"
12083 "var sum = 0;"
12084 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
12085 "sum");
12086 CHECK_EQ(48896, result->Int32Value());
12087
12088 // Make sure that pixel array loads are optimized by crankshaft.
Steve Block1e0659c2011-05-24 12:43:12 +010012089 result = CompileRun("function pa_load(p) {"
12090 " var sum = 0;"
12091 " for (var i=0; i<256; ++i) {"
12092 " sum += p[i];"
12093 " }"
12094 " return sum; "
12095 "}"
12096 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
Steve Block44f0eee2011-05-26 01:26:41 +010012097 "for (var i = 0; i < 5000; ++i) {"
Steve Block1e0659c2011-05-24 12:43:12 +010012098 " result = pa_load(pixels);"
12099 "}"
12100 "result");
12101 CHECK_EQ(32640, result->Int32Value());
12102
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012103 // Make sure that pixel array stores are optimized by crankshaft.
12104 result = CompileRun("function pa_init(p) {"
12105 "for (var i = 0; i < 256; ++i) { p[i] = i; }"
12106 "}"
12107 "function pa_load(p) {"
12108 " var sum = 0;"
12109 " for (var i=0; i<256; ++i) {"
12110 " sum += p[i];"
12111 " }"
12112 " return sum; "
12113 "}"
Steve Block44f0eee2011-05-26 01:26:41 +010012114 "for (var i = 0; i < 5000; ++i) {"
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012115 " pa_init(pixels);"
12116 "}"
12117 "result = pa_load(pixels);"
12118 "result");
12119 CHECK_EQ(32640, result->Int32Value());
12120
Steve Blocka7e24c12009-10-30 11:49:00 +000012121 free(pixel_data);
12122}
12123
12124
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010012125THREADED_TEST(PixelArrayInfo) {
12126 v8::HandleScope scope;
12127 LocalContext context;
12128 for (int size = 0; size < 100; size += 10) {
12129 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
12130 v8::Handle<v8::Object> obj = v8::Object::New();
12131 obj->SetIndexedPropertiesToPixelData(pixel_data, size);
12132 CHECK(obj->HasIndexedPropertiesInPixelData());
12133 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
12134 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
12135 free(pixel_data);
12136 }
12137}
12138
12139
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012140static v8::Handle<Value> NotHandledIndexedPropertyGetter(
12141 uint32_t index,
12142 const AccessorInfo& info) {
12143 ApiTestFuzzer::Fuzz();
12144 return v8::Handle<Value>();
12145}
12146
12147
12148static v8::Handle<Value> NotHandledIndexedPropertySetter(
12149 uint32_t index,
12150 Local<Value> value,
12151 const AccessorInfo& info) {
12152 ApiTestFuzzer::Fuzz();
12153 return v8::Handle<Value>();
12154}
12155
12156
12157THREADED_TEST(PixelArrayWithInterceptor) {
12158 v8::HandleScope scope;
12159 LocalContext context;
12160 const int kElementCount = 260;
12161 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
Steve Block44f0eee2011-05-26 01:26:41 +010012162 i::Handle<i::ExternalPixelArray> pixels =
12163 i::Handle<i::ExternalPixelArray>::cast(
12164 FACTORY->NewExternalArray(kElementCount,
12165 v8::kExternalPixelArray,
12166 pixel_data));
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012167 for (int i = 0; i < kElementCount; i++) {
12168 pixels->set(i, i % 256);
12169 }
12170 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12171 templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
12172 NotHandledIndexedPropertySetter);
12173 v8::Handle<v8::Object> obj = templ->NewInstance();
12174 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
12175 context->Global()->Set(v8_str("pixels"), obj);
12176 v8::Handle<v8::Value> result = CompileRun("pixels[1]");
12177 CHECK_EQ(1, result->Int32Value());
12178 result = CompileRun("var sum = 0;"
12179 "for (var i = 0; i < 8; i++) {"
12180 " sum += pixels[i] = pixels[i] = -i;"
12181 "}"
12182 "sum;");
12183 CHECK_EQ(-28, result->Int32Value());
12184 result = CompileRun("pixels.hasOwnProperty('1')");
12185 CHECK(result->BooleanValue());
12186 free(pixel_data);
12187}
12188
12189
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010012190static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
12191 switch (array_type) {
12192 case v8::kExternalByteArray:
12193 case v8::kExternalUnsignedByteArray:
Steve Block44f0eee2011-05-26 01:26:41 +010012194 case v8::kExternalPixelArray:
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010012195 return 1;
12196 break;
12197 case v8::kExternalShortArray:
12198 case v8::kExternalUnsignedShortArray:
12199 return 2;
12200 break;
12201 case v8::kExternalIntArray:
12202 case v8::kExternalUnsignedIntArray:
12203 case v8::kExternalFloatArray:
12204 return 4;
12205 break;
Ben Murdoch257744e2011-11-30 15:57:28 +000012206 case v8::kExternalDoubleArray:
12207 return 8;
12208 break;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010012209 default:
12210 UNREACHABLE();
12211 return -1;
12212 }
12213 UNREACHABLE();
12214 return -1;
12215}
12216
12217
Steve Block3ce2e202009-11-05 08:53:23 +000012218template <class ExternalArrayClass, class ElementType>
12219static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
12220 int64_t low,
12221 int64_t high) {
12222 v8::HandleScope scope;
12223 LocalContext context;
12224 const int kElementCount = 40;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010012225 int element_size = ExternalArrayElementSize(array_type);
Steve Block3ce2e202009-11-05 08:53:23 +000012226 ElementType* array_data =
12227 static_cast<ElementType*>(malloc(kElementCount * element_size));
12228 i::Handle<ExternalArrayClass> array =
12229 i::Handle<ExternalArrayClass>::cast(
Steve Block44f0eee2011-05-26 01:26:41 +010012230 FACTORY->NewExternalArray(kElementCount, array_type, array_data));
12231 HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
Steve Block3ce2e202009-11-05 08:53:23 +000012232 for (int i = 0; i < kElementCount; i++) {
12233 array->set(i, static_cast<ElementType>(i));
12234 }
Steve Block44f0eee2011-05-26 01:26:41 +010012235 HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
Steve Block3ce2e202009-11-05 08:53:23 +000012236 for (int i = 0; i < kElementCount; i++) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012237 CHECK_EQ(static_cast<int64_t>(i),
12238 static_cast<int64_t>(array->get_scalar(i)));
Steve Block3ce2e202009-11-05 08:53:23 +000012239 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
12240 }
12241
12242 v8::Handle<v8::Object> obj = v8::Object::New();
12243 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
12244 // Set the elements to be the external array.
12245 obj->SetIndexedPropertiesToExternalArrayData(array_data,
12246 array_type,
12247 kElementCount);
John Reck59135872010-11-02 12:39:01 -070012248 CHECK_EQ(
12249 1, static_cast<int>(jsobj->GetElement(1)->ToObjectChecked()->Number()));
Steve Block3ce2e202009-11-05 08:53:23 +000012250 obj->Set(v8_str("field"), v8::Int32::New(1503));
12251 context->Global()->Set(v8_str("ext_array"), obj);
12252 v8::Handle<v8::Value> result = CompileRun("ext_array.field");
12253 CHECK_EQ(1503, result->Int32Value());
12254 result = CompileRun("ext_array[1]");
12255 CHECK_EQ(1, result->Int32Value());
12256
12257 // Check pass through of assigned smis
12258 result = CompileRun("var sum = 0;"
12259 "for (var i = 0; i < 8; i++) {"
12260 " sum += ext_array[i] = ext_array[i] = -i;"
12261 "}"
12262 "sum;");
12263 CHECK_EQ(-28, result->Int32Value());
12264
12265 // Check assigned smis
12266 result = CompileRun("for (var i = 0; i < 8; i++) {"
12267 " ext_array[i] = i;"
12268 "}"
12269 "var sum = 0;"
12270 "for (var i = 0; i < 8; i++) {"
12271 " sum += ext_array[i];"
12272 "}"
12273 "sum;");
12274 CHECK_EQ(28, result->Int32Value());
12275
12276 // Check assigned smis in reverse order
12277 result = CompileRun("for (var i = 8; --i >= 0; ) {"
12278 " ext_array[i] = i;"
12279 "}"
12280 "var sum = 0;"
12281 "for (var i = 0; i < 8; i++) {"
12282 " sum += ext_array[i];"
12283 "}"
12284 "sum;");
12285 CHECK_EQ(28, result->Int32Value());
12286
12287 // Check pass through of assigned HeapNumbers
12288 result = CompileRun("var sum = 0;"
12289 "for (var i = 0; i < 16; i+=2) {"
12290 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
12291 "}"
12292 "sum;");
12293 CHECK_EQ(-28, result->Int32Value());
12294
12295 // Check assigned HeapNumbers
12296 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
12297 " ext_array[i] = (i * 0.5);"
12298 "}"
12299 "var sum = 0;"
12300 "for (var i = 0; i < 16; i+=2) {"
12301 " sum += ext_array[i];"
12302 "}"
12303 "sum;");
12304 CHECK_EQ(28, result->Int32Value());
12305
12306 // Check assigned HeapNumbers in reverse order
12307 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
12308 " ext_array[i] = (i * 0.5);"
12309 "}"
12310 "var sum = 0;"
12311 "for (var i = 0; i < 16; i+=2) {"
12312 " sum += ext_array[i];"
12313 "}"
12314 "sum;");
12315 CHECK_EQ(28, result->Int32Value());
12316
12317 i::ScopedVector<char> test_buf(1024);
12318
12319 // Check legal boundary conditions.
12320 // The repeated loads and stores ensure the ICs are exercised.
12321 const char* boundary_program =
12322 "var res = 0;"
12323 "for (var i = 0; i < 16; i++) {"
12324 " ext_array[i] = %lld;"
12325 " if (i > 8) {"
12326 " res = ext_array[i];"
12327 " }"
12328 "}"
12329 "res;";
12330 i::OS::SNPrintF(test_buf,
12331 boundary_program,
12332 low);
12333 result = CompileRun(test_buf.start());
12334 CHECK_EQ(low, result->IntegerValue());
12335
12336 i::OS::SNPrintF(test_buf,
12337 boundary_program,
12338 high);
12339 result = CompileRun(test_buf.start());
12340 CHECK_EQ(high, result->IntegerValue());
12341
12342 // Check misprediction of type in IC.
12343 result = CompileRun("var tmp_array = ext_array;"
12344 "var sum = 0;"
12345 "for (var i = 0; i < 8; i++) {"
12346 " tmp_array[i] = i;"
12347 " sum += tmp_array[i];"
12348 " if (i == 4) {"
12349 " tmp_array = {};"
12350 " }"
12351 "}"
12352 "sum;");
Steve Block44f0eee2011-05-26 01:26:41 +010012353 HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
Steve Block3ce2e202009-11-05 08:53:23 +000012354 CHECK_EQ(28, result->Int32Value());
12355
12356 // Make sure out-of-range loads do not throw.
12357 i::OS::SNPrintF(test_buf,
12358 "var caught_exception = false;"
12359 "try {"
12360 " ext_array[%d];"
12361 "} catch (e) {"
12362 " caught_exception = true;"
12363 "}"
12364 "caught_exception;",
12365 kElementCount);
12366 result = CompileRun(test_buf.start());
12367 CHECK_EQ(false, result->BooleanValue());
12368
12369 // Make sure out-of-range stores do not throw.
12370 i::OS::SNPrintF(test_buf,
12371 "var caught_exception = false;"
12372 "try {"
12373 " ext_array[%d] = 1;"
12374 "} catch (e) {"
12375 " caught_exception = true;"
12376 "}"
12377 "caught_exception;",
12378 kElementCount);
12379 result = CompileRun(test_buf.start());
12380 CHECK_EQ(false, result->BooleanValue());
12381
12382 // Check other boundary conditions, values and operations.
12383 result = CompileRun("for (var i = 0; i < 8; i++) {"
12384 " ext_array[7] = undefined;"
12385 "}"
12386 "ext_array[7];");
12387 CHECK_EQ(0, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070012388 CHECK_EQ(
12389 0, static_cast<int>(jsobj->GetElement(7)->ToObjectChecked()->Number()));
Steve Block3ce2e202009-11-05 08:53:23 +000012390
12391 result = CompileRun("for (var i = 0; i < 8; i++) {"
12392 " ext_array[6] = '2.3';"
12393 "}"
12394 "ext_array[6];");
12395 CHECK_EQ(2, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070012396 CHECK_EQ(
12397 2, static_cast<int>(jsobj->GetElement(6)->ToObjectChecked()->Number()));
Steve Block3ce2e202009-11-05 08:53:23 +000012398
Ben Murdoch257744e2011-11-30 15:57:28 +000012399 if (array_type != v8::kExternalFloatArray &&
12400 array_type != v8::kExternalDoubleArray) {
Steve Block3ce2e202009-11-05 08:53:23 +000012401 // Though the specification doesn't state it, be explicit about
12402 // converting NaNs and +/-Infinity to zero.
12403 result = CompileRun("for (var i = 0; i < 8; i++) {"
12404 " ext_array[i] = 5;"
12405 "}"
12406 "for (var i = 0; i < 8; i++) {"
12407 " ext_array[i] = NaN;"
12408 "}"
12409 "ext_array[5];");
12410 CHECK_EQ(0, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070012411 CHECK_EQ(0,
12412 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
Steve Block3ce2e202009-11-05 08:53:23 +000012413
12414 result = CompileRun("for (var i = 0; i < 8; i++) {"
12415 " ext_array[i] = 5;"
12416 "}"
12417 "for (var i = 0; i < 8; i++) {"
12418 " ext_array[i] = Infinity;"
12419 "}"
12420 "ext_array[5];");
Steve Block44f0eee2011-05-26 01:26:41 +010012421 int expected_value =
12422 (array_type == v8::kExternalPixelArray) ? 255 : 0;
12423 CHECK_EQ(expected_value, result->Int32Value());
12424 CHECK_EQ(expected_value,
John Reck59135872010-11-02 12:39:01 -070012425 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
Steve Block3ce2e202009-11-05 08:53:23 +000012426
12427 result = CompileRun("for (var i = 0; i < 8; i++) {"
12428 " ext_array[i] = 5;"
12429 "}"
12430 "for (var i = 0; i < 8; i++) {"
12431 " ext_array[i] = -Infinity;"
12432 "}"
12433 "ext_array[5];");
12434 CHECK_EQ(0, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070012435 CHECK_EQ(0,
12436 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
Steve Block1e0659c2011-05-24 12:43:12 +010012437
12438 // Check truncation behavior of integral arrays.
12439 const char* unsigned_data =
12440 "var source_data = [0.6, 10.6];"
12441 "var expected_results = [0, 10];";
12442 const char* signed_data =
12443 "var source_data = [0.6, 10.6, -0.6, -10.6];"
12444 "var expected_results = [0, 10, 0, -10];";
Steve Block44f0eee2011-05-26 01:26:41 +010012445 const char* pixel_data =
12446 "var source_data = [0.6, 10.6];"
12447 "var expected_results = [1, 11];";
Steve Block1e0659c2011-05-24 12:43:12 +010012448 bool is_unsigned =
12449 (array_type == v8::kExternalUnsignedByteArray ||
12450 array_type == v8::kExternalUnsignedShortArray ||
12451 array_type == v8::kExternalUnsignedIntArray);
Steve Block44f0eee2011-05-26 01:26:41 +010012452 bool is_pixel_data = array_type == v8::kExternalPixelArray;
Steve Block1e0659c2011-05-24 12:43:12 +010012453
12454 i::OS::SNPrintF(test_buf,
12455 "%s"
12456 "var all_passed = true;"
12457 "for (var i = 0; i < source_data.length; i++) {"
12458 " for (var j = 0; j < 8; j++) {"
12459 " ext_array[j] = source_data[i];"
12460 " }"
12461 " all_passed = all_passed &&"
12462 " (ext_array[5] == expected_results[i]);"
12463 "}"
12464 "all_passed;",
Steve Block44f0eee2011-05-26 01:26:41 +010012465 (is_unsigned ?
12466 unsigned_data :
12467 (is_pixel_data ? pixel_data : signed_data)));
Steve Block1e0659c2011-05-24 12:43:12 +010012468 result = CompileRun(test_buf.start());
12469 CHECK_EQ(true, result->BooleanValue());
Steve Block3ce2e202009-11-05 08:53:23 +000012470 }
12471
Ben Murdoch8b112d22011-06-08 16:22:53 +010012472 for (int i = 0; i < kElementCount; i++) {
12473 array->set(i, static_cast<ElementType>(i));
12474 }
12475 // Test complex assignments
12476 result = CompileRun("function ee_op_test_complex_func(sum) {"
12477 " for (var i = 0; i < 40; ++i) {"
12478 " sum += (ext_array[i] += 1);"
12479 " sum += (ext_array[i] -= 1);"
12480 " } "
12481 " return sum;"
12482 "}"
12483 "sum=0;"
12484 "for (var i=0;i<10000;++i) {"
12485 " sum=ee_op_test_complex_func(sum);"
12486 "}"
12487 "sum;");
12488 CHECK_EQ(16000000, result->Int32Value());
12489
12490 // Test count operations
12491 result = CompileRun("function ee_op_test_count_func(sum) {"
12492 " for (var i = 0; i < 40; ++i) {"
12493 " sum += (++ext_array[i]);"
12494 " sum += (--ext_array[i]);"
12495 " } "
12496 " return sum;"
12497 "}"
12498 "sum=0;"
12499 "for (var i=0;i<10000;++i) {"
12500 " sum=ee_op_test_count_func(sum);"
12501 "}"
12502 "sum;");
12503 CHECK_EQ(16000000, result->Int32Value());
12504
Steve Block3ce2e202009-11-05 08:53:23 +000012505 result = CompileRun("ext_array[3] = 33;"
12506 "delete ext_array[3];"
12507 "ext_array[3];");
12508 CHECK_EQ(33, result->Int32Value());
12509
12510 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
12511 "ext_array[2] = 12; ext_array[3] = 13;"
12512 "ext_array.__defineGetter__('2',"
12513 "function() { return 120; });"
12514 "ext_array[2];");
12515 CHECK_EQ(12, result->Int32Value());
12516
12517 result = CompileRun("var js_array = new Array(40);"
12518 "js_array[0] = 77;"
12519 "js_array;");
12520 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
12521
12522 result = CompileRun("ext_array[1] = 23;"
12523 "ext_array.__proto__ = [];"
12524 "js_array.__proto__ = ext_array;"
12525 "js_array.concat(ext_array);");
12526 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
12527 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
12528
12529 result = CompileRun("ext_array[1] = 23;");
12530 CHECK_EQ(23, result->Int32Value());
12531
Steve Blockd0582a62009-12-15 09:54:21 +000012532 // Test more complex manipulations which cause eax to contain values
12533 // that won't be completely overwritten by loads from the arrays.
12534 // This catches bugs in the instructions used for the KeyedLoadIC
12535 // for byte and word types.
12536 {
12537 const int kXSize = 300;
12538 const int kYSize = 300;
12539 const int kLargeElementCount = kXSize * kYSize * 4;
12540 ElementType* large_array_data =
12541 static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
12542 i::Handle<ExternalArrayClass> large_array =
12543 i::Handle<ExternalArrayClass>::cast(
Steve Block44f0eee2011-05-26 01:26:41 +010012544 FACTORY->NewExternalArray(kLargeElementCount,
Steve Blockd0582a62009-12-15 09:54:21 +000012545 array_type,
12546 array_data));
12547 v8::Handle<v8::Object> large_obj = v8::Object::New();
12548 // Set the elements to be the external array.
12549 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
12550 array_type,
12551 kLargeElementCount);
12552 context->Global()->Set(v8_str("large_array"), large_obj);
12553 // Initialize contents of a few rows.
12554 for (int x = 0; x < 300; x++) {
12555 int row = 0;
12556 int offset = row * 300 * 4;
12557 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
12558 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
12559 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
12560 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
12561 row = 150;
12562 offset = row * 300 * 4;
12563 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
12564 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
12565 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
12566 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
12567 row = 298;
12568 offset = row * 300 * 4;
12569 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
12570 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
12571 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
12572 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
12573 }
12574 // The goal of the code below is to make "offset" large enough
12575 // that the computation of the index (which goes into eax) has
12576 // high bits set which will not be overwritten by a byte or short
12577 // load.
12578 result = CompileRun("var failed = false;"
12579 "var offset = 0;"
12580 "for (var i = 0; i < 300; i++) {"
12581 " if (large_array[4 * i] != 127 ||"
12582 " large_array[4 * i + 1] != 0 ||"
12583 " large_array[4 * i + 2] != 0 ||"
12584 " large_array[4 * i + 3] != 127) {"
12585 " failed = true;"
12586 " }"
12587 "}"
12588 "offset = 150 * 300 * 4;"
12589 "for (var i = 0; i < 300; i++) {"
12590 " if (large_array[offset + 4 * i] != 127 ||"
12591 " large_array[offset + 4 * i + 1] != 0 ||"
12592 " large_array[offset + 4 * i + 2] != 0 ||"
12593 " large_array[offset + 4 * i + 3] != 127) {"
12594 " failed = true;"
12595 " }"
12596 "}"
12597 "offset = 298 * 300 * 4;"
12598 "for (var i = 0; i < 300; i++) {"
12599 " if (large_array[offset + 4 * i] != 127 ||"
12600 " large_array[offset + 4 * i + 1] != 0 ||"
12601 " large_array[offset + 4 * i + 2] != 0 ||"
12602 " large_array[offset + 4 * i + 3] != 127) {"
12603 " failed = true;"
12604 " }"
12605 "}"
12606 "!failed;");
12607 CHECK_EQ(true, result->BooleanValue());
12608 free(large_array_data);
12609 }
12610
Steve Block44f0eee2011-05-26 01:26:41 +010012611 // The "" property descriptor is overloaded to store information about
12612 // the external array. Ensure that setting and accessing the "" property
12613 // works (it should overwrite the information cached about the external
12614 // array in the DescriptorArray) in various situations.
12615 result = CompileRun("ext_array[''] = 23; ext_array['']");
12616 CHECK_EQ(23, result->Int32Value());
12617
12618 // Property "" set after the external array is associated with the object.
12619 {
12620 v8::Handle<v8::Object> obj2 = v8::Object::New();
12621 obj2->Set(v8_str("ee_test_field"), v8::Int32::New(256));
12622 obj2->Set(v8_str(""), v8::Int32::New(1503));
12623 // Set the elements to be the external array.
12624 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
12625 array_type,
12626 kElementCount);
12627 context->Global()->Set(v8_str("ext_array"), obj2);
12628 result = CompileRun("ext_array['']");
12629 CHECK_EQ(1503, result->Int32Value());
12630 }
12631
12632 // Property "" set after the external array is associated with the object.
12633 {
12634 v8::Handle<v8::Object> obj2 = v8::Object::New();
12635 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
12636 // Set the elements to be the external array.
12637 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
12638 array_type,
12639 kElementCount);
12640 obj2->Set(v8_str(""), v8::Int32::New(1503));
12641 context->Global()->Set(v8_str("ext_array"), obj2);
12642 result = CompileRun("ext_array['']");
12643 CHECK_EQ(1503, result->Int32Value());
12644 }
12645
12646 // Should reuse the map from previous test.
12647 {
12648 v8::Handle<v8::Object> obj2 = v8::Object::New();
12649 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
12650 // Set the elements to be the external array. Should re-use the map
12651 // from previous test.
12652 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
12653 array_type,
12654 kElementCount);
12655 context->Global()->Set(v8_str("ext_array"), obj2);
12656 result = CompileRun("ext_array['']");
12657 }
12658
12659 // Property "" is a constant function that shouldn't not be interfered with
12660 // when an external array is set.
12661 {
12662 v8::Handle<v8::Object> obj2 = v8::Object::New();
12663 // Start
12664 obj2->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
12665
12666 // Add a constant function to an object.
12667 context->Global()->Set(v8_str("ext_array"), obj2);
12668 result = CompileRun("ext_array[''] = function() {return 1503;};"
12669 "ext_array['']();");
12670
12671 // Add an external array transition to the same map that
12672 // has the constant transition.
12673 v8::Handle<v8::Object> obj3 = v8::Object::New();
12674 obj3->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
12675 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
12676 array_type,
12677 kElementCount);
12678 context->Global()->Set(v8_str("ext_array"), obj3);
12679 }
12680
12681 // If a external array transition is in the map, it should get clobbered
12682 // by a constant function.
12683 {
12684 // Add an external array transition.
12685 v8::Handle<v8::Object> obj3 = v8::Object::New();
12686 obj3->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
12687 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
12688 array_type,
12689 kElementCount);
12690
12691 // Add a constant function to the same map that just got an external array
12692 // transition.
12693 v8::Handle<v8::Object> obj2 = v8::Object::New();
12694 obj2->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
12695 context->Global()->Set(v8_str("ext_array"), obj2);
12696 result = CompileRun("ext_array[''] = function() {return 1503;};"
12697 "ext_array['']();");
12698 }
12699
Steve Block3ce2e202009-11-05 08:53:23 +000012700 free(array_data);
12701}
12702
12703
12704THREADED_TEST(ExternalByteArray) {
Steve Block8defd9f2010-07-08 12:39:36 +010012705 ExternalArrayTestHelper<i::ExternalByteArray, int8_t>(
Steve Block3ce2e202009-11-05 08:53:23 +000012706 v8::kExternalByteArray,
12707 -128,
12708 127);
12709}
12710
12711
12712THREADED_TEST(ExternalUnsignedByteArray) {
Steve Block8defd9f2010-07-08 12:39:36 +010012713 ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>(
Steve Block3ce2e202009-11-05 08:53:23 +000012714 v8::kExternalUnsignedByteArray,
12715 0,
12716 255);
12717}
12718
12719
Steve Block44f0eee2011-05-26 01:26:41 +010012720THREADED_TEST(ExternalPixelArray) {
12721 ExternalArrayTestHelper<i::ExternalPixelArray, uint8_t>(
12722 v8::kExternalPixelArray,
12723 0,
12724 255);
12725}
12726
12727
Steve Block3ce2e202009-11-05 08:53:23 +000012728THREADED_TEST(ExternalShortArray) {
Steve Block8defd9f2010-07-08 12:39:36 +010012729 ExternalArrayTestHelper<i::ExternalShortArray, int16_t>(
Steve Block3ce2e202009-11-05 08:53:23 +000012730 v8::kExternalShortArray,
12731 -32768,
12732 32767);
12733}
12734
12735
12736THREADED_TEST(ExternalUnsignedShortArray) {
Steve Block8defd9f2010-07-08 12:39:36 +010012737 ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>(
Steve Block3ce2e202009-11-05 08:53:23 +000012738 v8::kExternalUnsignedShortArray,
12739 0,
12740 65535);
12741}
12742
12743
12744THREADED_TEST(ExternalIntArray) {
Steve Block8defd9f2010-07-08 12:39:36 +010012745 ExternalArrayTestHelper<i::ExternalIntArray, int32_t>(
Steve Block3ce2e202009-11-05 08:53:23 +000012746 v8::kExternalIntArray,
12747 INT_MIN, // -2147483648
12748 INT_MAX); // 2147483647
12749}
12750
12751
12752THREADED_TEST(ExternalUnsignedIntArray) {
Steve Block8defd9f2010-07-08 12:39:36 +010012753 ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>(
Steve Block3ce2e202009-11-05 08:53:23 +000012754 v8::kExternalUnsignedIntArray,
12755 0,
12756 UINT_MAX); // 4294967295
12757}
12758
12759
12760THREADED_TEST(ExternalFloatArray) {
Steve Block8defd9f2010-07-08 12:39:36 +010012761 ExternalArrayTestHelper<i::ExternalFloatArray, float>(
Steve Block3ce2e202009-11-05 08:53:23 +000012762 v8::kExternalFloatArray,
12763 -500,
12764 500);
12765}
12766
12767
Ben Murdoch257744e2011-11-30 15:57:28 +000012768THREADED_TEST(ExternalDoubleArray) {
12769 ExternalArrayTestHelper<i::ExternalDoubleArray, double>(
12770 v8::kExternalDoubleArray,
12771 -500,
12772 500);
12773}
12774
12775
Steve Block3ce2e202009-11-05 08:53:23 +000012776THREADED_TEST(ExternalArrays) {
12777 TestExternalByteArray();
12778 TestExternalUnsignedByteArray();
12779 TestExternalShortArray();
12780 TestExternalUnsignedShortArray();
12781 TestExternalIntArray();
12782 TestExternalUnsignedIntArray();
12783 TestExternalFloatArray();
12784}
12785
12786
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010012787void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
12788 v8::HandleScope scope;
12789 LocalContext context;
12790 for (int size = 0; size < 100; size += 10) {
12791 int element_size = ExternalArrayElementSize(array_type);
12792 void* external_data = malloc(size * element_size);
12793 v8::Handle<v8::Object> obj = v8::Object::New();
12794 obj->SetIndexedPropertiesToExternalArrayData(
12795 external_data, array_type, size);
12796 CHECK(obj->HasIndexedPropertiesInExternalArrayData());
12797 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
12798 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
12799 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
12800 free(external_data);
12801 }
12802}
12803
12804
12805THREADED_TEST(ExternalArrayInfo) {
12806 ExternalArrayInfoTestHelper(v8::kExternalByteArray);
12807 ExternalArrayInfoTestHelper(v8::kExternalUnsignedByteArray);
12808 ExternalArrayInfoTestHelper(v8::kExternalShortArray);
12809 ExternalArrayInfoTestHelper(v8::kExternalUnsignedShortArray);
12810 ExternalArrayInfoTestHelper(v8::kExternalIntArray);
12811 ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray);
12812 ExternalArrayInfoTestHelper(v8::kExternalFloatArray);
Ben Murdoch257744e2011-11-30 15:57:28 +000012813 ExternalArrayInfoTestHelper(v8::kExternalDoubleArray);
Steve Block44f0eee2011-05-26 01:26:41 +010012814 ExternalArrayInfoTestHelper(v8::kExternalPixelArray);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010012815}
12816
12817
Steve Blocka7e24c12009-10-30 11:49:00 +000012818THREADED_TEST(ScriptContextDependence) {
12819 v8::HandleScope scope;
12820 LocalContext c1;
12821 const char *source = "foo";
12822 v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
12823 v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
12824 c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
12825 CHECK_EQ(dep->Run()->Int32Value(), 100);
12826 CHECK_EQ(indep->Run()->Int32Value(), 100);
12827 LocalContext c2;
12828 c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
12829 CHECK_EQ(dep->Run()->Int32Value(), 100);
12830 CHECK_EQ(indep->Run()->Int32Value(), 101);
12831}
12832
12833
12834THREADED_TEST(StackTrace) {
12835 v8::HandleScope scope;
12836 LocalContext context;
12837 v8::TryCatch try_catch;
12838 const char *source = "function foo() { FAIL.FAIL; }; foo();";
12839 v8::Handle<v8::String> src = v8::String::New(source);
12840 v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
12841 v8::Script::New(src, origin)->Run();
12842 CHECK(try_catch.HasCaught());
12843 v8::String::Utf8Value stack(try_catch.StackTrace());
12844 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
12845}
12846
12847
Kristian Monsen25f61362010-05-21 11:50:48 +010012848// Checks that a StackFrame has certain expected values.
12849void checkStackFrame(const char* expected_script_name,
12850 const char* expected_func_name, int expected_line_number,
12851 int expected_column, bool is_eval, bool is_constructor,
12852 v8::Handle<v8::StackFrame> frame) {
12853 v8::HandleScope scope;
12854 v8::String::Utf8Value func_name(frame->GetFunctionName());
12855 v8::String::Utf8Value script_name(frame->GetScriptName());
12856 if (*script_name == NULL) {
12857 // The situation where there is no associated script, like for evals.
12858 CHECK(expected_script_name == NULL);
12859 } else {
12860 CHECK(strstr(*script_name, expected_script_name) != NULL);
12861 }
12862 CHECK(strstr(*func_name, expected_func_name) != NULL);
12863 CHECK_EQ(expected_line_number, frame->GetLineNumber());
12864 CHECK_EQ(expected_column, frame->GetColumn());
12865 CHECK_EQ(is_eval, frame->IsEval());
12866 CHECK_EQ(is_constructor, frame->IsConstructor());
12867}
12868
12869
12870v8::Handle<Value> AnalyzeStackInNativeCode(const v8::Arguments& args) {
12871 v8::HandleScope scope;
12872 const char* origin = "capture-stack-trace-test";
12873 const int kOverviewTest = 1;
12874 const int kDetailedTest = 2;
12875
12876 ASSERT(args.Length() == 1);
12877
12878 int testGroup = args[0]->Int32Value();
12879 if (testGroup == kOverviewTest) {
12880 v8::Handle<v8::StackTrace> stackTrace =
12881 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
12882 CHECK_EQ(4, stackTrace->GetFrameCount());
12883 checkStackFrame(origin, "bar", 2, 10, false, false,
12884 stackTrace->GetFrame(0));
12885 checkStackFrame(origin, "foo", 6, 3, false, false,
12886 stackTrace->GetFrame(1));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012887 // This is the source string inside the eval which has the call to foo.
12888 checkStackFrame(NULL, "", 1, 5, false, false,
Kristian Monsen25f61362010-05-21 11:50:48 +010012889 stackTrace->GetFrame(2));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012890 // The last frame is an anonymous function which has the initial eval call.
Kristian Monsen25f61362010-05-21 11:50:48 +010012891 checkStackFrame(origin, "", 8, 7, false, false,
12892 stackTrace->GetFrame(3));
12893
12894 CHECK(stackTrace->AsArray()->IsArray());
12895 } else if (testGroup == kDetailedTest) {
12896 v8::Handle<v8::StackTrace> stackTrace =
12897 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
12898 CHECK_EQ(4, stackTrace->GetFrameCount());
12899 checkStackFrame(origin, "bat", 4, 22, false, false,
12900 stackTrace->GetFrame(0));
12901 checkStackFrame(origin, "baz", 8, 3, false, true,
12902 stackTrace->GetFrame(1));
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010012903#ifdef ENABLE_DEBUGGER_SUPPORT
12904 bool is_eval = true;
12905#else // ENABLE_DEBUGGER_SUPPORT
12906 bool is_eval = false;
12907#endif // ENABLE_DEBUGGER_SUPPORT
12908
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012909 // This is the source string inside the eval which has the call to baz.
12910 checkStackFrame(NULL, "", 1, 5, is_eval, false,
Kristian Monsen25f61362010-05-21 11:50:48 +010012911 stackTrace->GetFrame(2));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012912 // The last frame is an anonymous function which has the initial eval call.
Kristian Monsen25f61362010-05-21 11:50:48 +010012913 checkStackFrame(origin, "", 10, 1, false, false,
12914 stackTrace->GetFrame(3));
12915
12916 CHECK(stackTrace->AsArray()->IsArray());
12917 }
12918 return v8::Undefined();
12919}
12920
12921
12922// Tests the C++ StackTrace API.
Ben Murdochb0fe1622011-05-05 13:52:32 +010012923// TODO(3074796): Reenable this as a THREADED_TEST once it passes.
12924// THREADED_TEST(CaptureStackTrace) {
12925TEST(CaptureStackTrace) {
Kristian Monsen25f61362010-05-21 11:50:48 +010012926 v8::HandleScope scope;
12927 v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
12928 Local<ObjectTemplate> templ = ObjectTemplate::New();
12929 templ->Set(v8_str("AnalyzeStackInNativeCode"),
12930 v8::FunctionTemplate::New(AnalyzeStackInNativeCode));
12931 LocalContext context(0, templ);
12932
12933 // Test getting OVERVIEW information. Should ignore information that is not
12934 // script name, function name, line number, and column offset.
12935 const char *overview_source =
12936 "function bar() {\n"
12937 " var y; AnalyzeStackInNativeCode(1);\n"
12938 "}\n"
12939 "function foo() {\n"
12940 "\n"
12941 " bar();\n"
12942 "}\n"
12943 "var x;eval('new foo();');";
12944 v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
12945 v8::Handle<Value> overview_result =
12946 v8::Script::New(overview_src, origin)->Run();
12947 ASSERT(!overview_result.IsEmpty());
12948 ASSERT(overview_result->IsObject());
12949
12950 // Test getting DETAILED information.
12951 const char *detailed_source =
12952 "function bat() {AnalyzeStackInNativeCode(2);\n"
12953 "}\n"
12954 "\n"
12955 "function baz() {\n"
12956 " bat();\n"
12957 "}\n"
12958 "eval('new baz();');";
12959 v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
12960 // Make the script using a non-zero line and column offset.
12961 v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
12962 v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
12963 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
12964 v8::Handle<v8::Script> detailed_script(
12965 v8::Script::New(detailed_src, &detailed_origin));
12966 v8::Handle<Value> detailed_result = detailed_script->Run();
12967 ASSERT(!detailed_result.IsEmpty());
12968 ASSERT(detailed_result->IsObject());
12969}
12970
12971
Ben Murdoch3bec4d22010-07-22 14:51:16 +010012972static void StackTraceForUncaughtExceptionListener(
12973 v8::Handle<v8::Message> message,
12974 v8::Handle<Value>) {
12975 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
12976 CHECK_EQ(2, stack_trace->GetFrameCount());
12977 checkStackFrame("origin", "foo", 2, 3, false, false,
12978 stack_trace->GetFrame(0));
12979 checkStackFrame("origin", "bar", 5, 3, false, false,
12980 stack_trace->GetFrame(1));
12981}
12982
12983TEST(CaptureStackTraceForUncaughtException) {
12984 report_count = 0;
12985 v8::HandleScope scope;
12986 LocalContext env;
12987 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
12988 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
12989
12990 Script::Compile(v8_str("function foo() {\n"
12991 " throw 1;\n"
12992 "};\n"
12993 "function bar() {\n"
12994 " foo();\n"
12995 "};"),
12996 v8_str("origin"))->Run();
12997 v8::Local<v8::Object> global = env->Global();
12998 Local<Value> trouble = global->Get(v8_str("bar"));
12999 CHECK(trouble->IsFunction());
13000 Function::Cast(*trouble)->Call(global, 0, NULL);
13001 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
13002 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
13003}
13004
13005
Steve Block1e0659c2011-05-24 12:43:12 +010013006TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
13007 v8::HandleScope scope;
13008 LocalContext env;
13009 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
13010 1024,
13011 v8::StackTrace::kDetailed);
13012
13013 CompileRun(
13014 "var setters = ['column', 'lineNumber', 'scriptName',\n"
13015 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
13016 " 'isConstructor'];\n"
13017 "for (var i = 0; i < setters.length; i++) {\n"
13018 " var prop = setters[i];\n"
13019 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
13020 "}\n");
13021 CompileRun("throw 'exception';");
13022 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
13023}
13024
13025
Ben Murdochf87a2032010-10-22 12:50:53 +010013026v8::Handle<Value> AnalyzeStackOfEvalWithSourceURL(const v8::Arguments& args) {
13027 v8::HandleScope scope;
13028 v8::Handle<v8::StackTrace> stackTrace =
13029 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
13030 CHECK_EQ(5, stackTrace->GetFrameCount());
13031 v8::Handle<v8::String> url = v8_str("eval_url");
13032 for (int i = 0; i < 3; i++) {
13033 v8::Handle<v8::String> name =
13034 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
13035 CHECK(!name.IsEmpty());
13036 CHECK_EQ(url, name);
13037 }
13038 return v8::Undefined();
13039}
13040
13041
13042TEST(SourceURLInStackTrace) {
13043 v8::HandleScope scope;
13044 Local<ObjectTemplate> templ = ObjectTemplate::New();
13045 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
13046 v8::FunctionTemplate::New(AnalyzeStackOfEvalWithSourceURL));
13047 LocalContext context(0, templ);
13048
13049 const char *source =
13050 "function outer() {\n"
13051 "function bar() {\n"
13052 " AnalyzeStackOfEvalWithSourceURL();\n"
13053 "}\n"
13054 "function foo() {\n"
13055 "\n"
13056 " bar();\n"
13057 "}\n"
13058 "foo();\n"
13059 "}\n"
13060 "eval('(' + outer +')()//@ sourceURL=eval_url');";
13061 CHECK(CompileRun(source)->IsUndefined());
13062}
13063
13064
Steve Block3ce2e202009-11-05 08:53:23 +000013065// Test that idle notification can be handled and eventually returns true.
Steve Blocka7e24c12009-10-30 11:49:00 +000013066THREADED_TEST(IdleNotification) {
Steve Block3ce2e202009-11-05 08:53:23 +000013067 bool rv = false;
13068 for (int i = 0; i < 100; i++) {
13069 rv = v8::V8::IdleNotification();
13070 if (rv)
13071 break;
13072 }
13073 CHECK(rv == true);
Steve Blocka7e24c12009-10-30 11:49:00 +000013074}
13075
13076
13077static uint32_t* stack_limit;
13078
13079static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
Steve Block44f0eee2011-05-26 01:26:41 +010013080 stack_limit = reinterpret_cast<uint32_t*>(
13081 i::Isolate::Current()->stack_guard()->real_climit());
Steve Blocka7e24c12009-10-30 11:49:00 +000013082 return v8::Undefined();
13083}
13084
13085
13086// Uses the address of a local variable to determine the stack top now.
13087// Given a size, returns an address that is that far from the current
13088// top of stack.
13089static uint32_t* ComputeStackLimit(uint32_t size) {
13090 uint32_t* answer = &size - (size / sizeof(size));
13091 // If the size is very large and the stack is very near the bottom of
13092 // memory then the calculation above may wrap around and give an address
13093 // that is above the (downwards-growing) stack. In that case we return
13094 // a very low address.
13095 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
13096 return answer;
13097}
13098
13099
13100TEST(SetResourceConstraints) {
13101 static const int K = 1024;
13102 uint32_t* set_limit = ComputeStackLimit(128 * K);
13103
13104 // Set stack limit.
13105 v8::ResourceConstraints constraints;
13106 constraints.set_stack_limit(set_limit);
13107 CHECK(v8::SetResourceConstraints(&constraints));
13108
13109 // Execute a script.
13110 v8::HandleScope scope;
13111 LocalContext env;
13112 Local<v8::FunctionTemplate> fun_templ =
13113 v8::FunctionTemplate::New(GetStackLimitCallback);
13114 Local<Function> fun = fun_templ->GetFunction();
13115 env->Global()->Set(v8_str("get_stack_limit"), fun);
13116 CompileRun("get_stack_limit();");
13117
13118 CHECK(stack_limit == set_limit);
13119}
13120
13121
13122TEST(SetResourceConstraintsInThread) {
13123 uint32_t* set_limit;
13124 {
13125 v8::Locker locker;
13126 static const int K = 1024;
13127 set_limit = ComputeStackLimit(128 * K);
13128
13129 // Set stack limit.
13130 v8::ResourceConstraints constraints;
13131 constraints.set_stack_limit(set_limit);
13132 CHECK(v8::SetResourceConstraints(&constraints));
13133
13134 // Execute a script.
13135 v8::HandleScope scope;
13136 LocalContext env;
13137 Local<v8::FunctionTemplate> fun_templ =
13138 v8::FunctionTemplate::New(GetStackLimitCallback);
13139 Local<Function> fun = fun_templ->GetFunction();
13140 env->Global()->Set(v8_str("get_stack_limit"), fun);
13141 CompileRun("get_stack_limit();");
13142
13143 CHECK(stack_limit == set_limit);
13144 }
13145 {
13146 v8::Locker locker;
13147 CHECK(stack_limit == set_limit);
13148 }
13149}
Steve Block3ce2e202009-11-05 08:53:23 +000013150
13151
13152THREADED_TEST(GetHeapStatistics) {
13153 v8::HandleScope scope;
13154 LocalContext c1;
13155 v8::HeapStatistics heap_statistics;
Steve Blockd0582a62009-12-15 09:54:21 +000013156 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
13157 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
Steve Block3ce2e202009-11-05 08:53:23 +000013158 v8::V8::GetHeapStatistics(&heap_statistics);
Steve Blockd0582a62009-12-15 09:54:21 +000013159 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
13160 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
13161}
13162
13163
13164static double DoubleFromBits(uint64_t value) {
13165 double target;
Steve Blockd0582a62009-12-15 09:54:21 +000013166 memcpy(&target, &value, sizeof(target));
Steve Blockd0582a62009-12-15 09:54:21 +000013167 return target;
13168}
13169
13170
13171static uint64_t DoubleToBits(double value) {
13172 uint64_t target;
Steve Blockd0582a62009-12-15 09:54:21 +000013173 memcpy(&target, &value, sizeof(target));
Steve Blockd0582a62009-12-15 09:54:21 +000013174 return target;
13175}
13176
13177
13178static double DoubleToDateTime(double input) {
13179 double date_limit = 864e13;
13180 if (IsNaN(input) || input < -date_limit || input > date_limit) {
13181 return i::OS::nan_value();
13182 }
13183 return (input < 0) ? -(floor(-input)) : floor(input);
13184}
13185
13186// We don't have a consistent way to write 64-bit constants syntactically, so we
13187// split them into two 32-bit constants and combine them programmatically.
13188static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
13189 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
13190}
13191
13192
13193THREADED_TEST(QuietSignalingNaNs) {
13194 v8::HandleScope scope;
13195 LocalContext context;
13196 v8::TryCatch try_catch;
13197
13198 // Special double values.
13199 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
13200 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
13201 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
13202 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
13203 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
13204 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
13205 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
13206
13207 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
13208 // on either side of the epoch.
13209 double date_limit = 864e13;
13210
13211 double test_values[] = {
13212 snan,
13213 qnan,
13214 infinity,
13215 max_normal,
13216 date_limit + 1,
13217 date_limit,
13218 min_normal,
13219 max_denormal,
13220 min_denormal,
13221 0,
13222 -0,
13223 -min_denormal,
13224 -max_denormal,
13225 -min_normal,
13226 -date_limit,
13227 -date_limit - 1,
13228 -max_normal,
13229 -infinity,
13230 -qnan,
13231 -snan
13232 };
13233 int num_test_values = 20;
13234
13235 for (int i = 0; i < num_test_values; i++) {
13236 double test_value = test_values[i];
13237
13238 // Check that Number::New preserves non-NaNs and quiets SNaNs.
13239 v8::Handle<v8::Value> number = v8::Number::New(test_value);
13240 double stored_number = number->NumberValue();
13241 if (!IsNaN(test_value)) {
13242 CHECK_EQ(test_value, stored_number);
13243 } else {
13244 uint64_t stored_bits = DoubleToBits(stored_number);
13245 // Check if quiet nan (bits 51..62 all set).
13246 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
13247 }
13248
13249 // Check that Date::New preserves non-NaNs in the date range and
13250 // quiets SNaNs.
13251 v8::Handle<v8::Value> date = v8::Date::New(test_value);
13252 double expected_stored_date = DoubleToDateTime(test_value);
13253 double stored_date = date->NumberValue();
13254 if (!IsNaN(expected_stored_date)) {
13255 CHECK_EQ(expected_stored_date, stored_date);
13256 } else {
13257 uint64_t stored_bits = DoubleToBits(stored_date);
13258 // Check if quiet nan (bits 51..62 all set).
13259 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
13260 }
13261 }
13262}
13263
13264
13265static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
13266 v8::HandleScope scope;
13267 v8::TryCatch tc;
13268 v8::Handle<v8::String> str = args[0]->ToString();
13269 if (tc.HasCaught())
13270 return tc.ReThrow();
13271 return v8::Undefined();
13272}
13273
13274
13275// Test that an exception can be propagated down through a spaghetti
13276// stack using ReThrow.
13277THREADED_TEST(SpaghettiStackReThrow) {
13278 v8::HandleScope scope;
13279 LocalContext context;
13280 context->Global()->Set(
13281 v8::String::New("s"),
13282 v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
13283 v8::TryCatch try_catch;
13284 CompileRun(
13285 "var i = 0;"
13286 "var o = {"
13287 " toString: function () {"
13288 " if (i == 10) {"
13289 " throw 'Hey!';"
13290 " } else {"
13291 " i++;"
13292 " return s(o);"
13293 " }"
13294 " }"
13295 "};"
13296 "s(o);");
13297 CHECK(try_catch.HasCaught());
13298 v8::String::Utf8Value value(try_catch.Exception());
13299 CHECK_EQ(0, strcmp(*value, "Hey!"));
13300}
13301
13302
Steve Blockd0582a62009-12-15 09:54:21 +000013303TEST(Regress528) {
13304 v8::V8::Initialize();
13305
13306 v8::HandleScope scope;
13307 v8::Persistent<Context> context;
13308 v8::Persistent<Context> other_context;
13309 int gc_count;
13310
13311 // Create a context used to keep the code from aging in the compilation
13312 // cache.
13313 other_context = Context::New();
13314
13315 // Context-dependent context data creates reference from the compilation
13316 // cache to the global object.
13317 const char* source_simple = "1";
13318 context = Context::New();
13319 {
13320 v8::HandleScope scope;
13321
13322 context->Enter();
13323 Local<v8::String> obj = v8::String::New("");
13324 context->SetData(obj);
13325 CompileRun(source_simple);
13326 context->Exit();
13327 }
13328 context.Dispose();
13329 for (gc_count = 1; gc_count < 10; gc_count++) {
13330 other_context->Enter();
13331 CompileRun(source_simple);
13332 other_context->Exit();
Steve Block44f0eee2011-05-26 01:26:41 +010013333 HEAP->CollectAllGarbage(false);
Steve Blockd0582a62009-12-15 09:54:21 +000013334 if (GetGlobalObjectsCount() == 1) break;
13335 }
13336 CHECK_GE(2, gc_count);
13337 CHECK_EQ(1, GetGlobalObjectsCount());
13338
13339 // Eval in a function creates reference from the compilation cache to the
13340 // global object.
13341 const char* source_eval = "function f(){eval('1')}; f()";
13342 context = Context::New();
13343 {
13344 v8::HandleScope scope;
13345
13346 context->Enter();
13347 CompileRun(source_eval);
13348 context->Exit();
13349 }
13350 context.Dispose();
13351 for (gc_count = 1; gc_count < 10; gc_count++) {
13352 other_context->Enter();
13353 CompileRun(source_eval);
13354 other_context->Exit();
Steve Block44f0eee2011-05-26 01:26:41 +010013355 HEAP->CollectAllGarbage(false);
Steve Blockd0582a62009-12-15 09:54:21 +000013356 if (GetGlobalObjectsCount() == 1) break;
13357 }
13358 CHECK_GE(2, gc_count);
13359 CHECK_EQ(1, GetGlobalObjectsCount());
13360
13361 // Looking up the line number for an exception creates reference from the
13362 // compilation cache to the global object.
13363 const char* source_exception = "function f(){throw 1;} f()";
13364 context = Context::New();
13365 {
13366 v8::HandleScope scope;
13367
13368 context->Enter();
13369 v8::TryCatch try_catch;
13370 CompileRun(source_exception);
13371 CHECK(try_catch.HasCaught());
13372 v8::Handle<v8::Message> message = try_catch.Message();
13373 CHECK(!message.IsEmpty());
13374 CHECK_EQ(1, message->GetLineNumber());
13375 context->Exit();
13376 }
13377 context.Dispose();
13378 for (gc_count = 1; gc_count < 10; gc_count++) {
13379 other_context->Enter();
13380 CompileRun(source_exception);
13381 other_context->Exit();
Steve Block44f0eee2011-05-26 01:26:41 +010013382 HEAP->CollectAllGarbage(false);
Steve Blockd0582a62009-12-15 09:54:21 +000013383 if (GetGlobalObjectsCount() == 1) break;
13384 }
13385 CHECK_GE(2, gc_count);
13386 CHECK_EQ(1, GetGlobalObjectsCount());
13387
13388 other_context.Dispose();
Steve Block3ce2e202009-11-05 08:53:23 +000013389}
Andrei Popescu402d9372010-02-26 13:31:12 +000013390
13391
13392THREADED_TEST(ScriptOrigin) {
13393 v8::HandleScope scope;
13394 LocalContext env;
13395 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
13396 v8::Handle<v8::String> script = v8::String::New(
13397 "function f() {}\n\nfunction g() {}");
13398 v8::Script::Compile(script, &origin)->Run();
13399 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
13400 env->Global()->Get(v8::String::New("f")));
13401 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
13402 env->Global()->Get(v8::String::New("g")));
13403
13404 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
13405 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
13406 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
13407
13408 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
13409 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
13410 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
13411}
13412
13413
13414THREADED_TEST(ScriptLineNumber) {
13415 v8::HandleScope scope;
13416 LocalContext env;
13417 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
13418 v8::Handle<v8::String> script = v8::String::New(
13419 "function f() {}\n\nfunction g() {}");
13420 v8::Script::Compile(script, &origin)->Run();
13421 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
13422 env->Global()->Get(v8::String::New("f")));
13423 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
13424 env->Global()->Get(v8::String::New("g")));
13425 CHECK_EQ(0, f->GetScriptLineNumber());
13426 CHECK_EQ(2, g->GetScriptLineNumber());
13427}
13428
13429
13430static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
13431 const AccessorInfo& info) {
13432 return v8_num(42);
13433}
13434
13435
13436static void SetterWhichSetsYOnThisTo23(Local<String> name,
13437 Local<Value> value,
13438 const AccessorInfo& info) {
13439 info.This()->Set(v8_str("y"), v8_num(23));
13440}
13441
13442
Steve Block6ded16b2010-05-10 14:33:55 +010013443TEST(SetterOnConstructorPrototype) {
Andrei Popescu402d9372010-02-26 13:31:12 +000013444 v8::HandleScope scope;
13445 Local<ObjectTemplate> templ = ObjectTemplate::New();
13446 templ->SetAccessor(v8_str("x"),
13447 GetterWhichReturns42,
13448 SetterWhichSetsYOnThisTo23);
13449 LocalContext context;
13450 context->Global()->Set(v8_str("P"), templ->NewInstance());
13451 CompileRun("function C1() {"
13452 " this.x = 23;"
13453 "};"
13454 "C1.prototype = P;"
13455 "function C2() {"
13456 " this.x = 23"
13457 "};"
13458 "C2.prototype = { };"
13459 "C2.prototype.__proto__ = P;");
13460
13461 v8::Local<v8::Script> script;
13462 script = v8::Script::Compile(v8_str("new C1();"));
13463 for (int i = 0; i < 10; i++) {
13464 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13465 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
13466 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
13467 }
13468
13469 script = v8::Script::Compile(v8_str("new C2();"));
13470 for (int i = 0; i < 10; i++) {
13471 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
13472 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
13473 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
13474 }
13475}
13476
13477
13478static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
13479 Local<String> name, const AccessorInfo& info) {
13480 return v8_num(42);
13481}
13482
13483
13484static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
13485 Local<String> name, Local<Value> value, const AccessorInfo& info) {
13486 if (name->Equals(v8_str("x"))) {
13487 info.This()->Set(v8_str("y"), v8_num(23));
13488 }
13489 return v8::Handle<Value>();
13490}
13491
13492
13493THREADED_TEST(InterceptorOnConstructorPrototype) {
13494 v8::HandleScope scope;
13495 Local<ObjectTemplate> templ = ObjectTemplate::New();
13496 templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
13497 NamedPropertySetterWhichSetsYOnThisTo23);
13498 LocalContext context;
13499 context->Global()->Set(v8_str("P"), templ->NewInstance());
13500 CompileRun("function C1() {"
13501 " this.x = 23;"
13502 "};"
13503 "C1.prototype = P;"
13504 "function C2() {"
13505 " this.x = 23"
13506 "};"
13507 "C2.prototype = { };"
13508 "C2.prototype.__proto__ = P;");
13509
13510 v8::Local<v8::Script> script;
13511 script = v8::Script::Compile(v8_str("new C1();"));
13512 for (int i = 0; i < 10; i++) {
13513 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13514 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
13515 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
13516 }
13517
13518 script = v8::Script::Compile(v8_str("new C2();"));
13519 for (int i = 0; i < 10; i++) {
13520 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
13521 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
13522 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
13523 }
13524}
Steve Block6ded16b2010-05-10 14:33:55 +010013525
13526
13527TEST(Bug618) {
13528 const char* source = "function C1() {"
13529 " this.x = 23;"
13530 "};"
13531 "C1.prototype = P;";
13532
13533 v8::HandleScope scope;
13534 LocalContext context;
13535 v8::Local<v8::Script> script;
13536
13537 // Use a simple object as prototype.
13538 v8::Local<v8::Object> prototype = v8::Object::New();
13539 prototype->Set(v8_str("y"), v8_num(42));
13540 context->Global()->Set(v8_str("P"), prototype);
13541
13542 // This compile will add the code to the compilation cache.
13543 CompileRun(source);
13544
13545 script = v8::Script::Compile(v8_str("new C1();"));
Kristian Monsen0d5e1162010-09-30 15:31:59 +010013546 // Allow enough iterations for the inobject slack tracking logic
13547 // to finalize instance size and install the fast construct stub.
13548 for (int i = 0; i < 256; i++) {
Steve Block6ded16b2010-05-10 14:33:55 +010013549 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13550 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
13551 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
13552 }
13553
13554 // Use an API object with accessors as prototype.
13555 Local<ObjectTemplate> templ = ObjectTemplate::New();
13556 templ->SetAccessor(v8_str("x"),
13557 GetterWhichReturns42,
13558 SetterWhichSetsYOnThisTo23);
13559 context->Global()->Set(v8_str("P"), templ->NewInstance());
13560
13561 // This compile will get the code from the compilation cache.
13562 CompileRun(source);
13563
13564 script = v8::Script::Compile(v8_str("new C1();"));
13565 for (int i = 0; i < 10; i++) {
13566 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13567 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
13568 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
13569 }
13570}
13571
13572int prologue_call_count = 0;
13573int epilogue_call_count = 0;
13574int prologue_call_count_second = 0;
13575int epilogue_call_count_second = 0;
13576
13577void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
13578 ++prologue_call_count;
13579}
13580
13581void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
13582 ++epilogue_call_count;
13583}
13584
13585void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
13586 ++prologue_call_count_second;
13587}
13588
13589void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
13590 ++epilogue_call_count_second;
13591}
13592
13593TEST(GCCallbacks) {
13594 LocalContext context;
13595
13596 v8::V8::AddGCPrologueCallback(PrologueCallback);
13597 v8::V8::AddGCEpilogueCallback(EpilogueCallback);
13598 CHECK_EQ(0, prologue_call_count);
13599 CHECK_EQ(0, epilogue_call_count);
Steve Block44f0eee2011-05-26 01:26:41 +010013600 HEAP->CollectAllGarbage(false);
Steve Block6ded16b2010-05-10 14:33:55 +010013601 CHECK_EQ(1, prologue_call_count);
13602 CHECK_EQ(1, epilogue_call_count);
13603 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
13604 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
Steve Block44f0eee2011-05-26 01:26:41 +010013605 HEAP->CollectAllGarbage(false);
Steve Block6ded16b2010-05-10 14:33:55 +010013606 CHECK_EQ(2, prologue_call_count);
13607 CHECK_EQ(2, epilogue_call_count);
13608 CHECK_EQ(1, prologue_call_count_second);
13609 CHECK_EQ(1, epilogue_call_count_second);
13610 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
13611 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
Steve Block44f0eee2011-05-26 01:26:41 +010013612 HEAP->CollectAllGarbage(false);
Steve Block6ded16b2010-05-10 14:33:55 +010013613 CHECK_EQ(2, prologue_call_count);
13614 CHECK_EQ(2, epilogue_call_count);
13615 CHECK_EQ(2, prologue_call_count_second);
13616 CHECK_EQ(2, epilogue_call_count_second);
13617 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
13618 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
Steve Block44f0eee2011-05-26 01:26:41 +010013619 HEAP->CollectAllGarbage(false);
Steve Block6ded16b2010-05-10 14:33:55 +010013620 CHECK_EQ(2, prologue_call_count);
13621 CHECK_EQ(2, epilogue_call_count);
13622 CHECK_EQ(2, prologue_call_count_second);
13623 CHECK_EQ(2, epilogue_call_count_second);
13624}
Kristian Monsen25f61362010-05-21 11:50:48 +010013625
13626
13627THREADED_TEST(AddToJSFunctionResultCache) {
13628 i::FLAG_allow_natives_syntax = true;
13629 v8::HandleScope scope;
13630
13631 LocalContext context;
13632
13633 const char* code =
13634 "(function() {"
13635 " var key0 = 'a';"
13636 " var key1 = 'b';"
13637 " var r0 = %_GetFromCache(0, key0);"
13638 " var r1 = %_GetFromCache(0, key1);"
13639 " var r0_ = %_GetFromCache(0, key0);"
13640 " if (r0 !== r0_)"
13641 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
13642 " var r1_ = %_GetFromCache(0, key1);"
13643 " if (r1 !== r1_)"
13644 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
13645 " return 'PASSED';"
13646 "})()";
Steve Block44f0eee2011-05-26 01:26:41 +010013647 HEAP->ClearJSFunctionResultCaches();
Kristian Monsen25f61362010-05-21 11:50:48 +010013648 ExpectString(code, "PASSED");
13649}
13650
13651
13652static const int k0CacheSize = 16;
13653
13654THREADED_TEST(FillJSFunctionResultCache) {
13655 i::FLAG_allow_natives_syntax = true;
13656 v8::HandleScope scope;
13657
13658 LocalContext context;
13659
13660 const char* code =
13661 "(function() {"
13662 " var k = 'a';"
13663 " var r = %_GetFromCache(0, k);"
13664 " for (var i = 0; i < 16; i++) {"
13665 " %_GetFromCache(0, 'a' + i);"
13666 " };"
13667 " if (r === %_GetFromCache(0, k))"
13668 " return 'FAILED: k0CacheSize is too small';"
13669 " return 'PASSED';"
13670 "})()";
Steve Block44f0eee2011-05-26 01:26:41 +010013671 HEAP->ClearJSFunctionResultCaches();
Kristian Monsen25f61362010-05-21 11:50:48 +010013672 ExpectString(code, "PASSED");
13673}
13674
13675
13676THREADED_TEST(RoundRobinGetFromCache) {
13677 i::FLAG_allow_natives_syntax = true;
13678 v8::HandleScope scope;
13679
13680 LocalContext context;
13681
13682 const char* code =
13683 "(function() {"
13684 " var keys = [];"
13685 " for (var i = 0; i < 16; i++) keys.push(i);"
13686 " var values = [];"
13687 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
13688 " for (var i = 0; i < 16; i++) {"
13689 " var v = %_GetFromCache(0, keys[i]);"
13690 " if (v !== values[i])"
13691 " return 'Wrong value for ' + "
13692 " keys[i] + ': ' + v + ' vs. ' + values[i];"
13693 " };"
13694 " return 'PASSED';"
13695 "})()";
Steve Block44f0eee2011-05-26 01:26:41 +010013696 HEAP->ClearJSFunctionResultCaches();
Kristian Monsen25f61362010-05-21 11:50:48 +010013697 ExpectString(code, "PASSED");
13698}
13699
13700
13701THREADED_TEST(ReverseGetFromCache) {
13702 i::FLAG_allow_natives_syntax = true;
13703 v8::HandleScope scope;
13704
13705 LocalContext context;
13706
13707 const char* code =
13708 "(function() {"
13709 " var keys = [];"
13710 " for (var i = 0; i < 16; i++) keys.push(i);"
13711 " var values = [];"
13712 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
13713 " for (var i = 15; i >= 16; i--) {"
13714 " var v = %_GetFromCache(0, keys[i]);"
13715 " if (v !== values[i])"
13716 " return 'Wrong value for ' + "
13717 " keys[i] + ': ' + v + ' vs. ' + values[i];"
13718 " };"
13719 " return 'PASSED';"
13720 "})()";
Steve Block44f0eee2011-05-26 01:26:41 +010013721 HEAP->ClearJSFunctionResultCaches();
Kristian Monsen25f61362010-05-21 11:50:48 +010013722 ExpectString(code, "PASSED");
13723}
13724
13725
13726THREADED_TEST(TestEviction) {
13727 i::FLAG_allow_natives_syntax = true;
13728 v8::HandleScope scope;
13729
13730 LocalContext context;
13731
13732 const char* code =
13733 "(function() {"
13734 " for (var i = 0; i < 2*16; i++) {"
13735 " %_GetFromCache(0, 'a' + i);"
13736 " };"
13737 " return 'PASSED';"
13738 "})()";
Steve Block44f0eee2011-05-26 01:26:41 +010013739 HEAP->ClearJSFunctionResultCaches();
Kristian Monsen25f61362010-05-21 11:50:48 +010013740 ExpectString(code, "PASSED");
13741}
Steve Block8defd9f2010-07-08 12:39:36 +010013742
13743
13744THREADED_TEST(TwoByteStringInAsciiCons) {
13745 // See Chromium issue 47824.
13746 v8::HandleScope scope;
13747
13748 LocalContext context;
13749 const char* init_code =
13750 "var str1 = 'abelspendabel';"
13751 "var str2 = str1 + str1 + str1;"
13752 "str2;";
13753 Local<Value> result = CompileRun(init_code);
13754
Ben Murdoch69a99ed2011-11-30 16:03:39 +000013755 Local<Value> indexof = CompileRun("str2.indexOf('els')");
13756 Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
13757
Steve Block8defd9f2010-07-08 12:39:36 +010013758 CHECK(result->IsString());
13759 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
13760 int length = string->length();
13761 CHECK(string->IsAsciiRepresentation());
13762
13763 FlattenString(string);
13764 i::Handle<i::String> flat_string = FlattenGetString(string);
13765
13766 CHECK(string->IsAsciiRepresentation());
13767 CHECK(flat_string->IsAsciiRepresentation());
13768
13769 // Create external resource.
13770 uint16_t* uc16_buffer = new uint16_t[length + 1];
13771
13772 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
13773 uc16_buffer[length] = 0;
13774
13775 TestResource resource(uc16_buffer);
13776
13777 flat_string->MakeExternal(&resource);
13778
13779 CHECK(flat_string->IsTwoByteRepresentation());
13780
13781 // At this point, we should have a Cons string which is flat and ASCII,
13782 // with a first half that is a two-byte string (although it only contains
13783 // ASCII characters). This is a valid sequence of steps, and it can happen
13784 // in real pages.
13785
13786 CHECK(string->IsAsciiRepresentation());
13787 i::ConsString* cons = i::ConsString::cast(*string);
13788 CHECK_EQ(0, cons->second()->length());
13789 CHECK(cons->first()->IsTwoByteRepresentation());
13790
13791 // Check that some string operations work.
13792
13793 // Atom RegExp.
13794 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
13795 CHECK_EQ(6, reresult->Int32Value());
13796
13797 // Nonatom RegExp.
13798 reresult = CompileRun("str2.match(/abe./g).length;");
13799 CHECK_EQ(6, reresult->Int32Value());
13800
13801 reresult = CompileRun("str2.search(/bel/g);");
13802 CHECK_EQ(1, reresult->Int32Value());
13803
13804 reresult = CompileRun("str2.search(/be./g);");
13805 CHECK_EQ(1, reresult->Int32Value());
13806
13807 ExpectTrue("/bel/g.test(str2);");
13808
13809 ExpectTrue("/be./g.test(str2);");
13810
13811 reresult = CompileRun("/bel/g.exec(str2);");
13812 CHECK(!reresult->IsNull());
13813
13814 reresult = CompileRun("/be./g.exec(str2);");
13815 CHECK(!reresult->IsNull());
13816
13817 ExpectString("str2.substring(2, 10);", "elspenda");
13818
13819 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
13820
13821 ExpectString("str2.charAt(2);", "e");
13822
Ben Murdoch69a99ed2011-11-30 16:03:39 +000013823 ExpectObject("str2.indexOf('els');", indexof);
13824
13825 ExpectObject("str2.lastIndexOf('dab');", lastindexof);
13826
Steve Block8defd9f2010-07-08 12:39:36 +010013827 reresult = CompileRun("str2.charCodeAt(2);");
13828 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
13829}
Iain Merrick75681382010-08-19 15:07:18 +010013830
13831
13832// Failed access check callback that performs a GC on each invocation.
13833void FailedAccessCheckCallbackGC(Local<v8::Object> target,
13834 v8::AccessType type,
13835 Local<v8::Value> data) {
Steve Block44f0eee2011-05-26 01:26:41 +010013836 HEAP->CollectAllGarbage(true);
Iain Merrick75681382010-08-19 15:07:18 +010013837}
13838
13839
13840TEST(GCInFailedAccessCheckCallback) {
13841 // Install a failed access check callback that performs a GC on each
13842 // invocation. Then force the callback to be called from va
13843
13844 v8::V8::Initialize();
13845 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
13846
13847 v8::HandleScope scope;
13848
13849 // Create an ObjectTemplate for global objects and install access
13850 // check callbacks that will block access.
13851 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
13852 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
13853 IndexedGetAccessBlocker,
13854 v8::Handle<v8::Value>(),
13855 false);
13856
13857 // Create a context and set an x property on it's global object.
13858 LocalContext context0(NULL, global_template);
13859 context0->Global()->Set(v8_str("x"), v8_num(42));
13860 v8::Handle<v8::Object> global0 = context0->Global();
13861
13862 // Create a context with a different security token so that the
13863 // failed access check callback will be called on each access.
13864 LocalContext context1(NULL, global_template);
13865 context1->Global()->Set(v8_str("other"), global0);
13866
13867 // Get property with failed access check.
13868 ExpectUndefined("other.x");
13869
13870 // Get element with failed access check.
13871 ExpectUndefined("other[0]");
13872
13873 // Set property with failed access check.
13874 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
13875 CHECK(result->IsObject());
13876
13877 // Set element with failed access check.
13878 result = CompileRun("other[0] = new Object()");
13879 CHECK(result->IsObject());
13880
13881 // Get property attribute with failed access check.
13882 ExpectFalse("\'x\' in other");
13883
13884 // Get property attribute for element with failed access check.
13885 ExpectFalse("0 in other");
13886
13887 // Delete property.
13888 ExpectFalse("delete other.x");
13889
13890 // Delete element.
13891 CHECK_EQ(false, global0->Delete(0));
13892
13893 // DefineAccessor.
13894 CHECK_EQ(false,
13895 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
13896
13897 // Define JavaScript accessor.
13898 ExpectUndefined("Object.prototype.__defineGetter__.call("
13899 " other, \'x\', function() { return 42; })");
13900
13901 // LookupAccessor.
13902 ExpectUndefined("Object.prototype.__lookupGetter__.call("
13903 " other, \'x\')");
13904
13905 // HasLocalElement.
13906 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
13907
13908 CHECK_EQ(false, global0->HasRealIndexedProperty(0));
13909 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
13910 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
13911
13912 // Reset the failed access check callback so it does not influence
13913 // the other tests.
13914 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
13915}
Kristian Monsen0d5e1162010-09-30 15:31:59 +010013916
Steve Block44f0eee2011-05-26 01:26:41 +010013917TEST(DefaultIsolateGetCurrent) {
13918 CHECK(v8::Isolate::GetCurrent() != NULL);
13919 v8::Isolate* isolate = v8::Isolate::GetCurrent();
13920 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
13921 printf("*** %s\n", "DefaultIsolateGetCurrent success");
13922}
13923
13924TEST(IsolateNewDispose) {
13925 v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
13926 v8::Isolate* isolate = v8::Isolate::New();
13927 CHECK(isolate != NULL);
13928 CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
13929 CHECK(current_isolate != isolate);
13930 CHECK(current_isolate == v8::Isolate::GetCurrent());
13931
13932 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13933 last_location = last_message = NULL;
13934 isolate->Dispose();
13935 CHECK_EQ(last_location, NULL);
13936 CHECK_EQ(last_message, NULL);
13937}
13938
13939TEST(IsolateEnterExitDefault) {
13940 v8::HandleScope scope;
13941 LocalContext context;
13942 v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
13943 CHECK(current_isolate != NULL); // Default isolate.
13944 ExpectString("'hello'", "hello");
13945 current_isolate->Enter();
13946 ExpectString("'still working'", "still working");
13947 current_isolate->Exit();
13948 ExpectString("'still working 2'", "still working 2");
13949 current_isolate->Exit();
13950 // Default isolate is always, well, 'default current'.
13951 CHECK_EQ(v8::Isolate::GetCurrent(), current_isolate);
13952 // Still working since default isolate is auto-entering any thread
13953 // that has no isolate and attempts to execute V8 APIs.
13954 ExpectString("'still working 3'", "still working 3");
13955}
13956
13957TEST(DisposeDefaultIsolate) {
13958 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13959
13960 // Run some V8 code to trigger default isolate to become 'current'.
13961 v8::HandleScope scope;
13962 LocalContext context;
13963 ExpectString("'run some V8'", "run some V8");
13964
13965 v8::Isolate* isolate = v8::Isolate::GetCurrent();
13966 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
13967 last_location = last_message = NULL;
13968 isolate->Dispose();
13969 // It is not possible to dispose default isolate via Isolate API.
13970 CHECK_NE(last_location, NULL);
13971 CHECK_NE(last_message, NULL);
13972}
13973
13974TEST(RunDefaultAndAnotherIsolate) {
13975 v8::HandleScope scope;
13976 LocalContext context;
13977
13978 // Enter new isolate.
13979 v8::Isolate* isolate = v8::Isolate::New();
13980 CHECK(isolate);
13981 isolate->Enter();
13982 { // Need this block because subsequent Exit() will deallocate Heap,
13983 // so we need all scope objects to be deconstructed when it happens.
13984 v8::HandleScope scope_new;
13985 LocalContext context_new;
13986
13987 // Run something in new isolate.
13988 CompileRun("var foo = 153;");
13989 ExpectTrue("function f() { return foo == 153; }; f()");
13990 }
13991 isolate->Exit();
13992
13993 // This runs automatically in default isolate.
13994 // Variables in another isolate should be not available.
13995 ExpectTrue("function f() {"
13996 " try {"
13997 " foo;"
13998 " return false;"
13999 " } catch(e) {"
14000 " return true;"
14001 " }"
14002 "};"
14003 "var bar = 371;"
14004 "f()");
14005
14006 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14007 last_location = last_message = NULL;
14008 isolate->Dispose();
14009 CHECK_EQ(last_location, NULL);
14010 CHECK_EQ(last_message, NULL);
14011
14012 // Check that default isolate still runs.
14013 ExpectTrue("function f() { return bar == 371; }; f()");
14014}
14015
14016TEST(DisposeIsolateWhenInUse) {
14017 v8::Isolate* isolate = v8::Isolate::New();
14018 CHECK(isolate);
14019 isolate->Enter();
14020 v8::HandleScope scope;
14021 LocalContext context;
14022 // Run something in this isolate.
14023 ExpectTrue("true");
14024 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14025 last_location = last_message = NULL;
14026 // Still entered, should fail.
14027 isolate->Dispose();
14028 CHECK_NE(last_location, NULL);
14029 CHECK_NE(last_message, NULL);
14030}
14031
14032TEST(RunTwoIsolatesOnSingleThread) {
14033 // Run isolate 1.
14034 v8::Isolate* isolate1 = v8::Isolate::New();
14035 isolate1->Enter();
14036 v8::Persistent<v8::Context> context1 = v8::Context::New();
14037
14038 {
14039 v8::Context::Scope cscope(context1);
14040 v8::HandleScope scope;
14041 // Run something in new isolate.
14042 CompileRun("var foo = 'isolate 1';");
14043 ExpectString("function f() { return foo; }; f()", "isolate 1");
14044 }
14045
14046 // Run isolate 2.
14047 v8::Isolate* isolate2 = v8::Isolate::New();
14048 v8::Persistent<v8::Context> context2;
14049
14050 {
14051 v8::Isolate::Scope iscope(isolate2);
14052 context2 = v8::Context::New();
14053 v8::Context::Scope cscope(context2);
14054 v8::HandleScope scope;
14055
14056 // Run something in new isolate.
14057 CompileRun("var foo = 'isolate 2';");
14058 ExpectString("function f() { return foo; }; f()", "isolate 2");
14059 }
14060
14061 {
14062 v8::Context::Scope cscope(context1);
14063 v8::HandleScope scope;
14064 // Now again in isolate 1
14065 ExpectString("function f() { return foo; }; f()", "isolate 1");
14066 }
14067
14068 isolate1->Exit();
14069
14070 // Run some stuff in default isolate.
14071 v8::Persistent<v8::Context> context_default = v8::Context::New();
14072
14073 {
14074 v8::Context::Scope cscope(context_default);
14075 v8::HandleScope scope;
14076 // Variables in other isolates should be not available, verify there
14077 // is an exception.
14078 ExpectTrue("function f() {"
14079 " try {"
14080 " foo;"
14081 " return false;"
14082 " } catch(e) {"
14083 " return true;"
14084 " }"
14085 "};"
14086 "var isDefaultIsolate = true;"
14087 "f()");
14088 }
14089
14090 isolate1->Enter();
14091
14092 {
14093 v8::Isolate::Scope iscope(isolate2);
14094 v8::Context::Scope cscope(context2);
14095 v8::HandleScope scope;
14096 ExpectString("function f() { return foo; }; f()", "isolate 2");
14097 }
14098
14099 {
14100 v8::Context::Scope cscope(context1);
14101 v8::HandleScope scope;
14102 ExpectString("function f() { return foo; }; f()", "isolate 1");
14103 }
14104
14105 {
14106 v8::Isolate::Scope iscope(isolate2);
14107 context2.Dispose();
14108 }
14109
14110 context1.Dispose();
14111 isolate1->Exit();
14112
14113 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14114 last_location = last_message = NULL;
14115
14116 isolate1->Dispose();
14117 CHECK_EQ(last_location, NULL);
14118 CHECK_EQ(last_message, NULL);
14119
14120 isolate2->Dispose();
14121 CHECK_EQ(last_location, NULL);
14122 CHECK_EQ(last_message, NULL);
14123
14124 // Check that default isolate still runs.
14125 {
14126 v8::Context::Scope cscope(context_default);
14127 v8::HandleScope scope;
14128 ExpectTrue("function f() { return isDefaultIsolate; }; f()");
14129 }
14130}
14131
14132static int CalcFibonacci(v8::Isolate* isolate, int limit) {
14133 v8::Isolate::Scope isolate_scope(isolate);
14134 v8::HandleScope scope;
14135 LocalContext context;
14136 i::ScopedVector<char> code(1024);
14137 i::OS::SNPrintF(code, "function fib(n) {"
14138 " if (n <= 2) return 1;"
14139 " return fib(n-1) + fib(n-2);"
14140 "}"
14141 "fib(%d)", limit);
14142 Local<Value> value = CompileRun(code.start());
14143 CHECK(value->IsNumber());
14144 return static_cast<int>(value->NumberValue());
14145}
14146
14147class IsolateThread : public v8::internal::Thread {
14148 public:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014149 IsolateThread(v8::Isolate* isolate, int fib_limit)
14150 : Thread("IsolateThread"),
Steve Block44f0eee2011-05-26 01:26:41 +010014151 isolate_(isolate),
14152 fib_limit_(fib_limit),
14153 result_(0) { }
14154
14155 void Run() {
14156 result_ = CalcFibonacci(isolate_, fib_limit_);
14157 }
14158
14159 int result() { return result_; }
14160
14161 private:
14162 v8::Isolate* isolate_;
14163 int fib_limit_;
14164 int result_;
14165};
14166
14167TEST(MultipleIsolatesOnIndividualThreads) {
14168 v8::Isolate* isolate1 = v8::Isolate::New();
14169 v8::Isolate* isolate2 = v8::Isolate::New();
14170
14171 IsolateThread thread1(isolate1, 21);
14172 IsolateThread thread2(isolate2, 12);
14173
14174 // Compute some fibonacci numbers on 3 threads in 3 isolates.
14175 thread1.Start();
14176 thread2.Start();
14177
14178 int result1 = CalcFibonacci(v8::Isolate::GetCurrent(), 21);
14179 int result2 = CalcFibonacci(v8::Isolate::GetCurrent(), 12);
14180
14181 thread1.Join();
14182 thread2.Join();
14183
14184 // Compare results. The actual fibonacci numbers for 12 and 21 are taken
14185 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
14186 CHECK_EQ(result1, 10946);
14187 CHECK_EQ(result2, 144);
14188 CHECK_EQ(result1, thread1.result());
14189 CHECK_EQ(result2, thread2.result());
14190
14191 isolate1->Dispose();
14192 isolate2->Dispose();
14193}
14194
Ben Murdoch257744e2011-11-30 15:57:28 +000014195TEST(IsolateDifferentContexts) {
14196 v8::Isolate* isolate = v8::Isolate::New();
14197 Persistent<v8::Context> context;
14198 {
14199 v8::Isolate::Scope isolate_scope(isolate);
14200 v8::HandleScope handle_scope;
14201 context = v8::Context::New();
14202 v8::Context::Scope context_scope(context);
14203 Local<Value> v = CompileRun("2");
14204 CHECK(v->IsNumber());
14205 CHECK_EQ(2, static_cast<int>(v->NumberValue()));
14206 }
14207 {
14208 v8::Isolate::Scope isolate_scope(isolate);
14209 v8::HandleScope handle_scope;
14210 context = v8::Context::New();
14211 v8::Context::Scope context_scope(context);
14212 Local<Value> v = CompileRun("22");
14213 CHECK(v->IsNumber());
14214 CHECK_EQ(22, static_cast<int>(v->NumberValue()));
14215 }
14216}
Steve Block44f0eee2011-05-26 01:26:41 +010014217
14218class InitDefaultIsolateThread : public v8::internal::Thread {
14219 public:
14220 enum TestCase {
14221 IgnoreOOM,
14222 SetResourceConstraints,
14223 SetFatalHandler,
14224 SetCounterFunction,
14225 SetCreateHistogramFunction,
14226 SetAddHistogramSampleFunction
14227 };
14228
14229 explicit InitDefaultIsolateThread(TestCase testCase)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014230 : Thread("InitDefaultIsolateThread"),
Steve Block44f0eee2011-05-26 01:26:41 +010014231 testCase_(testCase),
14232 result_(false) { }
14233
14234 void Run() {
14235 switch (testCase_) {
14236 case IgnoreOOM:
14237 v8::V8::IgnoreOutOfMemoryException();
14238 break;
14239
14240 case SetResourceConstraints: {
14241 static const int K = 1024;
14242 v8::ResourceConstraints constraints;
14243 constraints.set_max_young_space_size(256 * K);
14244 constraints.set_max_old_space_size(4 * K * K);
14245 v8::SetResourceConstraints(&constraints);
14246 break;
14247 }
14248
14249 case SetFatalHandler:
14250 v8::V8::SetFatalErrorHandler(NULL);
14251 break;
14252
14253 case SetCounterFunction:
14254 v8::V8::SetCounterFunction(NULL);
14255 break;
14256
14257 case SetCreateHistogramFunction:
14258 v8::V8::SetCreateHistogramFunction(NULL);
14259 break;
14260
14261 case SetAddHistogramSampleFunction:
14262 v8::V8::SetAddHistogramSampleFunction(NULL);
14263 break;
14264 }
14265 result_ = true;
14266 }
14267
14268 bool result() { return result_; }
14269
14270 private:
14271 TestCase testCase_;
14272 bool result_;
14273};
14274
14275
14276static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
14277 InitDefaultIsolateThread thread(testCase);
14278 thread.Start();
14279 thread.Join();
14280 CHECK_EQ(thread.result(), true);
14281}
14282
14283TEST(InitializeDefaultIsolateOnSecondaryThread1) {
14284 InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM);
14285}
14286
14287TEST(InitializeDefaultIsolateOnSecondaryThread2) {
14288 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
14289}
14290
14291TEST(InitializeDefaultIsolateOnSecondaryThread3) {
14292 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
14293}
14294
14295TEST(InitializeDefaultIsolateOnSecondaryThread4) {
14296 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
14297}
14298
14299TEST(InitializeDefaultIsolateOnSecondaryThread5) {
14300 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
14301}
14302
14303TEST(InitializeDefaultIsolateOnSecondaryThread6) {
14304 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
14305}
14306
Kristian Monsen0d5e1162010-09-30 15:31:59 +010014307
14308TEST(StringCheckMultipleContexts) {
14309 const char* code =
14310 "(function() { return \"a\".charAt(0); })()";
14311
14312 {
14313 // Run the code twice in the first context to initialize the call IC.
14314 v8::HandleScope scope;
14315 LocalContext context1;
14316 ExpectString(code, "a");
14317 ExpectString(code, "a");
14318 }
14319
14320 {
14321 // Change the String.prototype in the second context and check
14322 // that the right function gets called.
14323 v8::HandleScope scope;
14324 LocalContext context2;
14325 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
14326 ExpectString(code, "not a");
14327 }
14328}
14329
14330
14331TEST(NumberCheckMultipleContexts) {
14332 const char* code =
14333 "(function() { return (42).toString(); })()";
14334
14335 {
14336 // Run the code twice in the first context to initialize the call IC.
14337 v8::HandleScope scope;
14338 LocalContext context1;
14339 ExpectString(code, "42");
14340 ExpectString(code, "42");
14341 }
14342
14343 {
14344 // Change the Number.prototype in the second context and check
14345 // that the right function gets called.
14346 v8::HandleScope scope;
14347 LocalContext context2;
14348 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
14349 ExpectString(code, "not 42");
14350 }
14351}
14352
14353
14354TEST(BooleanCheckMultipleContexts) {
14355 const char* code =
14356 "(function() { return true.toString(); })()";
14357
14358 {
14359 // Run the code twice in the first context to initialize the call IC.
14360 v8::HandleScope scope;
14361 LocalContext context1;
14362 ExpectString(code, "true");
14363 ExpectString(code, "true");
14364 }
14365
14366 {
14367 // Change the Boolean.prototype in the second context and check
14368 // that the right function gets called.
14369 v8::HandleScope scope;
14370 LocalContext context2;
14371 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
14372 ExpectString(code, "");
14373 }
14374}
Ben Murdochf87a2032010-10-22 12:50:53 +010014375
14376
14377TEST(DontDeleteCellLoadIC) {
14378 const char* function_code =
14379 "function readCell() { while (true) { return cell; } }";
14380
14381 {
14382 // Run the code twice in the first context to initialize the load
14383 // IC for a don't delete cell.
14384 v8::HandleScope scope;
14385 LocalContext context1;
14386 CompileRun("var cell = \"first\";");
14387 ExpectBoolean("delete cell", false);
14388 CompileRun(function_code);
14389 ExpectString("readCell()", "first");
14390 ExpectString("readCell()", "first");
14391 }
14392
14393 {
14394 // Use a deletable cell in the second context.
14395 v8::HandleScope scope;
14396 LocalContext context2;
14397 CompileRun("cell = \"second\";");
14398 CompileRun(function_code);
14399 ExpectString("readCell()", "second");
14400 ExpectBoolean("delete cell", true);
14401 ExpectString("(function() {"
14402 " try {"
14403 " return readCell();"
14404 " } catch(e) {"
14405 " return e.toString();"
14406 " }"
14407 "})()",
14408 "ReferenceError: cell is not defined");
14409 CompileRun("cell = \"new_second\";");
Steve Block44f0eee2011-05-26 01:26:41 +010014410 HEAP->CollectAllGarbage(true);
Ben Murdochf87a2032010-10-22 12:50:53 +010014411 ExpectString("readCell()", "new_second");
14412 ExpectString("readCell()", "new_second");
14413 }
14414}
14415
14416
14417TEST(DontDeleteCellLoadICForceDelete) {
14418 const char* function_code =
14419 "function readCell() { while (true) { return cell; } }";
14420
14421 // Run the code twice to initialize the load IC for a don't delete
14422 // cell.
14423 v8::HandleScope scope;
14424 LocalContext context;
14425 CompileRun("var cell = \"value\";");
14426 ExpectBoolean("delete cell", false);
14427 CompileRun(function_code);
14428 ExpectString("readCell()", "value");
14429 ExpectString("readCell()", "value");
14430
14431 // Delete the cell using the API and check the inlined code works
14432 // correctly.
14433 CHECK(context->Global()->ForceDelete(v8_str("cell")));
14434 ExpectString("(function() {"
14435 " try {"
14436 " return readCell();"
14437 " } catch(e) {"
14438 " return e.toString();"
14439 " }"
14440 "})()",
14441 "ReferenceError: cell is not defined");
14442}
14443
14444
14445TEST(DontDeleteCellLoadICAPI) {
14446 const char* function_code =
14447 "function readCell() { while (true) { return cell; } }";
14448
14449 // Run the code twice to initialize the load IC for a don't delete
14450 // cell created using the API.
14451 v8::HandleScope scope;
14452 LocalContext context;
14453 context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
14454 ExpectBoolean("delete cell", false);
14455 CompileRun(function_code);
14456 ExpectString("readCell()", "value");
14457 ExpectString("readCell()", "value");
14458
14459 // Delete the cell using the API and check the inlined code works
14460 // correctly.
14461 CHECK(context->Global()->ForceDelete(v8_str("cell")));
14462 ExpectString("(function() {"
14463 " try {"
14464 " return readCell();"
14465 " } catch(e) {"
14466 " return e.toString();"
14467 " }"
14468 "})()",
14469 "ReferenceError: cell is not defined");
14470}
14471
14472
Ben Murdochf87a2032010-10-22 12:50:53 +010014473TEST(RegExp) {
14474 v8::HandleScope scope;
14475 LocalContext context;
14476
14477 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
14478 CHECK(re->IsRegExp());
14479 CHECK(re->GetSource()->Equals(v8_str("foo")));
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014480 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
Ben Murdochf87a2032010-10-22 12:50:53 +010014481
14482 re = v8::RegExp::New(v8_str("bar"),
14483 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
14484 v8::RegExp::kGlobal));
14485 CHECK(re->IsRegExp());
14486 CHECK(re->GetSource()->Equals(v8_str("bar")));
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014487 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
14488 static_cast<int>(re->GetFlags()));
Ben Murdochf87a2032010-10-22 12:50:53 +010014489
14490 re = v8::RegExp::New(v8_str("baz"),
14491 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
14492 v8::RegExp::kMultiline));
14493 CHECK(re->IsRegExp());
14494 CHECK(re->GetSource()->Equals(v8_str("baz")));
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014495 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
14496 static_cast<int>(re->GetFlags()));
Ben Murdochf87a2032010-10-22 12:50:53 +010014497
14498 re = CompileRun("/quux/").As<v8::RegExp>();
14499 CHECK(re->IsRegExp());
14500 CHECK(re->GetSource()->Equals(v8_str("quux")));
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014501 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
Ben Murdochf87a2032010-10-22 12:50:53 +010014502
14503 re = CompileRun("/quux/gm").As<v8::RegExp>();
14504 CHECK(re->IsRegExp());
14505 CHECK(re->GetSource()->Equals(v8_str("quux")));
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014506 CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
14507 static_cast<int>(re->GetFlags()));
Ben Murdochf87a2032010-10-22 12:50:53 +010014508
14509 // Override the RegExp constructor and check the API constructor
14510 // still works.
14511 CompileRun("RegExp = function() {}");
14512
14513 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
14514 CHECK(re->IsRegExp());
14515 CHECK(re->GetSource()->Equals(v8_str("foobar")));
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014516 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
Ben Murdochf87a2032010-10-22 12:50:53 +010014517
14518 re = v8::RegExp::New(v8_str("foobarbaz"),
14519 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
14520 v8::RegExp::kMultiline));
14521 CHECK(re->IsRegExp());
14522 CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014523 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
14524 static_cast<int>(re->GetFlags()));
Ben Murdochf87a2032010-10-22 12:50:53 +010014525
14526 context->Global()->Set(v8_str("re"), re);
14527 ExpectTrue("re.test('FoobarbaZ')");
14528
Ben Murdoch257744e2011-11-30 15:57:28 +000014529 // RegExps are objects on which you can set properties.
14530 re->Set(v8_str("property"), v8::Integer::New(32));
14531 v8::Handle<v8::Value> value = CompileRun("re.property");
14532 ASSERT_EQ(32, value->Int32Value());
14533
Ben Murdochf87a2032010-10-22 12:50:53 +010014534 v8::TryCatch try_catch;
14535 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
14536 CHECK(re.IsEmpty());
14537 CHECK(try_catch.HasCaught());
14538 context->Global()->Set(v8_str("ex"), try_catch.Exception());
14539 ExpectTrue("ex instanceof SyntaxError");
14540}
14541
14542
Steve Block1e0659c2011-05-24 12:43:12 +010014543THREADED_TEST(Equals) {
14544 v8::HandleScope handleScope;
14545 LocalContext localContext;
14546
14547 v8::Handle<v8::Object> globalProxy = localContext->Global();
14548 v8::Handle<Value> global = globalProxy->GetPrototype();
14549
14550 CHECK(global->StrictEquals(global));
14551 CHECK(!global->StrictEquals(globalProxy));
14552 CHECK(!globalProxy->StrictEquals(global));
14553 CHECK(globalProxy->StrictEquals(globalProxy));
14554
14555 CHECK(global->Equals(global));
14556 CHECK(!global->Equals(globalProxy));
14557 CHECK(!globalProxy->Equals(global));
14558 CHECK(globalProxy->Equals(globalProxy));
14559}
14560
14561
Ben Murdochf87a2032010-10-22 12:50:53 +010014562static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
14563 const v8::AccessorInfo& info ) {
14564 return v8_str("42!");
14565}
14566
14567
14568static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo& info) {
14569 v8::Handle<v8::Array> result = v8::Array::New();
14570 result->Set(0, v8_str("universalAnswer"));
14571 return result;
14572}
14573
14574
14575TEST(NamedEnumeratorAndForIn) {
14576 v8::HandleScope handle_scope;
14577 LocalContext context;
14578 v8::Context::Scope context_scope(context.local());
14579
14580 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New();
14581 tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
14582 context->Global()->Set(v8_str("o"), tmpl->NewInstance());
14583 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
14584 "var result = []; for (var k in o) result.push(k); result"));
14585 CHECK_EQ(1, result->Length());
14586 CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
14587}
Steve Block1e0659c2011-05-24 12:43:12 +010014588
14589
14590TEST(DefinePropertyPostDetach) {
14591 v8::HandleScope scope;
14592 LocalContext context;
14593 v8::Handle<v8::Object> proxy = context->Global();
14594 v8::Handle<v8::Function> define_property =
14595 CompileRun("(function() {"
14596 " Object.defineProperty("
14597 " this,"
14598 " 1,"
14599 " { configurable: true, enumerable: true, value: 3 });"
14600 "})").As<Function>();
14601 context->DetachGlobal();
14602 define_property->Call(proxy, 0, NULL);
14603}
Ben Murdoch8b112d22011-06-08 16:22:53 +010014604
14605
14606static void InstallContextId(v8::Handle<Context> context, int id) {
14607 Context::Scope scope(context);
14608 CompileRun("Object.prototype").As<Object>()->
14609 Set(v8_str("context_id"), v8::Integer::New(id));
14610}
14611
14612
14613static void CheckContextId(v8::Handle<Object> object, int expected) {
14614 CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
14615}
14616
14617
14618THREADED_TEST(CreationContext) {
14619 HandleScope handle_scope;
14620 Persistent<Context> context1 = Context::New();
14621 InstallContextId(context1, 1);
14622 Persistent<Context> context2 = Context::New();
14623 InstallContextId(context2, 2);
14624 Persistent<Context> context3 = Context::New();
14625 InstallContextId(context3, 3);
14626
14627 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New();
14628
14629 Local<Object> object1;
14630 Local<Function> func1;
14631 {
14632 Context::Scope scope(context1);
14633 object1 = Object::New();
14634 func1 = tmpl->GetFunction();
14635 }
14636
14637 Local<Object> object2;
14638 Local<Function> func2;
14639 {
14640 Context::Scope scope(context2);
14641 object2 = Object::New();
14642 func2 = tmpl->GetFunction();
14643 }
14644
14645 Local<Object> instance1;
14646 Local<Object> instance2;
14647
14648 {
14649 Context::Scope scope(context3);
14650 instance1 = func1->NewInstance();
14651 instance2 = func2->NewInstance();
14652 }
14653
14654 CHECK(object1->CreationContext() == context1);
14655 CheckContextId(object1, 1);
14656 CHECK(func1->CreationContext() == context1);
14657 CheckContextId(func1, 1);
14658 CHECK(instance1->CreationContext() == context1);
14659 CheckContextId(instance1, 1);
14660 CHECK(object2->CreationContext() == context2);
14661 CheckContextId(object2, 2);
14662 CHECK(func2->CreationContext() == context2);
14663 CheckContextId(func2, 2);
14664 CHECK(instance2->CreationContext() == context2);
14665 CheckContextId(instance2, 2);
14666
14667 {
14668 Context::Scope scope(context1);
14669 CHECK(object1->CreationContext() == context1);
14670 CheckContextId(object1, 1);
14671 CHECK(func1->CreationContext() == context1);
14672 CheckContextId(func1, 1);
14673 CHECK(instance1->CreationContext() == context1);
14674 CheckContextId(instance1, 1);
14675 CHECK(object2->CreationContext() == context2);
14676 CheckContextId(object2, 2);
14677 CHECK(func2->CreationContext() == context2);
14678 CheckContextId(func2, 2);
14679 CHECK(instance2->CreationContext() == context2);
14680 CheckContextId(instance2, 2);
14681 }
14682
14683 {
14684 Context::Scope scope(context2);
14685 CHECK(object1->CreationContext() == context1);
14686 CheckContextId(object1, 1);
14687 CHECK(func1->CreationContext() == context1);
14688 CheckContextId(func1, 1);
14689 CHECK(instance1->CreationContext() == context1);
14690 CheckContextId(instance1, 1);
14691 CHECK(object2->CreationContext() == context2);
14692 CheckContextId(object2, 2);
14693 CHECK(func2->CreationContext() == context2);
14694 CheckContextId(func2, 2);
14695 CHECK(instance2->CreationContext() == context2);
14696 CheckContextId(instance2, 2);
14697 }
14698
14699 context1.Dispose();
14700 context2.Dispose();
14701 context3.Dispose();
14702}
Ben Murdoch257744e2011-11-30 15:57:28 +000014703
14704
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014705THREADED_TEST(CreationContextOfJsFunction) {
14706 HandleScope handle_scope;
14707 Persistent<Context> context = Context::New();
14708 InstallContextId(context, 1);
14709
14710 Local<Object> function;
14711 {
14712 Context::Scope scope(context);
14713 function = CompileRun("function foo() {}; foo").As<Object>();
14714 }
14715
14716 CHECK(function->CreationContext() == context);
14717 CheckContextId(function, 1);
14718
14719 context.Dispose();
14720}
14721
14722
Ben Murdoch257744e2011-11-30 15:57:28 +000014723Handle<Value> HasOwnPropertyIndexedPropertyGetter(uint32_t index,
14724 const AccessorInfo& info) {
14725 if (index == 42) return v8_str("yes");
14726 return Handle<v8::Integer>();
14727}
14728
14729
14730Handle<Value> HasOwnPropertyNamedPropertyGetter(Local<String> property,
14731 const AccessorInfo& info) {
14732 if (property->Equals(v8_str("foo"))) return v8_str("yes");
14733 return Handle<Value>();
14734}
14735
14736
14737Handle<v8::Integer> HasOwnPropertyIndexedPropertyQuery(
14738 uint32_t index, const AccessorInfo& info) {
14739 if (index == 42) return v8_num(1).As<v8::Integer>();
14740 return Handle<v8::Integer>();
14741}
14742
14743
14744Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery(
14745 Local<String> property, const AccessorInfo& info) {
14746 if (property->Equals(v8_str("foo"))) return v8_num(1).As<v8::Integer>();
14747 return Handle<v8::Integer>();
14748}
14749
14750
14751Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery2(
14752 Local<String> property, const AccessorInfo& info) {
14753 if (property->Equals(v8_str("bar"))) return v8_num(1).As<v8::Integer>();
14754 return Handle<v8::Integer>();
14755}
14756
14757
14758Handle<Value> HasOwnPropertyAccessorGetter(Local<String> property,
14759 const AccessorInfo& info) {
14760 return v8_str("yes");
14761}
14762
14763
14764TEST(HasOwnProperty) {
14765 v8::HandleScope scope;
14766 LocalContext env;
14767 { // Check normal properties and defined getters.
14768 Handle<Value> value = CompileRun(
14769 "function Foo() {"
14770 " this.foo = 11;"
14771 " this.__defineGetter__('baz', function() { return 1; });"
14772 "};"
14773 "function Bar() { "
14774 " this.bar = 13;"
14775 " this.__defineGetter__('bla', function() { return 2; });"
14776 "};"
14777 "Bar.prototype = new Foo();"
14778 "new Bar();");
14779 CHECK(value->IsObject());
14780 Handle<Object> object = value->ToObject();
14781 CHECK(object->Has(v8_str("foo")));
14782 CHECK(!object->HasOwnProperty(v8_str("foo")));
14783 CHECK(object->HasOwnProperty(v8_str("bar")));
14784 CHECK(object->Has(v8_str("baz")));
14785 CHECK(!object->HasOwnProperty(v8_str("baz")));
14786 CHECK(object->HasOwnProperty(v8_str("bla")));
14787 }
14788 { // Check named getter interceptors.
14789 Handle<ObjectTemplate> templ = ObjectTemplate::New();
14790 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
14791 Handle<Object> instance = templ->NewInstance();
14792 CHECK(!instance->HasOwnProperty(v8_str("42")));
14793 CHECK(instance->HasOwnProperty(v8_str("foo")));
14794 CHECK(!instance->HasOwnProperty(v8_str("bar")));
14795 }
14796 { // Check indexed getter interceptors.
14797 Handle<ObjectTemplate> templ = ObjectTemplate::New();
14798 templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
14799 Handle<Object> instance = templ->NewInstance();
14800 CHECK(instance->HasOwnProperty(v8_str("42")));
14801 CHECK(!instance->HasOwnProperty(v8_str("43")));
14802 CHECK(!instance->HasOwnProperty(v8_str("foo")));
14803 }
14804 { // Check named query interceptors.
14805 Handle<ObjectTemplate> templ = ObjectTemplate::New();
14806 templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
14807 Handle<Object> instance = templ->NewInstance();
14808 CHECK(instance->HasOwnProperty(v8_str("foo")));
14809 CHECK(!instance->HasOwnProperty(v8_str("bar")));
14810 }
14811 { // Check indexed query interceptors.
14812 Handle<ObjectTemplate> templ = ObjectTemplate::New();
14813 templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
14814 Handle<Object> instance = templ->NewInstance();
14815 CHECK(instance->HasOwnProperty(v8_str("42")));
14816 CHECK(!instance->HasOwnProperty(v8_str("41")));
14817 }
14818 { // Check callbacks.
14819 Handle<ObjectTemplate> templ = ObjectTemplate::New();
14820 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
14821 Handle<Object> instance = templ->NewInstance();
14822 CHECK(instance->HasOwnProperty(v8_str("foo")));
14823 CHECK(!instance->HasOwnProperty(v8_str("bar")));
14824 }
14825 { // Check that query wins on disagreement.
14826 Handle<ObjectTemplate> templ = ObjectTemplate::New();
14827 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
14828 0,
14829 HasOwnPropertyNamedPropertyQuery2);
14830 Handle<Object> instance = templ->NewInstance();
14831 CHECK(!instance->HasOwnProperty(v8_str("foo")));
14832 CHECK(instance->HasOwnProperty(v8_str("bar")));
14833 }
14834}
14835
14836
14837void CheckCodeGenerationAllowed() {
14838 Handle<Value> result = CompileRun("eval('42')");
14839 CHECK_EQ(42, result->Int32Value());
14840 result = CompileRun("(function(e) { return e('42'); })(eval)");
14841 CHECK_EQ(42, result->Int32Value());
14842 result = CompileRun("var f = new Function('return 42'); f()");
14843 CHECK_EQ(42, result->Int32Value());
14844}
14845
14846
14847void CheckCodeGenerationDisallowed() {
14848 TryCatch try_catch;
14849
14850 Handle<Value> result = CompileRun("eval('42')");
14851 CHECK(result.IsEmpty());
14852 CHECK(try_catch.HasCaught());
14853 try_catch.Reset();
14854
14855 result = CompileRun("(function(e) { return e('42'); })(eval)");
14856 CHECK(result.IsEmpty());
14857 CHECK(try_catch.HasCaught());
14858 try_catch.Reset();
14859
14860 result = CompileRun("var f = new Function('return 42'); f()");
14861 CHECK(result.IsEmpty());
14862 CHECK(try_catch.HasCaught());
14863}
14864
14865
14866bool CodeGenerationAllowed(Local<Context> context) {
14867 ApiTestFuzzer::Fuzz();
14868 return true;
14869}
14870
14871
14872bool CodeGenerationDisallowed(Local<Context> context) {
14873 ApiTestFuzzer::Fuzz();
14874 return false;
14875}
14876
14877
14878THREADED_TEST(AllowCodeGenFromStrings) {
14879 v8::HandleScope scope;
14880 LocalContext context;
14881
14882 // eval and the Function constructor allowed by default.
14883 CheckCodeGenerationAllowed();
14884
14885 // Disallow eval and the Function constructor.
14886 context->AllowCodeGenerationFromStrings(false);
14887 CheckCodeGenerationDisallowed();
14888
14889 // Allow again.
14890 context->AllowCodeGenerationFromStrings(true);
14891 CheckCodeGenerationAllowed();
14892
14893 // Disallow but setting a global callback that will allow the calls.
14894 context->AllowCodeGenerationFromStrings(false);
14895 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
14896 CheckCodeGenerationAllowed();
14897
14898 // Set a callback that disallows the code generation.
14899 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
14900 CheckCodeGenerationDisallowed();
14901}
14902
14903
14904static v8::Handle<Value> NonObjectThis(const v8::Arguments& args) {
14905 return v8::Undefined();
14906}
14907
14908
14909THREADED_TEST(CallAPIFunctionOnNonObject) {
14910 v8::HandleScope scope;
14911 LocalContext context;
14912 Handle<FunctionTemplate> templ = v8::FunctionTemplate::New(NonObjectThis);
14913 Handle<Function> function = templ->GetFunction();
14914 context->Global()->Set(v8_str("f"), function);
14915 TryCatch try_catch;
14916 CompileRun("f.call(2)");
14917}
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014918
14919
14920// Regression test for issue 1470.
14921THREADED_TEST(ReadOnlyIndexedProperties) {
14922 v8::HandleScope scope;
14923 Local<ObjectTemplate> templ = ObjectTemplate::New();
14924
14925 LocalContext context;
14926 Local<v8::Object> obj = templ->NewInstance();
14927 context->Global()->Set(v8_str("obj"), obj);
14928 obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
14929 obj->Set(v8_str("1"), v8_str("foobar"));
14930 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
14931 obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
14932 obj->Set(v8_num(2), v8_str("foobar"));
14933 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
14934
14935 // Test non-smi case.
14936 obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
14937 obj->Set(v8_str("2000000000"), v8_str("foobar"));
14938 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
14939}
14940
14941
14942THREADED_TEST(Regress1516) {
14943 v8::HandleScope scope;
14944
14945 LocalContext context;
14946 { v8::HandleScope temp_scope;
14947 CompileRun("({'a': 0})");
14948 }
14949
14950 int elements;
14951 { i::MapCache* map_cache =
14952 i::MapCache::cast(i::Isolate::Current()->context()->map_cache());
14953 elements = map_cache->NumberOfElements();
14954 CHECK_LE(1, elements);
14955 }
14956
14957 i::Isolate::Current()->heap()->CollectAllGarbage(true);
14958 { i::Object* raw_map_cache = i::Isolate::Current()->context()->map_cache();
14959 if (raw_map_cache != i::Isolate::Current()->heap()->undefined_value()) {
14960 i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
14961 CHECK_GT(elements, map_cache->NumberOfElements());
14962 }
14963 }
14964}
14965
14966
14967static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
14968 Local<Value> name,
14969 v8::AccessType type,
14970 Local<Value> data) {
14971 // Only block read access to __proto__.
14972 if (type == v8::ACCESS_GET &&
14973 name->IsString() &&
14974 name->ToString()->Length() == 9 &&
14975 name->ToString()->Utf8Length() == 9) {
14976 char buffer[10];
14977 CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
14978 return strncmp(buffer, "__proto__", 9) != 0;
14979 }
14980
14981 return true;
14982}
14983
14984
14985THREADED_TEST(Regress93759) {
14986 HandleScope scope;
14987
14988 // Template for object with security check.
14989 Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New();
14990 // We don't do indexing, so any callback can be used for that.
14991 no_proto_template->SetAccessCheckCallbacks(
14992 BlockProtoNamedSecurityTestCallback,
14993 IndexedSecurityTestCallback);
14994
14995 // Templates for objects with hidden prototypes and possibly security check.
14996 Local<FunctionTemplate> hidden_proto_template = v8::FunctionTemplate::New();
14997 hidden_proto_template->SetHiddenPrototype(true);
14998
14999 Local<FunctionTemplate> protected_hidden_proto_template =
15000 v8::FunctionTemplate::New();
15001 protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
15002 BlockProtoNamedSecurityTestCallback,
15003 IndexedSecurityTestCallback);
15004 protected_hidden_proto_template->SetHiddenPrototype(true);
15005
15006 // Context for "foreign" objects used in test.
15007 Persistent<Context> context = v8::Context::New();
15008 context->Enter();
15009
15010 // Plain object, no security check.
15011 Local<Object> simple_object = Object::New();
15012
15013 // Object with explicit security check.
15014 Local<Object> protected_object =
15015 no_proto_template->NewInstance();
15016
15017 // JSGlobalProxy object, always have security check.
15018 Local<Object> proxy_object =
15019 context->Global();
15020
15021 // Global object, the prototype of proxy_object. No security checks.
15022 Local<Object> global_object =
15023 proxy_object->GetPrototype()->ToObject();
15024
15025 // Hidden prototype without security check.
15026 Local<Object> hidden_prototype =
15027 hidden_proto_template->GetFunction()->NewInstance();
15028 Local<Object> object_with_hidden =
15029 Object::New();
15030 object_with_hidden->SetPrototype(hidden_prototype);
15031
15032 // Hidden prototype with security check on the hidden prototype.
15033 Local<Object> protected_hidden_prototype =
15034 protected_hidden_proto_template->GetFunction()->NewInstance();
15035 Local<Object> object_with_protected_hidden =
15036 Object::New();
15037 object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
15038
15039 context->Exit();
15040
15041 // Template for object for second context. Values to test are put on it as
15042 // properties.
15043 Local<ObjectTemplate> global_template = ObjectTemplate::New();
15044 global_template->Set(v8_str("simple"), simple_object);
15045 global_template->Set(v8_str("protected"), protected_object);
15046 global_template->Set(v8_str("global"), global_object);
15047 global_template->Set(v8_str("proxy"), proxy_object);
15048 global_template->Set(v8_str("hidden"), object_with_hidden);
15049 global_template->Set(v8_str("phidden"), object_with_protected_hidden);
15050
15051 LocalContext context2(NULL, global_template);
15052
15053 Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
15054 CHECK(result1->Equals(simple_object->GetPrototype()));
15055
15056 Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
15057 CHECK(result2->Equals(Undefined()));
15058
15059 Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
15060 CHECK(result3->Equals(global_object->GetPrototype()));
15061
15062 Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
15063 CHECK(result4->Equals(Undefined()));
15064
15065 Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
15066 CHECK(result5->Equals(
15067 object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
15068
15069 Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
15070 CHECK(result6->Equals(Undefined()));
15071
15072 context.Dispose();
15073}
Ben Murdoch69a99ed2011-11-30 16:03:39 +000015074
15075
15076static void TestReceiver(Local<Value> expected_result,
15077 Local<Value> expected_receiver,
15078 const char* code) {
15079 Local<Value> result = CompileRun(code);
15080 CHECK(result->IsObject());
15081 CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
15082 CHECK(expected_result->Equals(result->ToObject()->Get(0)));
15083}
15084
15085
15086THREADED_TEST(ForeignFunctionReceiver) {
15087 HandleScope scope;
15088
15089 // Create two contexts with different "id" properties ('i' and 'o').
15090 // Call a function both from its own context and from a the foreign
15091 // context, and see what "this" is bound to (returning both "this"
15092 // and "this.id" for comparison).
15093
15094 Persistent<Context> foreign_context = v8::Context::New();
15095 foreign_context->Enter();
15096 Local<Value> foreign_function =
15097 CompileRun("function func() { return { 0: this.id, "
15098 " 1: this, "
15099 " toString: function() { "
15100 " return this[0];"
15101 " }"
15102 " };"
15103 "}"
15104 "var id = 'i';"
15105 "func;");
15106 CHECK(foreign_function->IsFunction());
15107 foreign_context->Exit();
15108
15109 LocalContext context;
15110
15111 Local<String> password = v8_str("Password");
15112 // Don't get hit by security checks when accessing foreign_context's
15113 // global receiver (aka. global proxy).
15114 context->SetSecurityToken(password);
15115 foreign_context->SetSecurityToken(password);
15116
15117 Local<String> i = v8_str("i");
15118 Local<String> o = v8_str("o");
15119 Local<String> id = v8_str("id");
15120
15121 CompileRun("function ownfunc() { return { 0: this.id, "
15122 " 1: this, "
15123 " toString: function() { "
15124 " return this[0];"
15125 " }"
15126 " };"
15127 "}"
15128 "var id = 'o';"
15129 "ownfunc");
15130 context->Global()->Set(v8_str("func"), foreign_function);
15131
15132 // Sanity check the contexts.
15133 CHECK(i->Equals(foreign_context->Global()->Get(id)));
15134 CHECK(o->Equals(context->Global()->Get(id)));
15135
15136 // Checking local function's receiver.
15137 // Calling function using its call/apply methods.
15138 TestReceiver(o, context->Global(), "ownfunc.call()");
15139 TestReceiver(o, context->Global(), "ownfunc.apply()");
15140 // Making calls through built-in functions.
15141 TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
15142 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
15143 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
15144 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
15145 // Calling with environment record as base.
15146 TestReceiver(o, context->Global(), "ownfunc()");
15147 // Calling with no base.
15148 TestReceiver(o, context->Global(), "(1,ownfunc)()");
15149
15150 // Checking foreign function return value.
15151 // Calling function using its call/apply methods.
15152 TestReceiver(i, foreign_context->Global(), "func.call()");
15153 TestReceiver(i, foreign_context->Global(), "func.apply()");
15154 // Calling function using another context's call/apply methods.
15155 TestReceiver(i, foreign_context->Global(),
15156 "Function.prototype.call.call(func)");
15157 TestReceiver(i, foreign_context->Global(),
15158 "Function.prototype.call.apply(func)");
15159 TestReceiver(i, foreign_context->Global(),
15160 "Function.prototype.apply.call(func)");
15161 TestReceiver(i, foreign_context->Global(),
15162 "Function.prototype.apply.apply(func)");
15163 // Making calls through built-in functions.
15164 TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
15165 // ToString(func()) is func()[0], i.e., the returned this.id.
15166 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
15167 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
15168 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
15169
15170 // TODO(1547): Make the following also return "i".
15171 // Calling with environment record as base.
15172 TestReceiver(o, context->Global(), "func()");
15173 // Calling with no base.
15174 TestReceiver(o, context->Global(), "(1,func)()");
15175
15176 foreign_context.Dispose();
15177}