blob: f4ab9ad0df9b4e1f4260871a1642e435dfc44103 [file] [log] [blame]
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001// Copyright 2012 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
Ben Murdoch3ef787d2012-04-12 10:51:47 +010083static void ExpectInt32(const char* code, int expected) {
84 Local<Value> result = CompileRun(code);
85 CHECK(result->IsInt32());
86 CHECK_EQ(expected, result->Int32Value());
87}
Leon Clarked91b9f72010-01-27 17:25:45 +000088
89static void ExpectBoolean(const char* code, bool expected) {
90 Local<Value> result = CompileRun(code);
91 CHECK(result->IsBoolean());
92 CHECK_EQ(expected, result->BooleanValue());
93}
94
95
Leon Clarkef7060e22010-06-03 12:02:55 +010096static void ExpectTrue(const char* code) {
97 ExpectBoolean(code, true);
98}
99
100
Iain Merrick75681382010-08-19 15:07:18 +0100101static void ExpectFalse(const char* code) {
102 ExpectBoolean(code, false);
103}
104
105
Leon Clarked91b9f72010-01-27 17:25:45 +0000106static void ExpectObject(const char* code, Local<Value> expected) {
107 Local<Value> result = CompileRun(code);
108 CHECK(result->Equals(expected));
109}
110
111
Iain Merrick75681382010-08-19 15:07:18 +0100112static void ExpectUndefined(const char* code) {
113 Local<Value> result = CompileRun(code);
114 CHECK(result->IsUndefined());
115}
116
117
Steve Blocka7e24c12009-10-30 11:49:00 +0000118static int signature_callback_count;
119static v8::Handle<Value> IncrementingSignatureCallback(
120 const v8::Arguments& args) {
121 ApiTestFuzzer::Fuzz();
122 signature_callback_count++;
123 v8::Handle<v8::Array> result = v8::Array::New(args.Length());
124 for (int i = 0; i < args.Length(); i++)
125 result->Set(v8::Integer::New(i), args[i]);
126 return result;
127}
128
129
130static v8::Handle<Value> SignatureCallback(const v8::Arguments& args) {
131 ApiTestFuzzer::Fuzz();
132 v8::Handle<v8::Array> result = v8::Array::New(args.Length());
133 for (int i = 0; i < args.Length(); i++) {
134 result->Set(v8::Integer::New(i), args[i]);
135 }
136 return result;
137}
138
139
140THREADED_TEST(Handles) {
141 v8::HandleScope scope;
142 Local<Context> local_env;
143 {
144 LocalContext env;
145 local_env = env.local();
146 }
147
148 // Local context should still be live.
149 CHECK(!local_env.IsEmpty());
150 local_env->Enter();
151
152 v8::Handle<v8::Primitive> undef = v8::Undefined();
153 CHECK(!undef.IsEmpty());
154 CHECK(undef->IsUndefined());
155
156 const char* c_source = "1 + 2 + 3";
157 Local<String> source = String::New(c_source);
158 Local<Script> script = Script::Compile(source);
159 CHECK_EQ(6, script->Run()->Int32Value());
160
161 local_env->Exit();
162}
163
164
Steve Blocka7e24c12009-10-30 11:49:00 +0000165THREADED_TEST(ReceiverSignature) {
166 v8::HandleScope scope;
167 LocalContext env;
168 v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
169 v8::Handle<v8::Signature> sig = v8::Signature::New(fun);
170 fun->PrototypeTemplate()->Set(
171 v8_str("m"),
172 v8::FunctionTemplate::New(IncrementingSignatureCallback,
173 v8::Handle<Value>(),
174 sig));
175 env->Global()->Set(v8_str("Fun"), fun->GetFunction());
176 signature_callback_count = 0;
177 CompileRun(
178 "var o = new Fun();"
179 "o.m();");
180 CHECK_EQ(1, signature_callback_count);
181 v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New();
182 sub_fun->Inherit(fun);
183 env->Global()->Set(v8_str("SubFun"), sub_fun->GetFunction());
184 CompileRun(
185 "var o = new SubFun();"
186 "o.m();");
187 CHECK_EQ(2, signature_callback_count);
188
189 v8::TryCatch try_catch;
190 CompileRun(
191 "var o = { };"
192 "o.m = Fun.prototype.m;"
193 "o.m();");
194 CHECK_EQ(2, signature_callback_count);
195 CHECK(try_catch.HasCaught());
196 try_catch.Reset();
197 v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New();
198 sub_fun->Inherit(fun);
199 env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
200 CompileRun(
201 "var o = new UnrelFun();"
202 "o.m = Fun.prototype.m;"
203 "o.m();");
204 CHECK_EQ(2, signature_callback_count);
205 CHECK(try_catch.HasCaught());
206}
207
208
Steve Blocka7e24c12009-10-30 11:49:00 +0000209THREADED_TEST(ArgumentSignature) {
210 v8::HandleScope scope;
211 LocalContext env;
212 v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New();
213 cons->SetClassName(v8_str("Cons"));
214 v8::Handle<v8::Signature> sig =
215 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 1, &cons);
216 v8::Handle<v8::FunctionTemplate> fun =
217 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig);
218 env->Global()->Set(v8_str("Cons"), cons->GetFunction());
219 env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
220
221 v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
222 CHECK(value1->IsTrue());
223
224 v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
225 CHECK(value2->IsTrue());
226
227 v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
228 CHECK(value3->IsTrue());
229
230 v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New();
231 cons1->SetClassName(v8_str("Cons1"));
232 v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New();
233 cons2->SetClassName(v8_str("Cons2"));
234 v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New();
235 cons3->SetClassName(v8_str("Cons3"));
236
237 v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
238 v8::Handle<v8::Signature> wsig =
239 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 3, args);
240 v8::Handle<v8::FunctionTemplate> fun2 =
241 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig);
242
243 env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
244 env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
245 env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
246 env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
247 v8::Handle<Value> value4 = CompileRun(
248 "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
249 "'[object Cons1],[object Cons2],[object Cons3]'");
250 CHECK(value4->IsTrue());
251
252 v8::Handle<Value> value5 = CompileRun(
253 "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
254 CHECK(value5->IsTrue());
255
256 v8::Handle<Value> value6 = CompileRun(
257 "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
258 CHECK(value6->IsTrue());
259
260 v8::Handle<Value> value7 = CompileRun(
261 "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
262 "'[object Cons1],[object Cons2],[object Cons3],d';");
263 CHECK(value7->IsTrue());
264
265 v8::Handle<Value> value8 = CompileRun(
266 "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
267 CHECK(value8->IsTrue());
268}
269
270
271THREADED_TEST(HulIgennem) {
272 v8::HandleScope scope;
273 LocalContext env;
274 v8::Handle<v8::Primitive> undef = v8::Undefined();
275 Local<String> undef_str = undef->ToString();
276 char* value = i::NewArray<char>(undef_str->Length() + 1);
277 undef_str->WriteAscii(value);
278 CHECK_EQ(0, strcmp(value, "undefined"));
279 i::DeleteArray(value);
280}
281
282
283THREADED_TEST(Access) {
284 v8::HandleScope scope;
285 LocalContext env;
286 Local<v8::Object> obj = v8::Object::New();
287 Local<Value> foo_before = obj->Get(v8_str("foo"));
288 CHECK(foo_before->IsUndefined());
289 Local<String> bar_str = v8_str("bar");
290 obj->Set(v8_str("foo"), bar_str);
291 Local<Value> foo_after = obj->Get(v8_str("foo"));
292 CHECK(!foo_after->IsUndefined());
293 CHECK(foo_after->IsString());
294 CHECK_EQ(bar_str, foo_after);
295}
296
297
Steve Block6ded16b2010-05-10 14:33:55 +0100298THREADED_TEST(AccessElement) {
299 v8::HandleScope scope;
300 LocalContext env;
301 Local<v8::Object> obj = v8::Object::New();
302 Local<Value> before = obj->Get(1);
303 CHECK(before->IsUndefined());
304 Local<String> bar_str = v8_str("bar");
305 obj->Set(1, bar_str);
306 Local<Value> after = obj->Get(1);
307 CHECK(!after->IsUndefined());
308 CHECK(after->IsString());
309 CHECK_EQ(bar_str, after);
310
311 Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
312 CHECK_EQ(v8_str("a"), value->Get(0));
313 CHECK_EQ(v8_str("b"), value->Get(1));
314}
315
316
Steve Blocka7e24c12009-10-30 11:49:00 +0000317THREADED_TEST(Script) {
318 v8::HandleScope scope;
319 LocalContext env;
320 const char* c_source = "1 + 2 + 3";
321 Local<String> source = String::New(c_source);
322 Local<Script> script = Script::Compile(source);
323 CHECK_EQ(6, script->Run()->Int32Value());
324}
325
326
327static uint16_t* AsciiToTwoByteString(const char* source) {
Steve Blockd0582a62009-12-15 09:54:21 +0000328 int array_length = i::StrLength(source) + 1;
Steve Blocka7e24c12009-10-30 11:49:00 +0000329 uint16_t* converted = i::NewArray<uint16_t>(array_length);
Steve Blockd0582a62009-12-15 09:54:21 +0000330 for (int i = 0; i < array_length; i++) converted[i] = source[i];
Steve Blocka7e24c12009-10-30 11:49:00 +0000331 return converted;
332}
333
334
335class TestResource: public String::ExternalStringResource {
336 public:
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000337 explicit TestResource(uint16_t* data, int* counter = NULL)
338 : data_(data), length_(0), counter_(counter) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000339 while (data[length_]) ++length_;
340 }
341
342 ~TestResource() {
343 i::DeleteArray(data_);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000344 if (counter_ != NULL) ++*counter_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000345 }
346
347 const uint16_t* data() const {
348 return data_;
349 }
350
351 size_t length() const {
352 return length_;
353 }
354 private:
355 uint16_t* data_;
356 size_t length_;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000357 int* counter_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000358};
359
360
Steve Blocka7e24c12009-10-30 11:49:00 +0000361class TestAsciiResource: public String::ExternalAsciiStringResource {
362 public:
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000363 explicit TestAsciiResource(const char* data, int* counter = NULL)
364 : data_(data), length_(strlen(data)), counter_(counter) { }
Steve Blocka7e24c12009-10-30 11:49:00 +0000365
366 ~TestAsciiResource() {
367 i::DeleteArray(data_);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000368 if (counter_ != NULL) ++*counter_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000369 }
370
371 const char* data() const {
372 return data_;
373 }
374
375 size_t length() const {
376 return length_;
377 }
378 private:
379 const char* data_;
380 size_t length_;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000381 int* counter_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000382};
383
384
Steve Blocka7e24c12009-10-30 11:49:00 +0000385THREADED_TEST(ScriptUsingStringResource) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000386 int dispose_count = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +0000387 const char* c_source = "1 + 2 * 3";
388 uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
389 {
390 v8::HandleScope scope;
391 LocalContext env;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000392 TestResource* resource = new TestResource(two_byte_source, &dispose_count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000393 Local<String> source = String::NewExternal(resource);
394 Local<Script> script = Script::Compile(source);
395 Local<Value> value = script->Run();
396 CHECK(value->IsNumber());
397 CHECK_EQ(7, value->Int32Value());
398 CHECK(source->IsExternal());
399 CHECK_EQ(resource,
400 static_cast<TestResource*>(source->GetExternalStringResource()));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100401 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000402 CHECK_EQ(0, dispose_count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000403 }
Steve Block44f0eee2011-05-26 01:26:41 +0100404 v8::internal::Isolate::Current()->compilation_cache()->Clear();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100405 HEAP->CollectAllAvailableGarbage();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000406 CHECK_EQ(1, dispose_count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000407}
408
409
410THREADED_TEST(ScriptUsingAsciiStringResource) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000411 int dispose_count = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +0000412 const char* c_source = "1 + 2 * 3";
413 {
414 v8::HandleScope scope;
415 LocalContext env;
416 Local<String> source =
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000417 String::NewExternal(new TestAsciiResource(i::StrDup(c_source),
418 &dispose_count));
Steve Blocka7e24c12009-10-30 11:49:00 +0000419 Local<Script> script = Script::Compile(source);
420 Local<Value> value = script->Run();
421 CHECK(value->IsNumber());
422 CHECK_EQ(7, value->Int32Value());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100423 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000424 CHECK_EQ(0, dispose_count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000425 }
Steve Block44f0eee2011-05-26 01:26:41 +0100426 i::Isolate::Current()->compilation_cache()->Clear();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100427 HEAP->CollectAllAvailableGarbage();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000428 CHECK_EQ(1, dispose_count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000429}
430
431
432THREADED_TEST(ScriptMakingExternalString) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000433 int dispose_count = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +0000434 uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
435 {
436 v8::HandleScope scope;
437 LocalContext env;
438 Local<String> source = String::New(two_byte_source);
Andrei Popescu402d9372010-02-26 13:31:12 +0000439 // Trigger GCs so that the newly allocated string moves to old gen.
Steve Block44f0eee2011-05-26 01:26:41 +0100440 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
441 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000442 bool success = source->MakeExternal(new TestResource(two_byte_source,
443 &dispose_count));
Steve Blocka7e24c12009-10-30 11:49:00 +0000444 CHECK(success);
445 Local<Script> script = Script::Compile(source);
446 Local<Value> value = script->Run();
447 CHECK(value->IsNumber());
448 CHECK_EQ(7, value->Int32Value());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100449 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000450 CHECK_EQ(0, dispose_count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000451 }
Steve Block44f0eee2011-05-26 01:26:41 +0100452 i::Isolate::Current()->compilation_cache()->Clear();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100453 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000454 CHECK_EQ(1, dispose_count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000455}
456
457
458THREADED_TEST(ScriptMakingExternalAsciiString) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000459 int dispose_count = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +0000460 const char* c_source = "1 + 2 * 3";
461 {
462 v8::HandleScope scope;
463 LocalContext env;
464 Local<String> source = v8_str(c_source);
Andrei Popescu402d9372010-02-26 13:31:12 +0000465 // Trigger GCs so that the newly allocated string moves to old gen.
Steve Block44f0eee2011-05-26 01:26:41 +0100466 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
467 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
Steve Blocka7e24c12009-10-30 11:49:00 +0000468 bool success = source->MakeExternal(
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000469 new TestAsciiResource(i::StrDup(c_source), &dispose_count));
Steve Blocka7e24c12009-10-30 11:49:00 +0000470 CHECK(success);
471 Local<Script> script = Script::Compile(source);
472 Local<Value> value = script->Run();
473 CHECK(value->IsNumber());
474 CHECK_EQ(7, value->Int32Value());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100475 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000476 CHECK_EQ(0, dispose_count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000477 }
Steve Block44f0eee2011-05-26 01:26:41 +0100478 i::Isolate::Current()->compilation_cache()->Clear();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100479 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000480 CHECK_EQ(1, dispose_count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000481}
482
483
Andrei Popescu402d9372010-02-26 13:31:12 +0000484TEST(MakingExternalStringConditions) {
485 v8::HandleScope scope;
486 LocalContext env;
487
488 // Free some space in the new space so that we can check freshness.
Steve Block44f0eee2011-05-26 01:26:41 +0100489 HEAP->CollectGarbage(i::NEW_SPACE);
490 HEAP->CollectGarbage(i::NEW_SPACE);
Andrei Popescu402d9372010-02-26 13:31:12 +0000491
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100492 uint16_t* two_byte_string = AsciiToTwoByteString("s1");
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100493 Local<String> small_string = String::New(two_byte_string);
494 i::DeleteArray(two_byte_string);
495
Andrei Popescu402d9372010-02-26 13:31:12 +0000496 // We should refuse to externalize newly created small string.
497 CHECK(!small_string->CanMakeExternal());
498 // Trigger GCs so that the newly allocated string moves to old gen.
Steve Block44f0eee2011-05-26 01:26:41 +0100499 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
500 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
Andrei Popescu402d9372010-02-26 13:31:12 +0000501 // Old space strings should be accepted.
502 CHECK(small_string->CanMakeExternal());
503
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100504 two_byte_string = AsciiToTwoByteString("small string 2");
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100505 small_string = String::New(two_byte_string);
506 i::DeleteArray(two_byte_string);
507
Andrei Popescu402d9372010-02-26 13:31:12 +0000508 // We should refuse externalizing newly created small string.
509 CHECK(!small_string->CanMakeExternal());
510 for (int i = 0; i < 100; i++) {
511 String::Value value(small_string);
512 }
513 // Frequently used strings should be accepted.
514 CHECK(small_string->CanMakeExternal());
515
516 const int buf_size = 10 * 1024;
517 char* buf = i::NewArray<char>(buf_size);
518 memset(buf, 'a', buf_size);
519 buf[buf_size - 1] = '\0';
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100520
521 two_byte_string = AsciiToTwoByteString(buf);
522 Local<String> large_string = String::New(two_byte_string);
Andrei Popescu402d9372010-02-26 13:31:12 +0000523 i::DeleteArray(buf);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100524 i::DeleteArray(two_byte_string);
Andrei Popescu402d9372010-02-26 13:31:12 +0000525 // Large strings should be immediately accepted.
526 CHECK(large_string->CanMakeExternal());
527}
528
529
530TEST(MakingExternalAsciiStringConditions) {
531 v8::HandleScope scope;
532 LocalContext env;
533
534 // Free some space in the new space so that we can check freshness.
Steve Block44f0eee2011-05-26 01:26:41 +0100535 HEAP->CollectGarbage(i::NEW_SPACE);
536 HEAP->CollectGarbage(i::NEW_SPACE);
Andrei Popescu402d9372010-02-26 13:31:12 +0000537
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100538 Local<String> small_string = String::New("s1");
Andrei Popescu402d9372010-02-26 13:31:12 +0000539 // We should refuse to externalize newly created small string.
540 CHECK(!small_string->CanMakeExternal());
541 // Trigger GCs so that the newly allocated string moves to old gen.
Steve Block44f0eee2011-05-26 01:26:41 +0100542 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
543 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
Andrei Popescu402d9372010-02-26 13:31:12 +0000544 // Old space strings should be accepted.
545 CHECK(small_string->CanMakeExternal());
546
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100547 small_string = String::New("small string 2");
Andrei Popescu402d9372010-02-26 13:31:12 +0000548 // We should refuse externalizing newly created small string.
549 CHECK(!small_string->CanMakeExternal());
550 for (int i = 0; i < 100; i++) {
551 String::Value value(small_string);
552 }
553 // Frequently used strings should be accepted.
554 CHECK(small_string->CanMakeExternal());
555
556 const int buf_size = 10 * 1024;
557 char* buf = i::NewArray<char>(buf_size);
558 memset(buf, 'a', buf_size);
559 buf[buf_size - 1] = '\0';
560 Local<String> large_string = String::New(buf);
561 i::DeleteArray(buf);
562 // Large strings should be immediately accepted.
563 CHECK(large_string->CanMakeExternal());
564}
565
566
Steve Blocka7e24c12009-10-30 11:49:00 +0000567THREADED_TEST(UsingExternalString) {
568 {
569 v8::HandleScope scope;
570 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
571 Local<String> string =
572 String::NewExternal(new TestResource(two_byte_string));
573 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
574 // Trigger GCs so that the newly allocated string moves to old gen.
Steve Block44f0eee2011-05-26 01:26:41 +0100575 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
576 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
577 i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
Steve Blocka7e24c12009-10-30 11:49:00 +0000578 CHECK(isymbol->IsSymbol());
579 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100580 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
581 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000582}
583
584
585THREADED_TEST(UsingExternalAsciiString) {
586 {
587 v8::HandleScope scope;
588 const char* one_byte_string = "test string";
589 Local<String> string = String::NewExternal(
590 new TestAsciiResource(i::StrDup(one_byte_string)));
591 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
592 // Trigger GCs so that the newly allocated string moves to old gen.
Steve Block44f0eee2011-05-26 01:26:41 +0100593 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
594 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
595 i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
Steve Blocka7e24c12009-10-30 11:49:00 +0000596 CHECK(isymbol->IsSymbol());
597 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100598 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
599 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000600}
601
602
Leon Clarkee46be812010-01-19 14:06:41 +0000603THREADED_TEST(ScavengeExternalString) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000604 int dispose_count = 0;
Steve Block6ded16b2010-05-10 14:33:55 +0100605 bool in_new_space = false;
Leon Clarkee46be812010-01-19 14:06:41 +0000606 {
607 v8::HandleScope scope;
608 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
609 Local<String> string =
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000610 String::NewExternal(new TestResource(two_byte_string,
611 &dispose_count));
Leon Clarkee46be812010-01-19 14:06:41 +0000612 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
Steve Block44f0eee2011-05-26 01:26:41 +0100613 HEAP->CollectGarbage(i::NEW_SPACE);
614 in_new_space = HEAP->InNewSpace(*istring);
615 CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000616 CHECK_EQ(0, dispose_count);
Leon Clarkee46be812010-01-19 14:06:41 +0000617 }
Steve Block44f0eee2011-05-26 01:26:41 +0100618 HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000619 CHECK_EQ(1, dispose_count);
Leon Clarkee46be812010-01-19 14:06:41 +0000620}
621
622
623THREADED_TEST(ScavengeExternalAsciiString) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000624 int dispose_count = 0;
Steve Block6ded16b2010-05-10 14:33:55 +0100625 bool in_new_space = false;
Leon Clarkee46be812010-01-19 14:06:41 +0000626 {
627 v8::HandleScope scope;
628 const char* one_byte_string = "test string";
629 Local<String> string = String::NewExternal(
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000630 new TestAsciiResource(i::StrDup(one_byte_string), &dispose_count));
Leon Clarkee46be812010-01-19 14:06:41 +0000631 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
Steve Block44f0eee2011-05-26 01:26:41 +0100632 HEAP->CollectGarbage(i::NEW_SPACE);
633 in_new_space = HEAP->InNewSpace(*istring);
634 CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000635 CHECK_EQ(0, dispose_count);
Leon Clarkee46be812010-01-19 14:06:41 +0000636 }
Steve Block44f0eee2011-05-26 01:26:41 +0100637 HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000638 CHECK_EQ(1, dispose_count);
Leon Clarkee46be812010-01-19 14:06:41 +0000639}
640
641
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100642class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
643 public:
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000644 // Only used by non-threaded tests, so it can use static fields.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100645 static int dispose_calls;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000646 static int dispose_count;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100647
648 TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000649 : TestAsciiResource(data, &dispose_count),
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100650 dispose_(dispose) { }
651
652 void Dispose() {
653 ++dispose_calls;
654 if (dispose_) delete this;
655 }
656 private:
657 bool dispose_;
658};
659
660
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000661int TestAsciiResourceWithDisposeControl::dispose_count = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100662int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
663
664
665TEST(ExternalStringWithDisposeHandling) {
666 const char* c_source = "1 + 2 * 3";
667
668 // Use a stack allocated external string resource allocated object.
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000669 TestAsciiResourceWithDisposeControl::dispose_count = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100670 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
671 TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
672 {
673 v8::HandleScope scope;
674 LocalContext env;
675 Local<String> source = String::NewExternal(&res_stack);
676 Local<Script> script = Script::Compile(source);
677 Local<Value> value = script->Run();
678 CHECK(value->IsNumber());
679 CHECK_EQ(7, value->Int32Value());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100680 HEAP->CollectAllAvailableGarbage();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000681 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100682 }
Steve Block44f0eee2011-05-26 01:26:41 +0100683 i::Isolate::Current()->compilation_cache()->Clear();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100684 HEAP->CollectAllAvailableGarbage();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100685 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000686 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100687
688 // Use a heap allocated external string resource allocated object.
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000689 TestAsciiResourceWithDisposeControl::dispose_count = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100690 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
691 TestAsciiResource* res_heap =
692 new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
693 {
694 v8::HandleScope scope;
695 LocalContext env;
696 Local<String> source = String::NewExternal(res_heap);
697 Local<Script> script = Script::Compile(source);
698 Local<Value> value = script->Run();
699 CHECK(value->IsNumber());
700 CHECK_EQ(7, value->Int32Value());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100701 HEAP->CollectAllAvailableGarbage();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000702 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100703 }
Steve Block44f0eee2011-05-26 01:26:41 +0100704 i::Isolate::Current()->compilation_cache()->Clear();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100705 HEAP->CollectAllAvailableGarbage();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100706 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000707 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100708}
709
710
Steve Block3ce2e202009-11-05 08:53:23 +0000711THREADED_TEST(StringConcat) {
712 {
713 v8::HandleScope scope;
714 LocalContext env;
715 const char* one_byte_string_1 = "function a_times_t";
716 const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
717 const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
718 const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
719 const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
720 const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
721 const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
722 Local<String> left = v8_str(one_byte_string_1);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100723
724 uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
725 Local<String> right = String::New(two_byte_source);
726 i::DeleteArray(two_byte_source);
727
Steve Block3ce2e202009-11-05 08:53:23 +0000728 Local<String> source = String::Concat(left, right);
729 right = String::NewExternal(
730 new TestAsciiResource(i::StrDup(one_byte_extern_1)));
731 source = String::Concat(source, right);
732 right = String::NewExternal(
733 new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
734 source = String::Concat(source, right);
735 right = v8_str(one_byte_string_2);
736 source = String::Concat(source, right);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100737
738 two_byte_source = AsciiToTwoByteString(two_byte_string_2);
739 right = String::New(two_byte_source);
740 i::DeleteArray(two_byte_source);
741
Steve Block3ce2e202009-11-05 08:53:23 +0000742 source = String::Concat(source, right);
743 right = String::NewExternal(
744 new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
745 source = String::Concat(source, right);
746 Local<Script> script = Script::Compile(source);
747 Local<Value> value = script->Run();
748 CHECK(value->IsNumber());
749 CHECK_EQ(68, value->Int32Value());
750 }
Steve Block44f0eee2011-05-26 01:26:41 +0100751 i::Isolate::Current()->compilation_cache()->Clear();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100752 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
753 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Block3ce2e202009-11-05 08:53:23 +0000754}
755
756
Steve Blocka7e24c12009-10-30 11:49:00 +0000757THREADED_TEST(GlobalProperties) {
758 v8::HandleScope scope;
759 LocalContext env;
760 v8::Handle<v8::Object> global = env->Global();
761 global->Set(v8_str("pi"), v8_num(3.1415926));
762 Local<Value> pi = global->Get(v8_str("pi"));
763 CHECK_EQ(3.1415926, pi->NumberValue());
764}
765
766
767static v8::Handle<Value> handle_call(const v8::Arguments& args) {
768 ApiTestFuzzer::Fuzz();
769 return v8_num(102);
770}
771
772
773static v8::Handle<Value> construct_call(const v8::Arguments& args) {
774 ApiTestFuzzer::Fuzz();
775 args.This()->Set(v8_str("x"), v8_num(1));
776 args.This()->Set(v8_str("y"), v8_num(2));
777 return args.This();
778}
779
Ben Murdochf87a2032010-10-22 12:50:53 +0100780static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
781 ApiTestFuzzer::Fuzz();
782 return v8_num(239);
783}
784
785
Steve Blocka7e24c12009-10-30 11:49:00 +0000786THREADED_TEST(FunctionTemplate) {
787 v8::HandleScope scope;
788 LocalContext env;
789 {
790 Local<v8::FunctionTemplate> fun_templ =
791 v8::FunctionTemplate::New(handle_call);
792 Local<Function> fun = fun_templ->GetFunction();
793 env->Global()->Set(v8_str("obj"), fun);
794 Local<Script> script = v8_compile("obj()");
795 CHECK_EQ(102, script->Run()->Int32Value());
796 }
797 // Use SetCallHandler to initialize a function template, should work like the
798 // previous one.
799 {
800 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
801 fun_templ->SetCallHandler(handle_call);
802 Local<Function> fun = fun_templ->GetFunction();
803 env->Global()->Set(v8_str("obj"), fun);
804 Local<Script> script = v8_compile("obj()");
805 CHECK_EQ(102, script->Run()->Int32Value());
806 }
807 // Test constructor calls.
808 {
809 Local<v8::FunctionTemplate> fun_templ =
810 v8::FunctionTemplate::New(construct_call);
811 fun_templ->SetClassName(v8_str("funky"));
Ben Murdochf87a2032010-10-22 12:50:53 +0100812 fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), Return239);
Steve Blocka7e24c12009-10-30 11:49:00 +0000813 Local<Function> fun = fun_templ->GetFunction();
814 env->Global()->Set(v8_str("obj"), fun);
815 Local<Script> script = v8_compile("var s = new obj(); s.x");
816 CHECK_EQ(1, script->Run()->Int32Value());
817
818 Local<Value> result = v8_compile("(new obj()).toString()")->Run();
819 CHECK_EQ(v8_str("[object funky]"), result);
Ben Murdochf87a2032010-10-22 12:50:53 +0100820
821 result = v8_compile("(new obj()).m")->Run();
822 CHECK_EQ(239, result->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +0000823 }
824}
825
826
Ben Murdochb8e0da22011-05-16 14:20:40 +0100827static void* expected_ptr;
828static v8::Handle<v8::Value> callback(const v8::Arguments& args) {
829 void* ptr = v8::External::Unwrap(args.Data());
830 CHECK_EQ(expected_ptr, ptr);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000831 return v8::True();
Ben Murdochb8e0da22011-05-16 14:20:40 +0100832}
833
834
835static void TestExternalPointerWrapping() {
836 v8::HandleScope scope;
837 LocalContext env;
838
839 v8::Handle<v8::Value> data = v8::External::Wrap(expected_ptr);
840
841 v8::Handle<v8::Object> obj = v8::Object::New();
842 obj->Set(v8_str("func"),
843 v8::FunctionTemplate::New(callback, data)->GetFunction());
844 env->Global()->Set(v8_str("obj"), obj);
845
846 CHECK(CompileRun(
847 "function foo() {\n"
848 " for (var i = 0; i < 13; i++) obj.func();\n"
849 "}\n"
850 "foo(), true")->BooleanValue());
851}
852
853
854THREADED_TEST(ExternalWrap) {
855 // Check heap allocated object.
856 int* ptr = new int;
857 expected_ptr = ptr;
858 TestExternalPointerWrapping();
859 delete ptr;
860
861 // Check stack allocated object.
862 int foo;
863 expected_ptr = &foo;
864 TestExternalPointerWrapping();
865
866 // Check not aligned addresses.
867 const int n = 100;
868 char* s = new char[n];
869 for (int i = 0; i < n; i++) {
870 expected_ptr = s + i;
871 TestExternalPointerWrapping();
872 }
873
874 delete[] s;
875
876 // Check several invalid addresses.
877 expected_ptr = reinterpret_cast<void*>(1);
878 TestExternalPointerWrapping();
879
880 expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
881 TestExternalPointerWrapping();
882
883 expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
884 TestExternalPointerWrapping();
885
886#if defined(V8_HOST_ARCH_X64)
Steve Block1e0659c2011-05-24 12:43:12 +0100887 // Check a value with a leading 1 bit in x64 Smi encoding.
888 expected_ptr = reinterpret_cast<void*>(0x400000000);
889 TestExternalPointerWrapping();
890
Ben Murdochb8e0da22011-05-16 14:20:40 +0100891 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
892 TestExternalPointerWrapping();
893
894 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
895 TestExternalPointerWrapping();
896#endif
897}
898
899
Steve Blocka7e24c12009-10-30 11:49:00 +0000900THREADED_TEST(FindInstanceInPrototypeChain) {
901 v8::HandleScope scope;
902 LocalContext env;
903
904 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
905 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
906 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
907 derived->Inherit(base);
908
909 Local<v8::Function> base_function = base->GetFunction();
910 Local<v8::Function> derived_function = derived->GetFunction();
911 Local<v8::Function> other_function = other->GetFunction();
912
913 Local<v8::Object> base_instance = base_function->NewInstance();
914 Local<v8::Object> derived_instance = derived_function->NewInstance();
915 Local<v8::Object> derived_instance2 = derived_function->NewInstance();
916 Local<v8::Object> other_instance = other_function->NewInstance();
917 derived_instance2->Set(v8_str("__proto__"), derived_instance);
918 other_instance->Set(v8_str("__proto__"), derived_instance2);
919
920 // base_instance is only an instance of base.
921 CHECK_EQ(base_instance,
922 base_instance->FindInstanceInPrototypeChain(base));
923 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
924 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
925
926 // derived_instance is an instance of base and derived.
927 CHECK_EQ(derived_instance,
928 derived_instance->FindInstanceInPrototypeChain(base));
929 CHECK_EQ(derived_instance,
930 derived_instance->FindInstanceInPrototypeChain(derived));
931 CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
932
933 // other_instance is an instance of other and its immediate
934 // prototype derived_instance2 is an instance of base and derived.
935 // Note, derived_instance is an instance of base and derived too,
936 // but it comes after derived_instance2 in the prototype chain of
937 // other_instance.
938 CHECK_EQ(derived_instance2,
939 other_instance->FindInstanceInPrototypeChain(base));
940 CHECK_EQ(derived_instance2,
941 other_instance->FindInstanceInPrototypeChain(derived));
942 CHECK_EQ(other_instance,
943 other_instance->FindInstanceInPrototypeChain(other));
944}
945
946
Steve Block3ce2e202009-11-05 08:53:23 +0000947THREADED_TEST(TinyInteger) {
948 v8::HandleScope scope;
949 LocalContext env;
950 int32_t value = 239;
951 Local<v8::Integer> value_obj = v8::Integer::New(value);
952 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
953}
954
955
956THREADED_TEST(BigSmiInteger) {
957 v8::HandleScope scope;
958 LocalContext env;
959 int32_t value = i::Smi::kMaxValue;
960 // We cannot add one to a Smi::kMaxValue without wrapping.
961 if (i::kSmiValueSize < 32) {
962 CHECK(i::Smi::IsValid(value));
963 CHECK(!i::Smi::IsValid(value + 1));
964 Local<v8::Integer> value_obj = v8::Integer::New(value);
965 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
966 }
967}
968
969
970THREADED_TEST(BigInteger) {
971 v8::HandleScope scope;
972 LocalContext env;
973 // We cannot add one to a Smi::kMaxValue without wrapping.
974 if (i::kSmiValueSize < 32) {
975 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
976 // The code will not be run in that case, due to the "if" guard.
977 int32_t value =
978 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
979 CHECK(value > i::Smi::kMaxValue);
980 CHECK(!i::Smi::IsValid(value));
981 Local<v8::Integer> value_obj = v8::Integer::New(value);
982 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
983 }
984}
985
986
987THREADED_TEST(TinyUnsignedInteger) {
988 v8::HandleScope scope;
989 LocalContext env;
990 uint32_t value = 239;
991 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
992 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
993}
994
995
996THREADED_TEST(BigUnsignedSmiInteger) {
997 v8::HandleScope scope;
998 LocalContext env;
999 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1000 CHECK(i::Smi::IsValid(value));
1001 CHECK(!i::Smi::IsValid(value + 1));
1002 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1003 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1004}
1005
1006
1007THREADED_TEST(BigUnsignedInteger) {
1008 v8::HandleScope scope;
1009 LocalContext env;
1010 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1011 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1012 CHECK(!i::Smi::IsValid(value));
1013 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1014 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1015}
1016
1017
1018THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1019 v8::HandleScope scope;
1020 LocalContext env;
1021 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1022 uint32_t value = INT32_MAX_AS_UINT + 1;
1023 CHECK(value > INT32_MAX_AS_UINT); // No overflow.
1024 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1025 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1026}
1027
1028
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001029THREADED_TEST(IsNativeError) {
1030 v8::HandleScope scope;
1031 LocalContext env;
1032 v8::Handle<Value> syntax_error = CompileRun(
1033 "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1034 CHECK(syntax_error->IsNativeError());
1035 v8::Handle<Value> not_error = CompileRun("{a:42}");
1036 CHECK(!not_error->IsNativeError());
1037 v8::Handle<Value> not_object = CompileRun("42");
1038 CHECK(!not_object->IsNativeError());
1039}
1040
1041
1042THREADED_TEST(StringObject) {
1043 v8::HandleScope scope;
1044 LocalContext env;
1045 v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1046 CHECK(boxed_string->IsStringObject());
1047 v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1048 CHECK(!unboxed_string->IsStringObject());
1049 v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1050 CHECK(!boxed_not_string->IsStringObject());
1051 v8::Handle<Value> not_object = CompileRun("0");
1052 CHECK(!not_object->IsStringObject());
1053 v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1054 CHECK(!as_boxed.IsEmpty());
1055 Local<v8::String> the_string = as_boxed->StringValue();
1056 CHECK(!the_string.IsEmpty());
1057 ExpectObject("\"test\"", the_string);
1058 v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1059 CHECK(new_boxed_string->IsStringObject());
1060 as_boxed = new_boxed_string.As<v8::StringObject>();
1061 the_string = as_boxed->StringValue();
1062 CHECK(!the_string.IsEmpty());
1063 ExpectObject("\"test\"", the_string);
1064}
1065
1066
1067THREADED_TEST(NumberObject) {
1068 v8::HandleScope scope;
1069 LocalContext env;
1070 v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1071 CHECK(boxed_number->IsNumberObject());
1072 v8::Handle<Value> unboxed_number = CompileRun("42");
1073 CHECK(!unboxed_number->IsNumberObject());
1074 v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1075 CHECK(!boxed_not_number->IsNumberObject());
1076 v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1077 CHECK(!as_boxed.IsEmpty());
1078 double the_number = as_boxed->NumberValue();
1079 CHECK_EQ(42.0, the_number);
1080 v8::Handle<v8::Value> new_boxed_number = v8::NumberObject::New(43);
1081 CHECK(new_boxed_number->IsNumberObject());
1082 as_boxed = new_boxed_number.As<v8::NumberObject>();
1083 the_number = as_boxed->NumberValue();
1084 CHECK_EQ(43.0, the_number);
1085}
1086
1087
1088THREADED_TEST(BooleanObject) {
1089 v8::HandleScope scope;
1090 LocalContext env;
1091 v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1092 CHECK(boxed_boolean->IsBooleanObject());
1093 v8::Handle<Value> unboxed_boolean = CompileRun("true");
1094 CHECK(!unboxed_boolean->IsBooleanObject());
1095 v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1096 CHECK(!boxed_not_boolean->IsBooleanObject());
1097 v8::Handle<v8::BooleanObject> as_boxed =
1098 boxed_boolean.As<v8::BooleanObject>();
1099 CHECK(!as_boxed.IsEmpty());
1100 bool the_boolean = as_boxed->BooleanValue();
1101 CHECK_EQ(true, the_boolean);
1102 v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1103 v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1104 CHECK(boxed_true->IsBooleanObject());
1105 CHECK(boxed_false->IsBooleanObject());
1106 as_boxed = boxed_true.As<v8::BooleanObject>();
1107 CHECK_EQ(true, as_boxed->BooleanValue());
1108 as_boxed = boxed_false.As<v8::BooleanObject>();
1109 CHECK_EQ(false, as_boxed->BooleanValue());
1110}
1111
1112
Steve Blocka7e24c12009-10-30 11:49:00 +00001113THREADED_TEST(Number) {
1114 v8::HandleScope scope;
1115 LocalContext env;
1116 double PI = 3.1415926;
1117 Local<v8::Number> pi_obj = v8::Number::New(PI);
1118 CHECK_EQ(PI, pi_obj->NumberValue());
1119}
1120
1121
1122THREADED_TEST(ToNumber) {
1123 v8::HandleScope scope;
1124 LocalContext env;
1125 Local<String> str = v8_str("3.1415926");
1126 CHECK_EQ(3.1415926, str->NumberValue());
1127 v8::Handle<v8::Boolean> t = v8::True();
1128 CHECK_EQ(1.0, t->NumberValue());
1129 v8::Handle<v8::Boolean> f = v8::False();
1130 CHECK_EQ(0.0, f->NumberValue());
1131}
1132
1133
1134THREADED_TEST(Date) {
1135 v8::HandleScope scope;
1136 LocalContext env;
1137 double PI = 3.1415926;
Ben Murdoch257744e2011-11-30 15:57:28 +00001138 Local<Value> date = v8::Date::New(PI);
1139 CHECK_EQ(3.0, date->NumberValue());
1140 date.As<v8::Date>()->Set(v8_str("property"), v8::Integer::New(42));
1141 CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00001142}
1143
1144
1145THREADED_TEST(Boolean) {
1146 v8::HandleScope scope;
1147 LocalContext env;
1148 v8::Handle<v8::Boolean> t = v8::True();
1149 CHECK(t->Value());
1150 v8::Handle<v8::Boolean> f = v8::False();
1151 CHECK(!f->Value());
1152 v8::Handle<v8::Primitive> u = v8::Undefined();
1153 CHECK(!u->BooleanValue());
1154 v8::Handle<v8::Primitive> n = v8::Null();
1155 CHECK(!n->BooleanValue());
1156 v8::Handle<String> str1 = v8_str("");
1157 CHECK(!str1->BooleanValue());
1158 v8::Handle<String> str2 = v8_str("x");
1159 CHECK(str2->BooleanValue());
1160 CHECK(!v8::Number::New(0)->BooleanValue());
1161 CHECK(v8::Number::New(-1)->BooleanValue());
1162 CHECK(v8::Number::New(1)->BooleanValue());
1163 CHECK(v8::Number::New(42)->BooleanValue());
1164 CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1165}
1166
1167
1168static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
1169 ApiTestFuzzer::Fuzz();
1170 return v8_num(13.4);
1171}
1172
1173
1174static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
1175 ApiTestFuzzer::Fuzz();
1176 return v8_num(876);
1177}
1178
1179
1180THREADED_TEST(GlobalPrototype) {
1181 v8::HandleScope scope;
1182 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
1183 func_templ->PrototypeTemplate()->Set(
1184 "dummy",
1185 v8::FunctionTemplate::New(DummyCallHandler));
1186 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1187 templ->Set("x", v8_num(200));
1188 templ->SetAccessor(v8_str("m"), GetM);
1189 LocalContext env(0, templ);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001190 v8::Handle<Script> script(v8_compile("dummy()"));
1191 v8::Handle<Value> result(script->Run());
Steve Blocka7e24c12009-10-30 11:49:00 +00001192 CHECK_EQ(13.4, result->NumberValue());
1193 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1194 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1195}
1196
1197
Steve Blocka7e24c12009-10-30 11:49:00 +00001198THREADED_TEST(ObjectTemplate) {
1199 v8::HandleScope scope;
1200 Local<ObjectTemplate> templ1 = ObjectTemplate::New();
1201 templ1->Set("x", v8_num(10));
1202 templ1->Set("y", v8_num(13));
1203 LocalContext env;
1204 Local<v8::Object> instance1 = templ1->NewInstance();
1205 env->Global()->Set(v8_str("p"), instance1);
1206 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1207 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1208 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
1209 fun->PrototypeTemplate()->Set("nirk", v8_num(123));
1210 Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1211 templ2->Set("a", v8_num(12));
1212 templ2->Set("b", templ1);
1213 Local<v8::Object> instance2 = templ2->NewInstance();
1214 env->Global()->Set(v8_str("q"), instance2);
1215 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1216 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1217 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1218 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1219}
1220
1221
1222static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
1223 ApiTestFuzzer::Fuzz();
1224 return v8_num(17.2);
1225}
1226
1227
1228static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
1229 ApiTestFuzzer::Fuzz();
1230 return v8_num(15.2);
1231}
1232
1233
1234THREADED_TEST(DescriptorInheritance) {
1235 v8::HandleScope scope;
1236 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
1237 super->PrototypeTemplate()->Set("flabby",
1238 v8::FunctionTemplate::New(GetFlabby));
1239 super->PrototypeTemplate()->Set("PI", v8_num(3.14));
1240
1241 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1242
1243 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
1244 base1->Inherit(super);
1245 base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
1246
1247 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
1248 base2->Inherit(super);
1249 base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
1250
1251 LocalContext env;
1252
1253 env->Global()->Set(v8_str("s"), super->GetFunction());
1254 env->Global()->Set(v8_str("base1"), base1->GetFunction());
1255 env->Global()->Set(v8_str("base2"), base2->GetFunction());
1256
1257 // Checks right __proto__ chain.
1258 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1259 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1260
1261 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1262
1263 // Instance accessor should not be visible on function object or its prototype
1264 CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1265 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1266 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1267
1268 env->Global()->Set(v8_str("obj"),
1269 base1->GetFunction()->NewInstance());
1270 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1271 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1272 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1273 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1274 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1275
1276 env->Global()->Set(v8_str("obj2"),
1277 base2->GetFunction()->NewInstance());
1278 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1279 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1280 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1281 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1282 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1283
1284 // base1 and base2 cannot cross reference to each's prototype
1285 CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1286 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1287}
1288
1289
1290int echo_named_call_count;
1291
1292
1293static v8::Handle<Value> EchoNamedProperty(Local<String> name,
1294 const AccessorInfo& info) {
1295 ApiTestFuzzer::Fuzz();
1296 CHECK_EQ(v8_str("data"), info.Data());
1297 echo_named_call_count++;
1298 return name;
1299}
1300
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001301// Helper functions for Interceptor/Accessor interaction tests
1302
1303Handle<Value> SimpleAccessorGetter(Local<String> name,
1304 const AccessorInfo& info) {
1305 Handle<Object> self = info.This();
1306 return self->Get(String::Concat(v8_str("accessor_"), name));
1307}
1308
1309void SimpleAccessorSetter(Local<String> name, Local<Value> value,
1310 const AccessorInfo& info) {
1311 Handle<Object> self = info.This();
1312 self->Set(String::Concat(v8_str("accessor_"), name), value);
1313}
1314
1315Handle<Value> EmptyInterceptorGetter(Local<String> name,
1316 const AccessorInfo& info) {
1317 return Handle<Value>();
1318}
1319
1320Handle<Value> EmptyInterceptorSetter(Local<String> name,
1321 Local<Value> value,
1322 const AccessorInfo& info) {
1323 return Handle<Value>();
1324}
1325
1326Handle<Value> InterceptorGetter(Local<String> name,
1327 const AccessorInfo& info) {
1328 // Intercept names that start with 'interceptor_'.
1329 String::AsciiValue ascii(name);
1330 char* name_str = *ascii;
1331 char prefix[] = "interceptor_";
1332 int i;
1333 for (i = 0; name_str[i] && prefix[i]; ++i) {
1334 if (name_str[i] != prefix[i]) return Handle<Value>();
1335 }
1336 Handle<Object> self = info.This();
1337 return self->GetHiddenValue(v8_str(name_str + i));
1338}
1339
1340Handle<Value> InterceptorSetter(Local<String> name,
1341 Local<Value> value,
1342 const AccessorInfo& info) {
1343 // Intercept accesses that set certain integer values.
1344 if (value->IsInt32() && value->Int32Value() < 10000) {
1345 Handle<Object> self = info.This();
1346 self->SetHiddenValue(name, value);
1347 return value;
1348 }
1349 return Handle<Value>();
1350}
1351
1352void AddAccessor(Handle<FunctionTemplate> templ,
1353 Handle<String> name,
1354 v8::AccessorGetter getter,
1355 v8::AccessorSetter setter) {
1356 templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
1357}
1358
1359void AddInterceptor(Handle<FunctionTemplate> templ,
1360 v8::NamedPropertyGetter getter,
1361 v8::NamedPropertySetter setter) {
1362 templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
1363}
1364
1365THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
1366 v8::HandleScope scope;
1367 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1368 Handle<FunctionTemplate> child = FunctionTemplate::New();
1369 child->Inherit(parent);
1370 AddAccessor(parent, v8_str("age"),
1371 SimpleAccessorGetter, SimpleAccessorSetter);
1372 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1373 LocalContext env;
1374 env->Global()->Set(v8_str("Child"), child->GetFunction());
1375 CompileRun("var child = new Child;"
1376 "child.age = 10;");
1377 ExpectBoolean("child.hasOwnProperty('age')", false);
1378 ExpectInt32("child.age", 10);
1379 ExpectInt32("child.accessor_age", 10);
1380}
1381
1382THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
1383 v8::HandleScope scope;
1384 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1385 Handle<FunctionTemplate> child = FunctionTemplate::New();
1386 child->Inherit(parent);
1387 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1388 LocalContext env;
1389 env->Global()->Set(v8_str("Child"), child->GetFunction());
1390 CompileRun("var child = new Child;"
1391 "var parent = child.__proto__;"
1392 "Object.defineProperty(parent, 'age', "
1393 " {get: function(){ return this.accessor_age; }, "
1394 " set: function(v){ this.accessor_age = v; }, "
1395 " enumerable: true, configurable: true});"
1396 "child.age = 10;");
1397 ExpectBoolean("child.hasOwnProperty('age')", false);
1398 ExpectInt32("child.age", 10);
1399 ExpectInt32("child.accessor_age", 10);
1400}
1401
1402THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
1403 v8::HandleScope scope;
1404 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1405 Handle<FunctionTemplate> child = FunctionTemplate::New();
1406 child->Inherit(parent);
1407 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1408 LocalContext env;
1409 env->Global()->Set(v8_str("Child"), child->GetFunction());
1410 CompileRun("var child = new Child;"
1411 "var parent = child.__proto__;"
1412 "parent.name = 'Alice';");
1413 ExpectBoolean("child.hasOwnProperty('name')", false);
1414 ExpectString("child.name", "Alice");
1415 CompileRun("child.name = 'Bob';");
1416 ExpectString("child.name", "Bob");
1417 ExpectBoolean("child.hasOwnProperty('name')", true);
1418 ExpectString("parent.name", "Alice");
1419}
1420
1421THREADED_TEST(SwitchFromInterceptorToAccessor) {
1422 v8::HandleScope scope;
1423 Handle<FunctionTemplate> templ = FunctionTemplate::New();
1424 AddAccessor(templ, v8_str("age"),
1425 SimpleAccessorGetter, SimpleAccessorSetter);
1426 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1427 LocalContext env;
1428 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1429 CompileRun("var obj = new Obj;"
1430 "function setAge(i){ obj.age = i; };"
1431 "for(var i = 0; i <= 10000; i++) setAge(i);");
1432 // All i < 10000 go to the interceptor.
1433 ExpectInt32("obj.interceptor_age", 9999);
1434 // The last i goes to the accessor.
1435 ExpectInt32("obj.accessor_age", 10000);
1436}
1437
1438THREADED_TEST(SwitchFromAccessorToInterceptor) {
1439 v8::HandleScope scope;
1440 Handle<FunctionTemplate> templ = FunctionTemplate::New();
1441 AddAccessor(templ, v8_str("age"),
1442 SimpleAccessorGetter, SimpleAccessorSetter);
1443 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1444 LocalContext env;
1445 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1446 CompileRun("var obj = new Obj;"
1447 "function setAge(i){ obj.age = i; };"
1448 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1449 // All i >= 10000 go to the accessor.
1450 ExpectInt32("obj.accessor_age", 10000);
1451 // The last i goes to the interceptor.
1452 ExpectInt32("obj.interceptor_age", 9999);
1453}
1454
1455THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
1456 v8::HandleScope scope;
1457 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1458 Handle<FunctionTemplate> child = FunctionTemplate::New();
1459 child->Inherit(parent);
1460 AddAccessor(parent, v8_str("age"),
1461 SimpleAccessorGetter, SimpleAccessorSetter);
1462 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1463 LocalContext env;
1464 env->Global()->Set(v8_str("Child"), child->GetFunction());
1465 CompileRun("var child = new Child;"
1466 "function setAge(i){ child.age = i; };"
1467 "for(var i = 0; i <= 10000; i++) setAge(i);");
1468 // All i < 10000 go to the interceptor.
1469 ExpectInt32("child.interceptor_age", 9999);
1470 // The last i goes to the accessor.
1471 ExpectInt32("child.accessor_age", 10000);
1472}
1473
1474THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
1475 v8::HandleScope scope;
1476 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1477 Handle<FunctionTemplate> child = FunctionTemplate::New();
1478 child->Inherit(parent);
1479 AddAccessor(parent, v8_str("age"),
1480 SimpleAccessorGetter, SimpleAccessorSetter);
1481 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1482 LocalContext env;
1483 env->Global()->Set(v8_str("Child"), child->GetFunction());
1484 CompileRun("var child = new Child;"
1485 "function setAge(i){ child.age = i; };"
1486 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1487 // All i >= 10000 go to the accessor.
1488 ExpectInt32("child.accessor_age", 10000);
1489 // The last i goes to the interceptor.
1490 ExpectInt32("child.interceptor_age", 9999);
1491}
1492
1493THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
1494 v8::HandleScope scope;
1495 Handle<FunctionTemplate> templ = FunctionTemplate::New();
1496 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1497 LocalContext env;
1498 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1499 CompileRun("var obj = new Obj;"
1500 "function setter(i) { this.accessor_age = i; };"
1501 "function getter() { return this.accessor_age; };"
1502 "function setAge(i) { obj.age = i; };"
1503 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
1504 "for(var i = 0; i <= 10000; i++) setAge(i);");
1505 // All i < 10000 go to the interceptor.
1506 ExpectInt32("obj.interceptor_age", 9999);
1507 // The last i goes to the JavaScript accessor.
1508 ExpectInt32("obj.accessor_age", 10000);
1509 // The installed JavaScript getter is still intact.
1510 // This last part is a regression test for issue 1651 and relies on the fact
1511 // that both interceptor and accessor are being installed on the same object.
1512 ExpectInt32("obj.age", 10000);
1513 ExpectBoolean("obj.hasOwnProperty('age')", true);
1514 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
1515}
1516
1517THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
1518 v8::HandleScope scope;
1519 Handle<FunctionTemplate> templ = FunctionTemplate::New();
1520 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1521 LocalContext env;
1522 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1523 CompileRun("var obj = new Obj;"
1524 "function setter(i) { this.accessor_age = i; };"
1525 "function getter() { return this.accessor_age; };"
1526 "function setAge(i) { obj.age = i; };"
1527 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
1528 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1529 // All i >= 10000 go to the accessor.
1530 ExpectInt32("obj.accessor_age", 10000);
1531 // The last i goes to the interceptor.
1532 ExpectInt32("obj.interceptor_age", 9999);
1533 // The installed JavaScript getter is still intact.
1534 // This last part is a regression test for issue 1651 and relies on the fact
1535 // that both interceptor and accessor are being installed on the same object.
1536 ExpectInt32("obj.age", 10000);
1537 ExpectBoolean("obj.hasOwnProperty('age')", true);
1538 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
1539}
1540
1541THREADED_TEST(SwitchFromInterceptorToProperty) {
1542 v8::HandleScope scope;
1543 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1544 Handle<FunctionTemplate> child = FunctionTemplate::New();
1545 child->Inherit(parent);
1546 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1547 LocalContext env;
1548 env->Global()->Set(v8_str("Child"), child->GetFunction());
1549 CompileRun("var child = new Child;"
1550 "function setAge(i){ child.age = i; };"
1551 "for(var i = 0; i <= 10000; i++) setAge(i);");
1552 // All i < 10000 go to the interceptor.
1553 ExpectInt32("child.interceptor_age", 9999);
1554 // The last i goes to child's own property.
1555 ExpectInt32("child.age", 10000);
1556}
1557
1558THREADED_TEST(SwitchFromPropertyToInterceptor) {
1559 v8::HandleScope scope;
1560 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1561 Handle<FunctionTemplate> child = FunctionTemplate::New();
1562 child->Inherit(parent);
1563 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1564 LocalContext env;
1565 env->Global()->Set(v8_str("Child"), child->GetFunction());
1566 CompileRun("var child = new Child;"
1567 "function setAge(i){ child.age = i; };"
1568 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1569 // All i >= 10000 go to child's own property.
1570 ExpectInt32("child.age", 10000);
1571 // The last i goes to the interceptor.
1572 ExpectInt32("child.interceptor_age", 9999);
1573}
Steve Blocka7e24c12009-10-30 11:49:00 +00001574
1575THREADED_TEST(NamedPropertyHandlerGetter) {
1576 echo_named_call_count = 0;
1577 v8::HandleScope scope;
1578 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1579 templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
1580 0, 0, 0, 0,
1581 v8_str("data"));
1582 LocalContext env;
1583 env->Global()->Set(v8_str("obj"),
1584 templ->GetFunction()->NewInstance());
1585 CHECK_EQ(echo_named_call_count, 0);
1586 v8_compile("obj.x")->Run();
1587 CHECK_EQ(echo_named_call_count, 1);
1588 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
1589 v8::Handle<Value> str = CompileRun(code);
1590 String::AsciiValue value(str);
1591 CHECK_EQ(*value, "oddlepoddle");
1592 // Check default behavior
1593 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
1594 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
1595 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
1596}
1597
1598
1599int echo_indexed_call_count = 0;
1600
1601
1602static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
1603 const AccessorInfo& info) {
1604 ApiTestFuzzer::Fuzz();
1605 CHECK_EQ(v8_num(637), info.Data());
1606 echo_indexed_call_count++;
1607 return v8_num(index);
1608}
1609
1610
1611THREADED_TEST(IndexedPropertyHandlerGetter) {
1612 v8::HandleScope scope;
1613 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1614 templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
1615 0, 0, 0, 0,
1616 v8_num(637));
1617 LocalContext env;
1618 env->Global()->Set(v8_str("obj"),
1619 templ->GetFunction()->NewInstance());
1620 Local<Script> script = v8_compile("obj[900]");
1621 CHECK_EQ(script->Run()->Int32Value(), 900);
1622}
1623
1624
1625v8::Handle<v8::Object> bottom;
1626
1627static v8::Handle<Value> CheckThisIndexedPropertyHandler(
1628 uint32_t index,
1629 const AccessorInfo& info) {
1630 ApiTestFuzzer::Fuzz();
1631 CHECK(info.This()->Equals(bottom));
1632 return v8::Handle<Value>();
1633}
1634
1635static v8::Handle<Value> CheckThisNamedPropertyHandler(
1636 Local<String> name,
1637 const AccessorInfo& info) {
1638 ApiTestFuzzer::Fuzz();
1639 CHECK(info.This()->Equals(bottom));
1640 return v8::Handle<Value>();
1641}
1642
1643
1644v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
1645 Local<Value> value,
1646 const AccessorInfo& info) {
1647 ApiTestFuzzer::Fuzz();
1648 CHECK(info.This()->Equals(bottom));
1649 return v8::Handle<Value>();
1650}
1651
1652
1653v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
1654 Local<Value> value,
1655 const AccessorInfo& info) {
1656 ApiTestFuzzer::Fuzz();
1657 CHECK(info.This()->Equals(bottom));
1658 return v8::Handle<Value>();
1659}
1660
Iain Merrick75681382010-08-19 15:07:18 +01001661v8::Handle<v8::Integer> CheckThisIndexedPropertyQuery(
Steve Blocka7e24c12009-10-30 11:49:00 +00001662 uint32_t index,
1663 const AccessorInfo& info) {
1664 ApiTestFuzzer::Fuzz();
1665 CHECK(info.This()->Equals(bottom));
Iain Merrick75681382010-08-19 15:07:18 +01001666 return v8::Handle<v8::Integer>();
Steve Blocka7e24c12009-10-30 11:49:00 +00001667}
1668
1669
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001670v8::Handle<v8::Integer> CheckThisNamedPropertyQuery(Local<String> property,
Steve Blocka7e24c12009-10-30 11:49:00 +00001671 const AccessorInfo& info) {
1672 ApiTestFuzzer::Fuzz();
1673 CHECK(info.This()->Equals(bottom));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001674 return v8::Handle<v8::Integer>();
Steve Blocka7e24c12009-10-30 11:49:00 +00001675}
1676
1677
1678v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
1679 uint32_t index,
1680 const AccessorInfo& info) {
1681 ApiTestFuzzer::Fuzz();
1682 CHECK(info.This()->Equals(bottom));
1683 return v8::Handle<v8::Boolean>();
1684}
1685
1686
1687v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
1688 Local<String> property,
1689 const AccessorInfo& info) {
1690 ApiTestFuzzer::Fuzz();
1691 CHECK(info.This()->Equals(bottom));
1692 return v8::Handle<v8::Boolean>();
1693}
1694
1695
1696v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
1697 const AccessorInfo& info) {
1698 ApiTestFuzzer::Fuzz();
1699 CHECK(info.This()->Equals(bottom));
1700 return v8::Handle<v8::Array>();
1701}
1702
1703
1704v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
1705 const AccessorInfo& info) {
1706 ApiTestFuzzer::Fuzz();
1707 CHECK(info.This()->Equals(bottom));
1708 return v8::Handle<v8::Array>();
1709}
1710
1711
1712THREADED_TEST(PropertyHandlerInPrototype) {
1713 v8::HandleScope scope;
1714 LocalContext env;
1715
1716 // Set up a prototype chain with three interceptors.
1717 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1718 templ->InstanceTemplate()->SetIndexedPropertyHandler(
1719 CheckThisIndexedPropertyHandler,
1720 CheckThisIndexedPropertySetter,
1721 CheckThisIndexedPropertyQuery,
1722 CheckThisIndexedPropertyDeleter,
1723 CheckThisIndexedPropertyEnumerator);
1724
1725 templ->InstanceTemplate()->SetNamedPropertyHandler(
1726 CheckThisNamedPropertyHandler,
1727 CheckThisNamedPropertySetter,
1728 CheckThisNamedPropertyQuery,
1729 CheckThisNamedPropertyDeleter,
1730 CheckThisNamedPropertyEnumerator);
1731
1732 bottom = templ->GetFunction()->NewInstance();
1733 Local<v8::Object> top = templ->GetFunction()->NewInstance();
1734 Local<v8::Object> middle = templ->GetFunction()->NewInstance();
1735
1736 bottom->Set(v8_str("__proto__"), middle);
1737 middle->Set(v8_str("__proto__"), top);
1738 env->Global()->Set(v8_str("obj"), bottom);
1739
1740 // Indexed and named get.
1741 Script::Compile(v8_str("obj[0]"))->Run();
1742 Script::Compile(v8_str("obj.x"))->Run();
1743
1744 // Indexed and named set.
1745 Script::Compile(v8_str("obj[1] = 42"))->Run();
1746 Script::Compile(v8_str("obj.y = 42"))->Run();
1747
1748 // Indexed and named query.
1749 Script::Compile(v8_str("0 in obj"))->Run();
1750 Script::Compile(v8_str("'x' in obj"))->Run();
1751
1752 // Indexed and named deleter.
1753 Script::Compile(v8_str("delete obj[0]"))->Run();
1754 Script::Compile(v8_str("delete obj.x"))->Run();
1755
1756 // Enumerators.
1757 Script::Compile(v8_str("for (var p in obj) ;"))->Run();
1758}
1759
1760
1761static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
1762 const AccessorInfo& info) {
1763 ApiTestFuzzer::Fuzz();
1764 if (v8_str("pre")->Equals(key)) {
1765 return v8_str("PrePropertyHandler: pre");
1766 }
1767 return v8::Handle<String>();
1768}
1769
1770
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001771static v8::Handle<v8::Integer> PrePropertyHandlerQuery(Local<String> key,
1772 const AccessorInfo&) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001773 if (v8_str("pre")->Equals(key)) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001774 return v8::Integer::New(v8::None);
Steve Blocka7e24c12009-10-30 11:49:00 +00001775 }
1776
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001777 return v8::Handle<v8::Integer>(); // do not intercept the call
Steve Blocka7e24c12009-10-30 11:49:00 +00001778}
1779
1780
1781THREADED_TEST(PrePropertyHandler) {
1782 v8::HandleScope scope;
1783 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
1784 desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
1785 0,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001786 PrePropertyHandlerQuery);
Steve Blocka7e24c12009-10-30 11:49:00 +00001787 LocalContext env(NULL, desc->InstanceTemplate());
1788 Script::Compile(v8_str(
1789 "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
1790 v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
1791 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
1792 v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
1793 CHECK_EQ(v8_str("Object: on"), result_on);
1794 v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
1795 CHECK(result_post.IsEmpty());
1796}
1797
1798
1799THREADED_TEST(UndefinedIsNotEnumerable) {
1800 v8::HandleScope scope;
1801 LocalContext env;
1802 v8::Handle<Value> result = Script::Compile(v8_str(
1803 "this.propertyIsEnumerable(undefined)"))->Run();
1804 CHECK(result->IsFalse());
1805}
1806
1807
1808v8::Handle<Script> call_recursively_script;
Leon Clarke4515c472010-02-03 11:58:03 +00001809static const int kTargetRecursionDepth = 200; // near maximum
Steve Blocka7e24c12009-10-30 11:49:00 +00001810
1811
1812static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
1813 ApiTestFuzzer::Fuzz();
1814 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1815 if (depth == kTargetRecursionDepth) return v8::Undefined();
1816 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1817 return call_recursively_script->Run();
1818}
1819
1820
1821static v8::Handle<Value> CallFunctionRecursivelyCall(
1822 const v8::Arguments& args) {
1823 ApiTestFuzzer::Fuzz();
1824 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1825 if (depth == kTargetRecursionDepth) {
1826 printf("[depth = %d]\n", depth);
1827 return v8::Undefined();
1828 }
1829 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1830 v8::Handle<Value> function =
1831 args.This()->Get(v8_str("callFunctionRecursively"));
Steve Block6ded16b2010-05-10 14:33:55 +01001832 return function.As<Function>()->Call(args.This(), 0, NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001833}
1834
1835
1836THREADED_TEST(DeepCrossLanguageRecursion) {
1837 v8::HandleScope scope;
1838 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
1839 global->Set(v8_str("callScriptRecursively"),
1840 v8::FunctionTemplate::New(CallScriptRecursivelyCall));
1841 global->Set(v8_str("callFunctionRecursively"),
1842 v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
1843 LocalContext env(NULL, global);
1844
1845 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1846 call_recursively_script = v8_compile("callScriptRecursively()");
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001847 call_recursively_script->Run();
Steve Blocka7e24c12009-10-30 11:49:00 +00001848 call_recursively_script = v8::Handle<Script>();
1849
1850 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1851 Script::Compile(v8_str("callFunctionRecursively()"))->Run();
1852}
1853
1854
1855static v8::Handle<Value>
1856 ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1857 ApiTestFuzzer::Fuzz();
1858 return v8::ThrowException(key);
1859}
1860
1861
1862static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
1863 Local<Value>,
1864 const AccessorInfo&) {
1865 v8::ThrowException(key);
1866 return v8::Undefined(); // not the same as v8::Handle<v8::Value>()
1867}
1868
1869
1870THREADED_TEST(CallbackExceptionRegression) {
1871 v8::HandleScope scope;
1872 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1873 obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
1874 ThrowingPropertyHandlerSet);
1875 LocalContext env;
1876 env->Global()->Set(v8_str("obj"), obj->NewInstance());
1877 v8::Handle<Value> otto = Script::Compile(v8_str(
1878 "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
1879 CHECK_EQ(v8_str("otto"), otto);
1880 v8::Handle<Value> netto = Script::Compile(v8_str(
1881 "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
1882 CHECK_EQ(v8_str("netto"), netto);
1883}
1884
1885
Steve Blocka7e24c12009-10-30 11:49:00 +00001886THREADED_TEST(FunctionPrototype) {
1887 v8::HandleScope scope;
1888 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
1889 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
1890 LocalContext env;
1891 env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
1892 Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
1893 CHECK_EQ(script->Run()->Int32Value(), 321);
1894}
1895
1896
1897THREADED_TEST(InternalFields) {
1898 v8::HandleScope scope;
1899 LocalContext env;
1900
1901 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1902 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1903 instance_templ->SetInternalFieldCount(1);
1904 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1905 CHECK_EQ(1, obj->InternalFieldCount());
1906 CHECK(obj->GetInternalField(0)->IsUndefined());
1907 obj->SetInternalField(0, v8_num(17));
1908 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
1909}
1910
1911
Steve Block6ded16b2010-05-10 14:33:55 +01001912THREADED_TEST(GlobalObjectInternalFields) {
1913 v8::HandleScope scope;
1914 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
1915 global_template->SetInternalFieldCount(1);
1916 LocalContext env(NULL, global_template);
1917 v8::Handle<v8::Object> global_proxy = env->Global();
1918 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
1919 CHECK_EQ(1, global->InternalFieldCount());
1920 CHECK(global->GetInternalField(0)->IsUndefined());
1921 global->SetInternalField(0, v8_num(17));
1922 CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
1923}
1924
1925
Steve Blocka7e24c12009-10-30 11:49:00 +00001926THREADED_TEST(InternalFieldsNativePointers) {
1927 v8::HandleScope scope;
1928 LocalContext env;
1929
1930 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1931 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1932 instance_templ->SetInternalFieldCount(1);
1933 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1934 CHECK_EQ(1, obj->InternalFieldCount());
1935 CHECK(obj->GetPointerFromInternalField(0) == NULL);
1936
1937 char* data = new char[100];
1938
1939 void* aligned = data;
Ben Murdochf87a2032010-10-22 12:50:53 +01001940 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
Steve Blocka7e24c12009-10-30 11:49:00 +00001941 void* unaligned = data + 1;
Ben Murdochf87a2032010-10-22 12:50:53 +01001942 CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
Steve Blocka7e24c12009-10-30 11:49:00 +00001943
1944 // Check reading and writing aligned pointers.
1945 obj->SetPointerInInternalField(0, aligned);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001946 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +00001947 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1948
1949 // Check reading and writing unaligned pointers.
1950 obj->SetPointerInInternalField(0, unaligned);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001951 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +00001952 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1953
1954 delete[] data;
1955}
1956
1957
Steve Block3ce2e202009-11-05 08:53:23 +00001958THREADED_TEST(InternalFieldsNativePointersAndExternal) {
1959 v8::HandleScope scope;
1960 LocalContext env;
1961
1962 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1963 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1964 instance_templ->SetInternalFieldCount(1);
1965 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1966 CHECK_EQ(1, obj->InternalFieldCount());
1967 CHECK(obj->GetPointerFromInternalField(0) == NULL);
1968
1969 char* data = new char[100];
1970
1971 void* aligned = data;
Ben Murdochf87a2032010-10-22 12:50:53 +01001972 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
Steve Block3ce2e202009-11-05 08:53:23 +00001973 void* unaligned = data + 1;
Ben Murdochf87a2032010-10-22 12:50:53 +01001974 CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
Steve Block3ce2e202009-11-05 08:53:23 +00001975
1976 obj->SetPointerInInternalField(0, aligned);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001977 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Block3ce2e202009-11-05 08:53:23 +00001978 CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0)));
1979
1980 obj->SetPointerInInternalField(0, unaligned);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001981 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Block3ce2e202009-11-05 08:53:23 +00001982 CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0)));
1983
1984 obj->SetInternalField(0, v8::External::Wrap(aligned));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001985 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Block3ce2e202009-11-05 08:53:23 +00001986 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1987
1988 obj->SetInternalField(0, v8::External::Wrap(unaligned));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001989 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Block3ce2e202009-11-05 08:53:23 +00001990 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1991
1992 delete[] data;
1993}
1994
1995
Steve Blocka7e24c12009-10-30 11:49:00 +00001996THREADED_TEST(IdentityHash) {
1997 v8::HandleScope scope;
1998 LocalContext env;
1999
2000 // Ensure that the test starts with an fresh heap to test whether the hash
2001 // code is based on the address.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002002 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +00002003 Local<v8::Object> obj = v8::Object::New();
2004 int hash = obj->GetIdentityHash();
2005 int hash1 = obj->GetIdentityHash();
2006 CHECK_EQ(hash, hash1);
2007 int hash2 = v8::Object::New()->GetIdentityHash();
2008 // Since the identity hash is essentially a random number two consecutive
2009 // objects should not be assigned the same hash code. If the test below fails
2010 // the random number generator should be evaluated.
2011 CHECK_NE(hash, hash2);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002012 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +00002013 int hash3 = v8::Object::New()->GetIdentityHash();
2014 // Make sure that the identity hash is not based on the initial address of
2015 // the object alone. If the test below fails the random number generator
2016 // should be evaluated.
2017 CHECK_NE(hash, hash3);
2018 int hash4 = obj->GetIdentityHash();
2019 CHECK_EQ(hash, hash4);
Steve Block1e0659c2011-05-24 12:43:12 +01002020
2021 // Check identity hashes behaviour in the presence of JS accessors.
2022 // Put a getter for 'v8::IdentityHash' on the Object's prototype:
2023 {
2024 CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
2025 Local<v8::Object> o1 = v8::Object::New();
2026 Local<v8::Object> o2 = v8::Object::New();
2027 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2028 }
2029 {
2030 CompileRun(
2031 "function cnst() { return 42; };\n"
2032 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
2033 Local<v8::Object> o1 = v8::Object::New();
2034 Local<v8::Object> o2 = v8::Object::New();
2035 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2036 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002037}
2038
2039
2040THREADED_TEST(HiddenProperties) {
2041 v8::HandleScope scope;
2042 LocalContext env;
2043
2044 v8::Local<v8::Object> obj = v8::Object::New();
2045 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
2046 v8::Local<v8::String> empty = v8_str("");
2047 v8::Local<v8::String> prop_name = v8_str("prop_name");
2048
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002049 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +00002050
2051 // Make sure delete of a non-existent hidden value works
2052 CHECK(obj->DeleteHiddenValue(key));
2053
2054 CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
2055 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
2056 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
2057 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2058
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002059 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +00002060
2061 // Make sure we do not find the hidden property.
2062 CHECK(!obj->Has(empty));
2063 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2064 CHECK(obj->Get(empty)->IsUndefined());
2065 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2066 CHECK(obj->Set(empty, v8::Integer::New(2003)));
2067 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2068 CHECK_EQ(2003, obj->Get(empty)->Int32Value());
2069
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002070 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +00002071
2072 // Add another property and delete it afterwards to force the object in
2073 // slow case.
2074 CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
2075 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2076 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
2077 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2078 CHECK(obj->Delete(prop_name));
2079 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2080
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002081 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +00002082
2083 CHECK(obj->DeleteHiddenValue(key));
2084 CHECK(obj->GetHiddenValue(key).IsEmpty());
2085}
2086
2087
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002088THREADED_TEST(Regress97784) {
2089 // Regression test for crbug.com/97784
2090 // Messing with the Object.prototype should not have effect on
2091 // hidden properties.
2092 v8::HandleScope scope;
2093 LocalContext env;
2094
2095 v8::Local<v8::Object> obj = v8::Object::New();
2096 v8::Local<v8::String> key = v8_str("hidden");
2097
2098 CompileRun(
2099 "set_called = false;"
2100 "Object.defineProperty("
2101 " Object.prototype,"
2102 " 'hidden',"
2103 " {get: function() { return 45; },"
2104 " set: function() { set_called = true; }})");
2105
2106 CHECK(obj->GetHiddenValue(key).IsEmpty());
2107 // Make sure that the getter and setter from Object.prototype is not invoked.
2108 // If it did we would have full access to the hidden properties in
2109 // the accessor.
2110 CHECK(obj->SetHiddenValue(key, v8::Integer::New(42)));
2111 ExpectFalse("set_called");
2112 CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
2113}
2114
2115
Steve Blockd0582a62009-12-15 09:54:21 +00002116static bool interceptor_for_hidden_properties_called;
Steve Blocka7e24c12009-10-30 11:49:00 +00002117static v8::Handle<Value> InterceptorForHiddenProperties(
2118 Local<String> name, const AccessorInfo& info) {
Steve Blockd0582a62009-12-15 09:54:21 +00002119 interceptor_for_hidden_properties_called = true;
Steve Blocka7e24c12009-10-30 11:49:00 +00002120 return v8::Handle<Value>();
2121}
2122
2123
2124THREADED_TEST(HiddenPropertiesWithInterceptors) {
2125 v8::HandleScope scope;
2126 LocalContext context;
2127
Steve Blockd0582a62009-12-15 09:54:21 +00002128 interceptor_for_hidden_properties_called = false;
2129
Steve Blocka7e24c12009-10-30 11:49:00 +00002130 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
2131
2132 // Associate an interceptor with an object and start setting hidden values.
2133 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
2134 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
2135 instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
2136 Local<v8::Function> function = fun_templ->GetFunction();
2137 Local<v8::Object> obj = function->NewInstance();
2138 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
2139 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
Steve Blockd0582a62009-12-15 09:54:21 +00002140 CHECK(!interceptor_for_hidden_properties_called);
Steve Blocka7e24c12009-10-30 11:49:00 +00002141}
2142
2143
2144THREADED_TEST(External) {
2145 v8::HandleScope scope;
2146 int x = 3;
2147 Local<v8::External> ext = v8::External::New(&x);
2148 LocalContext env;
2149 env->Global()->Set(v8_str("ext"), ext);
2150 Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
Steve Block6ded16b2010-05-10 14:33:55 +01002151 v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
Steve Blocka7e24c12009-10-30 11:49:00 +00002152 int* ptr = static_cast<int*>(reext->Value());
2153 CHECK_EQ(x, 3);
2154 *ptr = 10;
2155 CHECK_EQ(x, 10);
2156
2157 // Make sure unaligned pointers are wrapped properly.
2158 char* data = i::StrDup("0123456789");
2159 Local<v8::Value> zero = v8::External::Wrap(&data[0]);
2160 Local<v8::Value> one = v8::External::Wrap(&data[1]);
2161 Local<v8::Value> two = v8::External::Wrap(&data[2]);
2162 Local<v8::Value> three = v8::External::Wrap(&data[3]);
2163
2164 char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero));
2165 CHECK_EQ('0', *char_ptr);
2166 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one));
2167 CHECK_EQ('1', *char_ptr);
2168 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two));
2169 CHECK_EQ('2', *char_ptr);
2170 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three));
2171 CHECK_EQ('3', *char_ptr);
2172 i::DeleteArray(data);
2173}
2174
2175
2176THREADED_TEST(GlobalHandle) {
2177 v8::Persistent<String> global;
2178 {
2179 v8::HandleScope scope;
2180 Local<String> str = v8_str("str");
2181 global = v8::Persistent<String>::New(str);
2182 }
2183 CHECK_EQ(global->Length(), 3);
2184 global.Dispose();
2185}
2186
2187
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002188class WeakCallCounter {
2189 public:
2190 explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
2191 int id() { return id_; }
2192 void increment() { number_of_weak_calls_++; }
2193 int NumberOfWeakCalls() { return number_of_weak_calls_; }
2194 private:
2195 int id_;
2196 int number_of_weak_calls_;
2197};
2198
2199
Steve Block44f0eee2011-05-26 01:26:41 +01002200static void WeakPointerCallback(Persistent<Value> handle, void* id) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002201 WeakCallCounter* counter = reinterpret_cast<WeakCallCounter*>(id);
2202 CHECK_EQ(1234, counter->id());
2203 counter->increment();
Steve Block44f0eee2011-05-26 01:26:41 +01002204 handle.Dispose();
2205}
2206
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002207
Steve Block44f0eee2011-05-26 01:26:41 +01002208THREADED_TEST(ApiObjectGroups) {
2209 HandleScope scope;
2210 LocalContext env;
2211
Steve Block44f0eee2011-05-26 01:26:41 +01002212 Persistent<Object> g1s1;
2213 Persistent<Object> g1s2;
2214 Persistent<Object> g1c1;
2215 Persistent<Object> g2s1;
2216 Persistent<Object> g2s2;
2217 Persistent<Object> g2c1;
2218
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002219 WeakCallCounter counter(1234);
2220
Steve Block44f0eee2011-05-26 01:26:41 +01002221 {
2222 HandleScope scope;
2223 g1s1 = Persistent<Object>::New(Object::New());
2224 g1s2 = Persistent<Object>::New(Object::New());
2225 g1c1 = Persistent<Object>::New(Object::New());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002226 g1s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2227 g1s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2228 g1c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
Steve Block44f0eee2011-05-26 01:26:41 +01002229
2230 g2s1 = Persistent<Object>::New(Object::New());
2231 g2s2 = Persistent<Object>::New(Object::New());
2232 g2c1 = Persistent<Object>::New(Object::New());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002233 g2s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2234 g2s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2235 g2c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
Steve Block44f0eee2011-05-26 01:26:41 +01002236 }
2237
2238 Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
2239
2240 // Connect group 1 and 2, make a cycle.
2241 CHECK(g1s2->Set(0, g2s2));
2242 CHECK(g2s1->Set(0, g1s1));
2243
2244 {
2245 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2246 Persistent<Value> g1_children[] = { g1c1 };
2247 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2248 Persistent<Value> g2_children[] = { g2c1 };
2249 V8::AddObjectGroup(g1_objects, 2);
2250 V8::AddImplicitReferences(g1s1, g1_children, 1);
2251 V8::AddObjectGroup(g2_objects, 2);
2252 V8::AddImplicitReferences(g2s2, g2_children, 1);
2253 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002254 // Do a single full GC, ensure incremental marking is stopped.
2255 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
Steve Block44f0eee2011-05-26 01:26:41 +01002256
2257 // All object should be alive.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002258 CHECK_EQ(0, counter.NumberOfWeakCalls());
Steve Block44f0eee2011-05-26 01:26:41 +01002259
2260 // Weaken the root.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002261 root.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
Steve Block44f0eee2011-05-26 01:26:41 +01002262 // But make children strong roots---all the objects (except for children)
2263 // should be collectable now.
2264 g1c1.ClearWeak();
2265 g2c1.ClearWeak();
2266
2267 // Groups are deleted, rebuild groups.
2268 {
2269 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2270 Persistent<Value> g1_children[] = { g1c1 };
2271 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2272 Persistent<Value> g2_children[] = { g2c1 };
2273 V8::AddObjectGroup(g1_objects, 2);
2274 V8::AddImplicitReferences(g1s1, g1_children, 1);
2275 V8::AddObjectGroup(g2_objects, 2);
2276 V8::AddImplicitReferences(g2s2, g2_children, 1);
2277 }
2278
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002279 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
Steve Block44f0eee2011-05-26 01:26:41 +01002280
2281 // All objects should be gone. 5 global handles in total.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002282 CHECK_EQ(5, counter.NumberOfWeakCalls());
Steve Block44f0eee2011-05-26 01:26:41 +01002283
2284 // And now make children weak again and collect them.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002285 g1c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2286 g2c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
Steve Block44f0eee2011-05-26 01:26:41 +01002287
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002288 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
2289 CHECK_EQ(7, counter.NumberOfWeakCalls());
Steve Block44f0eee2011-05-26 01:26:41 +01002290}
2291
2292
2293THREADED_TEST(ApiObjectGroupsCycle) {
2294 HandleScope scope;
2295 LocalContext env;
2296
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002297 WeakCallCounter counter(1234);
Steve Block44f0eee2011-05-26 01:26:41 +01002298
2299 Persistent<Object> g1s1;
2300 Persistent<Object> g1s2;
2301 Persistent<Object> g2s1;
2302 Persistent<Object> g2s2;
2303 Persistent<Object> g3s1;
2304 Persistent<Object> g3s2;
2305
2306 {
2307 HandleScope scope;
2308 g1s1 = Persistent<Object>::New(Object::New());
2309 g1s2 = Persistent<Object>::New(Object::New());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002310 g1s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2311 g1s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
Steve Block44f0eee2011-05-26 01:26:41 +01002312
2313 g2s1 = Persistent<Object>::New(Object::New());
2314 g2s2 = Persistent<Object>::New(Object::New());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002315 g2s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2316 g2s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
Steve Block44f0eee2011-05-26 01:26:41 +01002317
2318 g3s1 = Persistent<Object>::New(Object::New());
2319 g3s2 = Persistent<Object>::New(Object::New());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002320 g3s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2321 g3s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
Steve Block44f0eee2011-05-26 01:26:41 +01002322 }
2323
2324 Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
2325
2326 // Connect groups. We're building the following cycle:
2327 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
2328 // groups.
2329 {
2330 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2331 Persistent<Value> g1_children[] = { g2s1 };
2332 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2333 Persistent<Value> g2_children[] = { g3s1 };
2334 Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2335 Persistent<Value> g3_children[] = { g1s1 };
2336 V8::AddObjectGroup(g1_objects, 2);
2337 V8::AddImplicitReferences(g1s1, g1_children, 1);
2338 V8::AddObjectGroup(g2_objects, 2);
2339 V8::AddImplicitReferences(g2s1, g2_children, 1);
2340 V8::AddObjectGroup(g3_objects, 2);
2341 V8::AddImplicitReferences(g3s1, g3_children, 1);
2342 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002343 // Do a single full GC
2344 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
Steve Block44f0eee2011-05-26 01:26:41 +01002345
2346 // All object should be alive.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002347 CHECK_EQ(0, counter.NumberOfWeakCalls());
Steve Block44f0eee2011-05-26 01:26:41 +01002348
2349 // Weaken the root.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002350 root.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
Steve Block44f0eee2011-05-26 01:26:41 +01002351
2352 // Groups are deleted, rebuild groups.
2353 {
2354 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2355 Persistent<Value> g1_children[] = { g2s1 };
2356 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2357 Persistent<Value> g2_children[] = { g3s1 };
2358 Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2359 Persistent<Value> g3_children[] = { g1s1 };
2360 V8::AddObjectGroup(g1_objects, 2);
2361 V8::AddImplicitReferences(g1s1, g1_children, 1);
2362 V8::AddObjectGroup(g2_objects, 2);
2363 V8::AddImplicitReferences(g2s1, g2_children, 1);
2364 V8::AddObjectGroup(g3_objects, 2);
2365 V8::AddImplicitReferences(g3s1, g3_children, 1);
2366 }
2367
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002368 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
Steve Block44f0eee2011-05-26 01:26:41 +01002369
2370 // All objects should be gone. 7 global handles in total.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002371 CHECK_EQ(7, counter.NumberOfWeakCalls());
Steve Block44f0eee2011-05-26 01:26:41 +01002372}
2373
2374
Steve Blocka7e24c12009-10-30 11:49:00 +00002375THREADED_TEST(ScriptException) {
2376 v8::HandleScope scope;
2377 LocalContext env;
2378 Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
2379 v8::TryCatch try_catch;
2380 Local<Value> result = script->Run();
2381 CHECK(result.IsEmpty());
2382 CHECK(try_catch.HasCaught());
2383 String::AsciiValue exception_value(try_catch.Exception());
2384 CHECK_EQ(*exception_value, "panama!");
2385}
2386
2387
2388bool message_received;
2389
2390
2391static void check_message(v8::Handle<v8::Message> message,
2392 v8::Handle<Value> data) {
2393 CHECK_EQ(5.76, data->NumberValue());
2394 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
2395 CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
2396 message_received = true;
2397}
2398
2399
2400THREADED_TEST(MessageHandlerData) {
2401 message_received = false;
2402 v8::HandleScope scope;
2403 CHECK(!message_received);
2404 v8::V8::AddMessageListener(check_message, v8_num(5.76));
2405 LocalContext context;
2406 v8::ScriptOrigin origin =
2407 v8::ScriptOrigin(v8_str("6.75"));
2408 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
2409 &origin);
2410 script->SetData(v8_str("7.56"));
2411 script->Run();
2412 CHECK(message_received);
2413 // clear out the message listener
2414 v8::V8::RemoveMessageListeners(check_message);
2415}
2416
2417
2418THREADED_TEST(GetSetProperty) {
2419 v8::HandleScope scope;
2420 LocalContext context;
2421 context->Global()->Set(v8_str("foo"), v8_num(14));
2422 context->Global()->Set(v8_str("12"), v8_num(92));
2423 context->Global()->Set(v8::Integer::New(16), v8_num(32));
2424 context->Global()->Set(v8_num(13), v8_num(56));
2425 Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
2426 CHECK_EQ(14, foo->Int32Value());
2427 Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
2428 CHECK_EQ(92, twelve->Int32Value());
2429 Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
2430 CHECK_EQ(32, sixteen->Int32Value());
2431 Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
2432 CHECK_EQ(56, thirteen->Int32Value());
2433 CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
2434 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
2435 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
2436 CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
2437 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
2438 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
2439 CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
2440 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
2441 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
2442}
2443
2444
2445THREADED_TEST(PropertyAttributes) {
2446 v8::HandleScope scope;
2447 LocalContext context;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002448 // none
2449 Local<String> prop = v8_str("none");
2450 context->Global()->Set(prop, v8_num(7));
2451 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
Steve Blocka7e24c12009-10-30 11:49:00 +00002452 // read-only
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002453 prop = v8_str("read_only");
Steve Blocka7e24c12009-10-30 11:49:00 +00002454 context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
2455 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002456 CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
Steve Blocka7e24c12009-10-30 11:49:00 +00002457 Script::Compile(v8_str("read_only = 9"))->Run();
2458 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2459 context->Global()->Set(prop, v8_num(10));
2460 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2461 // dont-delete
2462 prop = v8_str("dont_delete");
2463 context->Global()->Set(prop, v8_num(13), v8::DontDelete);
2464 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
2465 Script::Compile(v8_str("delete dont_delete"))->Run();
2466 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002467 CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
2468 // dont-enum
2469 prop = v8_str("dont_enum");
2470 context->Global()->Set(prop, v8_num(28), v8::DontEnum);
2471 CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
2472 // absent
2473 prop = v8_str("absent");
2474 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
2475 Local<Value> fake_prop = v8_num(1);
2476 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
2477 // exception
2478 TryCatch try_catch;
2479 Local<Value> exception =
2480 CompileRun("({ toString: function() { throw 'exception';} })");
2481 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
2482 CHECK(try_catch.HasCaught());
2483 String::AsciiValue exception_value(try_catch.Exception());
2484 CHECK_EQ("exception", *exception_value);
2485 try_catch.Reset();
Steve Blocka7e24c12009-10-30 11:49:00 +00002486}
2487
2488
2489THREADED_TEST(Array) {
2490 v8::HandleScope scope;
2491 LocalContext context;
2492 Local<v8::Array> array = v8::Array::New();
2493 CHECK_EQ(0, array->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01002494 CHECK(array->Get(0)->IsUndefined());
Steve Blocka7e24c12009-10-30 11:49:00 +00002495 CHECK(!array->Has(0));
Steve Block6ded16b2010-05-10 14:33:55 +01002496 CHECK(array->Get(100)->IsUndefined());
Steve Blocka7e24c12009-10-30 11:49:00 +00002497 CHECK(!array->Has(100));
Steve Block6ded16b2010-05-10 14:33:55 +01002498 array->Set(2, v8_num(7));
Steve Blocka7e24c12009-10-30 11:49:00 +00002499 CHECK_EQ(3, array->Length());
2500 CHECK(!array->Has(0));
2501 CHECK(!array->Has(1));
2502 CHECK(array->Has(2));
Steve Block6ded16b2010-05-10 14:33:55 +01002503 CHECK_EQ(7, array->Get(2)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00002504 Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
Steve Block6ded16b2010-05-10 14:33:55 +01002505 Local<v8::Array> arr = obj.As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00002506 CHECK_EQ(3, arr->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01002507 CHECK_EQ(1, arr->Get(0)->Int32Value());
2508 CHECK_EQ(2, arr->Get(1)->Int32Value());
2509 CHECK_EQ(3, arr->Get(2)->Int32Value());
Steve Block44f0eee2011-05-26 01:26:41 +01002510 array = v8::Array::New(27);
2511 CHECK_EQ(27, array->Length());
2512 array = v8::Array::New(-27);
2513 CHECK_EQ(0, array->Length());
Steve Blocka7e24c12009-10-30 11:49:00 +00002514}
2515
2516
2517v8::Handle<Value> HandleF(const v8::Arguments& args) {
2518 v8::HandleScope scope;
2519 ApiTestFuzzer::Fuzz();
2520 Local<v8::Array> result = v8::Array::New(args.Length());
2521 for (int i = 0; i < args.Length(); i++)
Steve Block6ded16b2010-05-10 14:33:55 +01002522 result->Set(i, args[i]);
Steve Blocka7e24c12009-10-30 11:49:00 +00002523 return scope.Close(result);
2524}
2525
2526
2527THREADED_TEST(Vector) {
2528 v8::HandleScope scope;
2529 Local<ObjectTemplate> global = ObjectTemplate::New();
2530 global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
2531 LocalContext context(0, global);
2532
2533 const char* fun = "f()";
Steve Block6ded16b2010-05-10 14:33:55 +01002534 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00002535 CHECK_EQ(0, a0->Length());
2536
2537 const char* fun2 = "f(11)";
Steve Block6ded16b2010-05-10 14:33:55 +01002538 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00002539 CHECK_EQ(1, a1->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01002540 CHECK_EQ(11, a1->Get(0)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00002541
2542 const char* fun3 = "f(12, 13)";
Steve Block6ded16b2010-05-10 14:33:55 +01002543 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00002544 CHECK_EQ(2, a2->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01002545 CHECK_EQ(12, a2->Get(0)->Int32Value());
2546 CHECK_EQ(13, a2->Get(1)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00002547
2548 const char* fun4 = "f(14, 15, 16)";
Steve Block6ded16b2010-05-10 14:33:55 +01002549 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00002550 CHECK_EQ(3, a3->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01002551 CHECK_EQ(14, a3->Get(0)->Int32Value());
2552 CHECK_EQ(15, a3->Get(1)->Int32Value());
2553 CHECK_EQ(16, a3->Get(2)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00002554
2555 const char* fun5 = "f(17, 18, 19, 20)";
Steve Block6ded16b2010-05-10 14:33:55 +01002556 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00002557 CHECK_EQ(4, a4->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01002558 CHECK_EQ(17, a4->Get(0)->Int32Value());
2559 CHECK_EQ(18, a4->Get(1)->Int32Value());
2560 CHECK_EQ(19, a4->Get(2)->Int32Value());
2561 CHECK_EQ(20, a4->Get(3)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00002562}
2563
2564
2565THREADED_TEST(FunctionCall) {
2566 v8::HandleScope scope;
2567 LocalContext context;
2568 CompileRun(
2569 "function Foo() {"
2570 " var result = [];"
2571 " for (var i = 0; i < arguments.length; i++) {"
2572 " result.push(arguments[i]);"
2573 " }"
2574 " return result;"
2575 "}");
2576 Local<Function> Foo =
2577 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2578
2579 v8::Handle<Value>* args0 = NULL;
2580 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
2581 CHECK_EQ(0, a0->Length());
2582
2583 v8::Handle<Value> args1[] = { v8_num(1.1) };
2584 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
2585 CHECK_EQ(1, a1->Length());
2586 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2587
2588 v8::Handle<Value> args2[] = { v8_num(2.2),
2589 v8_num(3.3) };
2590 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
2591 CHECK_EQ(2, a2->Length());
2592 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2593 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2594
2595 v8::Handle<Value> args3[] = { v8_num(4.4),
2596 v8_num(5.5),
2597 v8_num(6.6) };
2598 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
2599 CHECK_EQ(3, a3->Length());
2600 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2601 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2602 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2603
2604 v8::Handle<Value> args4[] = { v8_num(7.7),
2605 v8_num(8.8),
2606 v8_num(9.9),
2607 v8_num(10.11) };
2608 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
2609 CHECK_EQ(4, a4->Length());
2610 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2611 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2612 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2613 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2614}
2615
2616
2617static const char* js_code_causing_out_of_memory =
2618 "var a = new Array(); while(true) a.push(a);";
2619
2620
2621// These tests run for a long time and prevent us from running tests
2622// that come after them so they cannot run in parallel.
2623TEST(OutOfMemory) {
2624 // It's not possible to read a snapshot into a heap with different dimensions.
Steve Block8defd9f2010-07-08 12:39:36 +01002625 if (i::Snapshot::IsEnabled()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00002626 // Set heap limits.
2627 static const int K = 1024;
2628 v8::ResourceConstraints constraints;
2629 constraints.set_max_young_space_size(256 * K);
2630 constraints.set_max_old_space_size(4 * K * K);
2631 v8::SetResourceConstraints(&constraints);
2632
2633 // Execute a script that causes out of memory.
2634 v8::HandleScope scope;
2635 LocalContext context;
2636 v8::V8::IgnoreOutOfMemoryException();
2637 Local<Script> script =
2638 Script::Compile(String::New(js_code_causing_out_of_memory));
2639 Local<Value> result = script->Run();
2640
2641 // Check for out of memory state.
2642 CHECK(result.IsEmpty());
2643 CHECK(context->HasOutOfMemoryException());
2644}
2645
2646
2647v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
2648 ApiTestFuzzer::Fuzz();
2649
2650 v8::HandleScope scope;
2651 LocalContext context;
2652 Local<Script> script =
2653 Script::Compile(String::New(js_code_causing_out_of_memory));
2654 Local<Value> result = script->Run();
2655
2656 // Check for out of memory state.
2657 CHECK(result.IsEmpty());
2658 CHECK(context->HasOutOfMemoryException());
2659
2660 return result;
2661}
2662
2663
2664TEST(OutOfMemoryNested) {
2665 // It's not possible to read a snapshot into a heap with different dimensions.
Steve Block8defd9f2010-07-08 12:39:36 +01002666 if (i::Snapshot::IsEnabled()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00002667 // Set heap limits.
2668 static const int K = 1024;
2669 v8::ResourceConstraints constraints;
2670 constraints.set_max_young_space_size(256 * K);
2671 constraints.set_max_old_space_size(4 * K * K);
2672 v8::SetResourceConstraints(&constraints);
2673
2674 v8::HandleScope scope;
2675 Local<ObjectTemplate> templ = ObjectTemplate::New();
2676 templ->Set(v8_str("ProvokeOutOfMemory"),
2677 v8::FunctionTemplate::New(ProvokeOutOfMemory));
2678 LocalContext context(0, templ);
2679 v8::V8::IgnoreOutOfMemoryException();
2680 Local<Value> result = CompileRun(
2681 "var thrown = false;"
2682 "try {"
2683 " ProvokeOutOfMemory();"
2684 "} catch (e) {"
2685 " thrown = true;"
2686 "}");
2687 // Check for out of memory state.
2688 CHECK(result.IsEmpty());
2689 CHECK(context->HasOutOfMemoryException());
2690}
2691
2692
2693TEST(HugeConsStringOutOfMemory) {
2694 // It's not possible to read a snapshot into a heap with different dimensions.
Steve Block8defd9f2010-07-08 12:39:36 +01002695 if (i::Snapshot::IsEnabled()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00002696 // Set heap limits.
2697 static const int K = 1024;
2698 v8::ResourceConstraints constraints;
2699 constraints.set_max_young_space_size(256 * K);
2700 constraints.set_max_old_space_size(2 * K * K);
2701 v8::SetResourceConstraints(&constraints);
2702
2703 // Execute a script that causes out of memory.
2704 v8::V8::IgnoreOutOfMemoryException();
2705
Steve Block44f0eee2011-05-26 01:26:41 +01002706 v8::HandleScope scope;
2707 LocalContext context;
2708
Steve Blocka7e24c12009-10-30 11:49:00 +00002709 // Build huge string. This should fail with out of memory exception.
2710 Local<Value> result = CompileRun(
2711 "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
Steve Block3ce2e202009-11-05 08:53:23 +00002712 "for (var i = 0; i < 22; i++) { str = str + str; }");
Steve Blocka7e24c12009-10-30 11:49:00 +00002713
2714 // Check for out of memory state.
2715 CHECK(result.IsEmpty());
2716 CHECK(context->HasOutOfMemoryException());
2717}
2718
2719
2720THREADED_TEST(ConstructCall) {
2721 v8::HandleScope scope;
2722 LocalContext context;
2723 CompileRun(
2724 "function Foo() {"
2725 " var result = [];"
2726 " for (var i = 0; i < arguments.length; i++) {"
2727 " result.push(arguments[i]);"
2728 " }"
2729 " return result;"
2730 "}");
2731 Local<Function> Foo =
2732 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2733
2734 v8::Handle<Value>* args0 = NULL;
2735 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
2736 CHECK_EQ(0, a0->Length());
2737
2738 v8::Handle<Value> args1[] = { v8_num(1.1) };
2739 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
2740 CHECK_EQ(1, a1->Length());
2741 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2742
2743 v8::Handle<Value> args2[] = { v8_num(2.2),
2744 v8_num(3.3) };
2745 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
2746 CHECK_EQ(2, a2->Length());
2747 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2748 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2749
2750 v8::Handle<Value> args3[] = { v8_num(4.4),
2751 v8_num(5.5),
2752 v8_num(6.6) };
2753 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
2754 CHECK_EQ(3, a3->Length());
2755 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2756 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2757 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2758
2759 v8::Handle<Value> args4[] = { v8_num(7.7),
2760 v8_num(8.8),
2761 v8_num(9.9),
2762 v8_num(10.11) };
2763 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
2764 CHECK_EQ(4, a4->Length());
2765 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2766 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2767 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2768 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2769}
2770
2771
2772static void CheckUncle(v8::TryCatch* try_catch) {
2773 CHECK(try_catch->HasCaught());
2774 String::AsciiValue str_value(try_catch->Exception());
2775 CHECK_EQ(*str_value, "uncle?");
2776 try_catch->Reset();
2777}
2778
2779
Steve Block6ded16b2010-05-10 14:33:55 +01002780THREADED_TEST(ConversionNumber) {
2781 v8::HandleScope scope;
2782 LocalContext env;
2783 // Very large number.
2784 CompileRun("var obj = Math.pow(2,32) * 1237;");
2785 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2786 CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
2787 CHECK_EQ(0, obj->ToInt32()->Value());
2788 CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned.
2789 // Large number.
2790 CompileRun("var obj = -1234567890123;");
2791 obj = env->Global()->Get(v8_str("obj"));
2792 CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
2793 CHECK_EQ(-1912276171, obj->ToInt32()->Value());
2794 CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT
2795 // Small positive integer.
2796 CompileRun("var obj = 42;");
2797 obj = env->Global()->Get(v8_str("obj"));
2798 CHECK_EQ(42.0, obj->ToNumber()->Value());
2799 CHECK_EQ(42, obj->ToInt32()->Value());
2800 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
2801 // Negative integer.
2802 CompileRun("var obj = -37;");
2803 obj = env->Global()->Get(v8_str("obj"));
2804 CHECK_EQ(-37.0, obj->ToNumber()->Value());
2805 CHECK_EQ(-37, obj->ToInt32()->Value());
2806 CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT
2807 // Positive non-int32 integer.
2808 CompileRun("var obj = 0x81234567;");
2809 obj = env->Global()->Get(v8_str("obj"));
2810 CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
2811 CHECK_EQ(-2128394905, obj->ToInt32()->Value());
2812 CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT
2813 // Fraction.
2814 CompileRun("var obj = 42.3;");
2815 obj = env->Global()->Get(v8_str("obj"));
2816 CHECK_EQ(42.3, obj->ToNumber()->Value());
2817 CHECK_EQ(42, obj->ToInt32()->Value());
2818 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
2819 // Large negative fraction.
2820 CompileRun("var obj = -5726623061.75;");
2821 obj = env->Global()->Get(v8_str("obj"));
2822 CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
2823 CHECK_EQ(-1431655765, obj->ToInt32()->Value());
2824 CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT
2825}
2826
2827
2828THREADED_TEST(isNumberType) {
2829 v8::HandleScope scope;
2830 LocalContext env;
2831 // Very large number.
2832 CompileRun("var obj = Math.pow(2,32) * 1237;");
2833 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2834 CHECK(!obj->IsInt32());
2835 CHECK(!obj->IsUint32());
2836 // Large negative number.
2837 CompileRun("var obj = -1234567890123;");
2838 obj = env->Global()->Get(v8_str("obj"));
2839 CHECK(!obj->IsInt32());
2840 CHECK(!obj->IsUint32());
2841 // Small positive integer.
2842 CompileRun("var obj = 42;");
2843 obj = env->Global()->Get(v8_str("obj"));
2844 CHECK(obj->IsInt32());
2845 CHECK(obj->IsUint32());
2846 // Negative integer.
2847 CompileRun("var obj = -37;");
2848 obj = env->Global()->Get(v8_str("obj"));
2849 CHECK(obj->IsInt32());
2850 CHECK(!obj->IsUint32());
2851 // Positive non-int32 integer.
2852 CompileRun("var obj = 0x81234567;");
2853 obj = env->Global()->Get(v8_str("obj"));
2854 CHECK(!obj->IsInt32());
2855 CHECK(obj->IsUint32());
2856 // Fraction.
2857 CompileRun("var obj = 42.3;");
2858 obj = env->Global()->Get(v8_str("obj"));
2859 CHECK(!obj->IsInt32());
2860 CHECK(!obj->IsUint32());
2861 // Large negative fraction.
2862 CompileRun("var obj = -5726623061.75;");
2863 obj = env->Global()->Get(v8_str("obj"));
2864 CHECK(!obj->IsInt32());
2865 CHECK(!obj->IsUint32());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002866 // Positive zero
2867 CompileRun("var obj = 0.0;");
2868 obj = env->Global()->Get(v8_str("obj"));
2869 CHECK(obj->IsInt32());
2870 CHECK(obj->IsUint32());
2871 // Positive zero
2872 CompileRun("var obj = -0.0;");
2873 obj = env->Global()->Get(v8_str("obj"));
2874 CHECK(!obj->IsInt32());
2875 CHECK(!obj->IsUint32());
Steve Block6ded16b2010-05-10 14:33:55 +01002876}
2877
2878
Steve Blocka7e24c12009-10-30 11:49:00 +00002879THREADED_TEST(ConversionException) {
2880 v8::HandleScope scope;
2881 LocalContext env;
2882 CompileRun(
2883 "function TestClass() { };"
2884 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
2885 "var obj = new TestClass();");
2886 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2887
2888 v8::TryCatch try_catch;
2889
2890 Local<Value> to_string_result = obj->ToString();
2891 CHECK(to_string_result.IsEmpty());
2892 CheckUncle(&try_catch);
2893
2894 Local<Value> to_number_result = obj->ToNumber();
2895 CHECK(to_number_result.IsEmpty());
2896 CheckUncle(&try_catch);
2897
2898 Local<Value> to_integer_result = obj->ToInteger();
2899 CHECK(to_integer_result.IsEmpty());
2900 CheckUncle(&try_catch);
2901
2902 Local<Value> to_uint32_result = obj->ToUint32();
2903 CHECK(to_uint32_result.IsEmpty());
2904 CheckUncle(&try_catch);
2905
2906 Local<Value> to_int32_result = obj->ToInt32();
2907 CHECK(to_int32_result.IsEmpty());
2908 CheckUncle(&try_catch);
2909
2910 Local<Value> to_object_result = v8::Undefined()->ToObject();
2911 CHECK(to_object_result.IsEmpty());
2912 CHECK(try_catch.HasCaught());
2913 try_catch.Reset();
2914
2915 int32_t int32_value = obj->Int32Value();
2916 CHECK_EQ(0, int32_value);
2917 CheckUncle(&try_catch);
2918
2919 uint32_t uint32_value = obj->Uint32Value();
2920 CHECK_EQ(0, uint32_value);
2921 CheckUncle(&try_catch);
2922
2923 double number_value = obj->NumberValue();
2924 CHECK_NE(0, IsNaN(number_value));
2925 CheckUncle(&try_catch);
2926
2927 int64_t integer_value = obj->IntegerValue();
2928 CHECK_EQ(0.0, static_cast<double>(integer_value));
2929 CheckUncle(&try_catch);
2930}
2931
2932
2933v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
2934 ApiTestFuzzer::Fuzz();
2935 return v8::ThrowException(v8_str("konto"));
2936}
2937
2938
2939v8::Handle<Value> CCatcher(const v8::Arguments& args) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002940 if (args.Length() < 1) return v8::False();
Steve Blocka7e24c12009-10-30 11:49:00 +00002941 v8::HandleScope scope;
2942 v8::TryCatch try_catch;
2943 Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
2944 CHECK(!try_catch.HasCaught() || result.IsEmpty());
2945 return v8::Boolean::New(try_catch.HasCaught());
2946}
2947
2948
2949THREADED_TEST(APICatch) {
2950 v8::HandleScope scope;
2951 Local<ObjectTemplate> templ = ObjectTemplate::New();
2952 templ->Set(v8_str("ThrowFromC"),
2953 v8::FunctionTemplate::New(ThrowFromC));
2954 LocalContext context(0, templ);
2955 CompileRun(
2956 "var thrown = false;"
2957 "try {"
2958 " ThrowFromC();"
2959 "} catch (e) {"
2960 " thrown = true;"
2961 "}");
2962 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
2963 CHECK(thrown->BooleanValue());
2964}
2965
2966
2967THREADED_TEST(APIThrowTryCatch) {
2968 v8::HandleScope scope;
2969 Local<ObjectTemplate> templ = ObjectTemplate::New();
2970 templ->Set(v8_str("ThrowFromC"),
2971 v8::FunctionTemplate::New(ThrowFromC));
2972 LocalContext context(0, templ);
2973 v8::TryCatch try_catch;
2974 CompileRun("ThrowFromC();");
2975 CHECK(try_catch.HasCaught());
2976}
2977
2978
2979// Test that a try-finally block doesn't shadow a try-catch block
2980// when setting up an external handler.
2981//
2982// BUG(271): Some of the exception propagation does not work on the
2983// ARM simulator because the simulator separates the C++ stack and the
2984// JS stack. This test therefore fails on the simulator. The test is
2985// not threaded to allow the threading tests to run on the simulator.
2986TEST(TryCatchInTryFinally) {
2987 v8::HandleScope scope;
2988 Local<ObjectTemplate> templ = ObjectTemplate::New();
2989 templ->Set(v8_str("CCatcher"),
2990 v8::FunctionTemplate::New(CCatcher));
2991 LocalContext context(0, templ);
2992 Local<Value> result = CompileRun("try {"
2993 " try {"
2994 " CCatcher('throw 7;');"
2995 " } finally {"
2996 " }"
2997 "} catch (e) {"
2998 "}");
2999 CHECK(result->IsTrue());
3000}
3001
3002
Ben Murdochb8e0da22011-05-16 14:20:40 +01003003static void check_reference_error_message(
3004 v8::Handle<v8::Message> message,
3005 v8::Handle<v8::Value> data) {
3006 const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
3007 CHECK(message->Get()->Equals(v8_str(reference_error)));
3008}
3009
3010
Steve Block1e0659c2011-05-24 12:43:12 +01003011static v8::Handle<Value> Fail(const v8::Arguments& args) {
3012 ApiTestFuzzer::Fuzz();
3013 CHECK(false);
3014 return v8::Undefined();
3015}
3016
3017
3018// Test that overwritten methods are not invoked on uncaught exception
3019// formatting. However, they are invoked when performing normal error
3020// string conversions.
Ben Murdochb8e0da22011-05-16 14:20:40 +01003021TEST(APIThrowMessageOverwrittenToString) {
3022 v8::HandleScope scope;
3023 v8::V8::AddMessageListener(check_reference_error_message);
Steve Block1e0659c2011-05-24 12:43:12 +01003024 Local<ObjectTemplate> templ = ObjectTemplate::New();
3025 templ->Set(v8_str("fail"), v8::FunctionTemplate::New(Fail));
3026 LocalContext context(NULL, templ);
3027 CompileRun("asdf;");
3028 CompileRun("var limit = {};"
3029 "limit.valueOf = fail;"
3030 "Error.stackTraceLimit = limit;");
3031 CompileRun("asdf");
3032 CompileRun("Array.prototype.pop = fail;");
3033 CompileRun("Object.prototype.hasOwnProperty = fail;");
3034 CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
3035 CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
3036 CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
Ben Murdochb8e0da22011-05-16 14:20:40 +01003037 CompileRun("ReferenceError.prototype.toString ="
3038 " function() { return 'Whoops' }");
3039 CompileRun("asdf;");
Steve Block1e0659c2011-05-24 12:43:12 +01003040 CompileRun("ReferenceError.prototype.constructor.name = void 0;");
3041 CompileRun("asdf;");
3042 CompileRun("ReferenceError.prototype.constructor = void 0;");
3043 CompileRun("asdf;");
3044 CompileRun("ReferenceError.prototype.__proto__ = new Object();");
3045 CompileRun("asdf;");
3046 CompileRun("ReferenceError.prototype = new Object();");
3047 CompileRun("asdf;");
Ben Murdochb8e0da22011-05-16 14:20:40 +01003048 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
3049 CHECK(string->Equals(v8_str("Whoops")));
Steve Block1e0659c2011-05-24 12:43:12 +01003050 CompileRun("ReferenceError.prototype.constructor = new Object();"
3051 "ReferenceError.prototype.constructor.name = 1;"
3052 "Number.prototype.toString = function() { return 'Whoops'; };"
3053 "ReferenceError.prototype.toString = Object.prototype.toString;");
3054 CompileRun("asdf;");
Ben Murdochb8e0da22011-05-16 14:20:40 +01003055 v8::V8::RemoveMessageListeners(check_message);
3056}
3057
3058
Steve Blocka7e24c12009-10-30 11:49:00 +00003059static void receive_message(v8::Handle<v8::Message> message,
3060 v8::Handle<v8::Value> data) {
3061 message->Get();
3062 message_received = true;
3063}
3064
3065
3066TEST(APIThrowMessage) {
3067 message_received = false;
3068 v8::HandleScope scope;
3069 v8::V8::AddMessageListener(receive_message);
3070 Local<ObjectTemplate> templ = ObjectTemplate::New();
3071 templ->Set(v8_str("ThrowFromC"),
3072 v8::FunctionTemplate::New(ThrowFromC));
3073 LocalContext context(0, templ);
3074 CompileRun("ThrowFromC();");
3075 CHECK(message_received);
3076 v8::V8::RemoveMessageListeners(check_message);
3077}
3078
3079
3080TEST(APIThrowMessageAndVerboseTryCatch) {
3081 message_received = false;
3082 v8::HandleScope scope;
3083 v8::V8::AddMessageListener(receive_message);
3084 Local<ObjectTemplate> templ = ObjectTemplate::New();
3085 templ->Set(v8_str("ThrowFromC"),
3086 v8::FunctionTemplate::New(ThrowFromC));
3087 LocalContext context(0, templ);
3088 v8::TryCatch try_catch;
3089 try_catch.SetVerbose(true);
3090 Local<Value> result = CompileRun("ThrowFromC();");
3091 CHECK(try_catch.HasCaught());
3092 CHECK(result.IsEmpty());
3093 CHECK(message_received);
3094 v8::V8::RemoveMessageListeners(check_message);
3095}
3096
3097
Ben Murdoch8b112d22011-06-08 16:22:53 +01003098TEST(APIStackOverflowAndVerboseTryCatch) {
3099 message_received = false;
3100 v8::HandleScope scope;
3101 v8::V8::AddMessageListener(receive_message);
3102 LocalContext context;
3103 v8::TryCatch try_catch;
3104 try_catch.SetVerbose(true);
3105 Local<Value> result = CompileRun("function foo() { foo(); } foo();");
3106 CHECK(try_catch.HasCaught());
3107 CHECK(result.IsEmpty());
3108 CHECK(message_received);
3109 v8::V8::RemoveMessageListeners(receive_message);
3110}
3111
3112
Steve Blocka7e24c12009-10-30 11:49:00 +00003113THREADED_TEST(ExternalScriptException) {
3114 v8::HandleScope scope;
3115 Local<ObjectTemplate> templ = ObjectTemplate::New();
3116 templ->Set(v8_str("ThrowFromC"),
3117 v8::FunctionTemplate::New(ThrowFromC));
3118 LocalContext context(0, templ);
3119
3120 v8::TryCatch try_catch;
3121 Local<Script> script
3122 = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
3123 Local<Value> result = script->Run();
3124 CHECK(result.IsEmpty());
3125 CHECK(try_catch.HasCaught());
3126 String::AsciiValue exception_value(try_catch.Exception());
3127 CHECK_EQ("konto", *exception_value);
3128}
3129
3130
3131
3132v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
3133 ApiTestFuzzer::Fuzz();
3134 CHECK_EQ(4, args.Length());
3135 int count = args[0]->Int32Value();
3136 int cInterval = args[2]->Int32Value();
3137 if (count == 0) {
3138 return v8::ThrowException(v8_str("FromC"));
3139 } else {
3140 Local<v8::Object> global = Context::GetCurrent()->Global();
3141 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
3142 v8::Handle<Value> argv[] = { v8_num(count - 1),
3143 args[1],
3144 args[2],
3145 args[3] };
3146 if (count % cInterval == 0) {
3147 v8::TryCatch try_catch;
Steve Block6ded16b2010-05-10 14:33:55 +01003148 Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
Steve Blocka7e24c12009-10-30 11:49:00 +00003149 int expected = args[3]->Int32Value();
3150 if (try_catch.HasCaught()) {
3151 CHECK_EQ(expected, count);
3152 CHECK(result.IsEmpty());
Steve Block44f0eee2011-05-26 01:26:41 +01003153 CHECK(!i::Isolate::Current()->has_scheduled_exception());
Steve Blocka7e24c12009-10-30 11:49:00 +00003154 } else {
3155 CHECK_NE(expected, count);
3156 }
3157 return result;
3158 } else {
Steve Block6ded16b2010-05-10 14:33:55 +01003159 return fun.As<Function>()->Call(global, 4, argv);
Steve Blocka7e24c12009-10-30 11:49:00 +00003160 }
3161 }
3162}
3163
3164
3165v8::Handle<Value> JSCheck(const v8::Arguments& args) {
3166 ApiTestFuzzer::Fuzz();
3167 CHECK_EQ(3, args.Length());
3168 bool equality = args[0]->BooleanValue();
3169 int count = args[1]->Int32Value();
3170 int expected = args[2]->Int32Value();
3171 if (equality) {
3172 CHECK_EQ(count, expected);
3173 } else {
3174 CHECK_NE(count, expected);
3175 }
3176 return v8::Undefined();
3177}
3178
3179
3180THREADED_TEST(EvalInTryFinally) {
3181 v8::HandleScope scope;
3182 LocalContext context;
3183 v8::TryCatch try_catch;
3184 CompileRun("(function() {"
3185 " try {"
3186 " eval('asldkf (*&^&*^');"
3187 " } finally {"
3188 " return;"
3189 " }"
3190 "})()");
3191 CHECK(!try_catch.HasCaught());
3192}
3193
3194
3195// This test works by making a stack of alternating JavaScript and C
3196// activations. These activations set up exception handlers with regular
3197// intervals, one interval for C activations and another for JavaScript
3198// activations. When enough activations have been created an exception is
3199// thrown and we check that the right activation catches the exception and that
3200// no other activations do. The right activation is always the topmost one with
3201// a handler, regardless of whether it is in JavaScript or C.
3202//
3203// The notation used to describe a test case looks like this:
3204//
3205// *JS[4] *C[3] @JS[2] C[1] JS[0]
3206//
3207// Each entry is an activation, either JS or C. The index is the count at that
3208// level. Stars identify activations with exception handlers, the @ identifies
3209// the exception handler that should catch the exception.
3210//
3211// BUG(271): Some of the exception propagation does not work on the
3212// ARM simulator because the simulator separates the C++ stack and the
3213// JS stack. This test therefore fails on the simulator. The test is
3214// not threaded to allow the threading tests to run on the simulator.
3215TEST(ExceptionOrder) {
3216 v8::HandleScope scope;
3217 Local<ObjectTemplate> templ = ObjectTemplate::New();
3218 templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
3219 templ->Set(v8_str("CThrowCountDown"),
3220 v8::FunctionTemplate::New(CThrowCountDown));
3221 LocalContext context(0, templ);
3222 CompileRun(
3223 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
3224 " if (count == 0) throw 'FromJS';"
3225 " if (count % jsInterval == 0) {"
3226 " try {"
3227 " var value = CThrowCountDown(count - 1,"
3228 " jsInterval,"
3229 " cInterval,"
3230 " expected);"
3231 " check(false, count, expected);"
3232 " return value;"
3233 " } catch (e) {"
3234 " check(true, count, expected);"
3235 " }"
3236 " } else {"
3237 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
3238 " }"
3239 "}");
3240 Local<Function> fun =
3241 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
3242
3243 const int argc = 4;
3244 // count jsInterval cInterval expected
3245
3246 // *JS[4] *C[3] @JS[2] C[1] JS[0]
3247 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
3248 fun->Call(fun, argc, a0);
3249
3250 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
3251 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
3252 fun->Call(fun, argc, a1);
3253
3254 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
3255 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
3256 fun->Call(fun, argc, a2);
3257
3258 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
3259 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
3260 fun->Call(fun, argc, a3);
3261
3262 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
3263 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
3264 fun->Call(fun, argc, a4);
3265
3266 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
3267 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
3268 fun->Call(fun, argc, a5);
3269}
3270
3271
3272v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
3273 ApiTestFuzzer::Fuzz();
3274 CHECK_EQ(1, args.Length());
3275 return v8::ThrowException(args[0]);
3276}
3277
3278
3279THREADED_TEST(ThrowValues) {
3280 v8::HandleScope scope;
3281 Local<ObjectTemplate> templ = ObjectTemplate::New();
3282 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
3283 LocalContext context(0, templ);
3284 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
3285 "function Run(obj) {"
3286 " try {"
3287 " Throw(obj);"
3288 " } catch (e) {"
3289 " return e;"
3290 " }"
3291 " return 'no exception';"
3292 "}"
3293 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
3294 CHECK_EQ(5, result->Length());
3295 CHECK(result->Get(v8::Integer::New(0))->IsString());
3296 CHECK(result->Get(v8::Integer::New(1))->IsNumber());
3297 CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
3298 CHECK(result->Get(v8::Integer::New(2))->IsNumber());
3299 CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
3300 CHECK(result->Get(v8::Integer::New(3))->IsNull());
3301 CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
3302}
3303
3304
3305THREADED_TEST(CatchZero) {
3306 v8::HandleScope scope;
3307 LocalContext context;
3308 v8::TryCatch try_catch;
3309 CHECK(!try_catch.HasCaught());
3310 Script::Compile(v8_str("throw 10"))->Run();
3311 CHECK(try_catch.HasCaught());
3312 CHECK_EQ(10, try_catch.Exception()->Int32Value());
3313 try_catch.Reset();
3314 CHECK(!try_catch.HasCaught());
3315 Script::Compile(v8_str("throw 0"))->Run();
3316 CHECK(try_catch.HasCaught());
3317 CHECK_EQ(0, try_catch.Exception()->Int32Value());
3318}
3319
3320
3321THREADED_TEST(CatchExceptionFromWith) {
3322 v8::HandleScope scope;
3323 LocalContext context;
3324 v8::TryCatch try_catch;
3325 CHECK(!try_catch.HasCaught());
3326 Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
3327 CHECK(try_catch.HasCaught());
3328}
3329
3330
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003331THREADED_TEST(TryCatchAndFinallyHidingException) {
3332 v8::HandleScope scope;
3333 LocalContext context;
3334 v8::TryCatch try_catch;
3335 CHECK(!try_catch.HasCaught());
3336 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
3337 CompileRun("f({toString: function() { throw 42; }});");
3338 CHECK(!try_catch.HasCaught());
3339}
3340
3341
3342v8::Handle<v8::Value> WithTryCatch(const v8::Arguments& args) {
3343 v8::TryCatch try_catch;
3344 return v8::Undefined();
3345}
3346
3347
3348THREADED_TEST(TryCatchAndFinally) {
3349 v8::HandleScope scope;
3350 LocalContext context;
3351 context->Global()->Set(
3352 v8_str("native_with_try_catch"),
3353 v8::FunctionTemplate::New(WithTryCatch)->GetFunction());
3354 v8::TryCatch try_catch;
3355 CHECK(!try_catch.HasCaught());
3356 CompileRun(
3357 "try {\n"
3358 " throw new Error('a');\n"
3359 "} finally {\n"
3360 " native_with_try_catch();\n"
3361 "}\n");
3362 CHECK(try_catch.HasCaught());
3363}
3364
3365
Steve Blocka7e24c12009-10-30 11:49:00 +00003366THREADED_TEST(Equality) {
3367 v8::HandleScope scope;
3368 LocalContext context;
3369 // Check that equality works at all before relying on CHECK_EQ
3370 CHECK(v8_str("a")->Equals(v8_str("a")));
3371 CHECK(!v8_str("a")->Equals(v8_str("b")));
3372
3373 CHECK_EQ(v8_str("a"), v8_str("a"));
3374 CHECK_NE(v8_str("a"), v8_str("b"));
3375 CHECK_EQ(v8_num(1), v8_num(1));
3376 CHECK_EQ(v8_num(1.00), v8_num(1));
3377 CHECK_NE(v8_num(1), v8_num(2));
3378
3379 // Assume String is not symbol.
3380 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
3381 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
3382 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
3383 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
3384 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
3385 CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
3386 Local<Value> not_a_number = v8_num(i::OS::nan_value());
3387 CHECK(!not_a_number->StrictEquals(not_a_number));
3388 CHECK(v8::False()->StrictEquals(v8::False()));
3389 CHECK(!v8::False()->StrictEquals(v8::Undefined()));
3390
3391 v8::Handle<v8::Object> obj = v8::Object::New();
3392 v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
3393 CHECK(alias->StrictEquals(obj));
3394 alias.Dispose();
3395}
3396
3397
3398THREADED_TEST(MultiRun) {
3399 v8::HandleScope scope;
3400 LocalContext context;
3401 Local<Script> script = Script::Compile(v8_str("x"));
3402 for (int i = 0; i < 10; i++)
3403 script->Run();
3404}
3405
3406
3407static v8::Handle<Value> GetXValue(Local<String> name,
3408 const AccessorInfo& info) {
3409 ApiTestFuzzer::Fuzz();
3410 CHECK_EQ(info.Data(), v8_str("donut"));
3411 CHECK_EQ(name, v8_str("x"));
3412 return name;
3413}
3414
3415
3416THREADED_TEST(SimplePropertyRead) {
3417 v8::HandleScope scope;
3418 Local<ObjectTemplate> templ = ObjectTemplate::New();
3419 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3420 LocalContext context;
3421 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3422 Local<Script> script = Script::Compile(v8_str("obj.x"));
3423 for (int i = 0; i < 10; i++) {
3424 Local<Value> result = script->Run();
3425 CHECK_EQ(result, v8_str("x"));
3426 }
3427}
3428
Andrei Popescu31002712010-02-23 13:46:05 +00003429THREADED_TEST(DefinePropertyOnAPIAccessor) {
3430 v8::HandleScope scope;
3431 Local<ObjectTemplate> templ = ObjectTemplate::New();
3432 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3433 LocalContext context;
3434 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3435
3436 // Uses getOwnPropertyDescriptor to check the configurable status
3437 Local<Script> script_desc
Leon Clarkef7060e22010-06-03 12:02:55 +01003438 = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
Andrei Popescu31002712010-02-23 13:46:05 +00003439 "obj, 'x');"
3440 "prop.configurable;"));
3441 Local<Value> result = script_desc->Run();
3442 CHECK_EQ(result->BooleanValue(), true);
3443
3444 // Redefine get - but still configurable
3445 Local<Script> script_define
3446 = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
3447 " configurable: true };"
3448 "Object.defineProperty(obj, 'x', desc);"
3449 "obj.x"));
3450 result = script_define->Run();
3451 CHECK_EQ(result, v8_num(42));
3452
3453 // Check that the accessor is still configurable
3454 result = script_desc->Run();
3455 CHECK_EQ(result->BooleanValue(), true);
3456
3457 // Redefine to a non-configurable
3458 script_define
3459 = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
3460 " configurable: false };"
3461 "Object.defineProperty(obj, 'x', desc);"
3462 "obj.x"));
3463 result = script_define->Run();
3464 CHECK_EQ(result, v8_num(43));
3465 result = script_desc->Run();
3466 CHECK_EQ(result->BooleanValue(), false);
3467
3468 // Make sure that it is not possible to redefine again
3469 v8::TryCatch try_catch;
3470 result = script_define->Run();
3471 CHECK(try_catch.HasCaught());
3472 String::AsciiValue exception_value(try_catch.Exception());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003473 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
Andrei Popescu31002712010-02-23 13:46:05 +00003474}
3475
3476THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
3477 v8::HandleScope scope;
3478 Local<ObjectTemplate> templ = ObjectTemplate::New();
3479 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3480 LocalContext context;
3481 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3482
3483 Local<Script> script_desc = Script::Compile(v8_str("var prop ="
3484 "Object.getOwnPropertyDescriptor( "
3485 "obj, 'x');"
3486 "prop.configurable;"));
3487 Local<Value> result = script_desc->Run();
3488 CHECK_EQ(result->BooleanValue(), true);
3489
3490 Local<Script> script_define =
3491 Script::Compile(v8_str("var desc = {get: function(){return 42; },"
3492 " configurable: true };"
3493 "Object.defineProperty(obj, 'x', desc);"
3494 "obj.x"));
3495 result = script_define->Run();
3496 CHECK_EQ(result, v8_num(42));
3497
3498
3499 result = script_desc->Run();
3500 CHECK_EQ(result->BooleanValue(), true);
3501
3502
3503 script_define =
3504 Script::Compile(v8_str("var desc = {get: function(){return 43; },"
3505 " configurable: false };"
3506 "Object.defineProperty(obj, 'x', desc);"
3507 "obj.x"));
3508 result = script_define->Run();
3509 CHECK_EQ(result, v8_num(43));
3510 result = script_desc->Run();
3511
3512 CHECK_EQ(result->BooleanValue(), false);
3513
3514 v8::TryCatch try_catch;
3515 result = script_define->Run();
3516 CHECK(try_catch.HasCaught());
3517 String::AsciiValue exception_value(try_catch.Exception());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003518 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
Andrei Popescu31002712010-02-23 13:46:05 +00003519}
3520
3521
Leon Clarkef7060e22010-06-03 12:02:55 +01003522static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
3523 char const* name) {
3524 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
3525}
Andrei Popescu31002712010-02-23 13:46:05 +00003526
3527
Leon Clarkef7060e22010-06-03 12:02:55 +01003528THREADED_TEST(DefineAPIAccessorOnObject) {
3529 v8::HandleScope scope;
3530 Local<ObjectTemplate> templ = ObjectTemplate::New();
3531 LocalContext context;
3532
3533 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3534 CompileRun("var obj2 = {};");
3535
3536 CHECK(CompileRun("obj1.x")->IsUndefined());
3537 CHECK(CompileRun("obj2.x")->IsUndefined());
3538
3539 CHECK(GetGlobalProperty(&context, "obj1")->
3540 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3541
3542 ExpectString("obj1.x", "x");
3543 CHECK(CompileRun("obj2.x")->IsUndefined());
3544
3545 CHECK(GetGlobalProperty(&context, "obj2")->
3546 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3547
3548 ExpectString("obj1.x", "x");
3549 ExpectString("obj2.x", "x");
3550
3551 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3552 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3553
3554 CompileRun("Object.defineProperty(obj1, 'x',"
3555 "{ get: function() { return 'y'; }, configurable: true })");
3556
3557 ExpectString("obj1.x", "y");
3558 ExpectString("obj2.x", "x");
3559
3560 CompileRun("Object.defineProperty(obj2, 'x',"
3561 "{ get: function() { return 'y'; }, configurable: true })");
3562
3563 ExpectString("obj1.x", "y");
3564 ExpectString("obj2.x", "y");
3565
3566 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3567 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3568
3569 CHECK(GetGlobalProperty(&context, "obj1")->
3570 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3571 CHECK(GetGlobalProperty(&context, "obj2")->
3572 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3573
3574 ExpectString("obj1.x", "x");
3575 ExpectString("obj2.x", "x");
3576
3577 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3578 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3579
3580 // Define getters/setters, but now make them not configurable.
3581 CompileRun("Object.defineProperty(obj1, 'x',"
3582 "{ get: function() { return 'z'; }, configurable: false })");
3583 CompileRun("Object.defineProperty(obj2, 'x',"
3584 "{ get: function() { return 'z'; }, configurable: false })");
3585
3586 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3587 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3588
3589 ExpectString("obj1.x", "z");
3590 ExpectString("obj2.x", "z");
3591
3592 CHECK(!GetGlobalProperty(&context, "obj1")->
3593 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3594 CHECK(!GetGlobalProperty(&context, "obj2")->
3595 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3596
3597 ExpectString("obj1.x", "z");
3598 ExpectString("obj2.x", "z");
3599}
3600
3601
3602THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
3603 v8::HandleScope scope;
3604 Local<ObjectTemplate> templ = ObjectTemplate::New();
3605 LocalContext context;
3606
3607 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3608 CompileRun("var obj2 = {};");
3609
3610 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3611 v8_str("x"),
3612 GetXValue, NULL,
3613 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3614 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3615 v8_str("x"),
3616 GetXValue, NULL,
3617 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3618
3619 ExpectString("obj1.x", "x");
3620 ExpectString("obj2.x", "x");
3621
3622 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3623 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3624
3625 CHECK(!GetGlobalProperty(&context, "obj1")->
3626 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3627 CHECK(!GetGlobalProperty(&context, "obj2")->
3628 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3629
3630 {
3631 v8::TryCatch try_catch;
3632 CompileRun("Object.defineProperty(obj1, 'x',"
3633 "{get: function() { return 'func'; }})");
3634 CHECK(try_catch.HasCaught());
3635 String::AsciiValue exception_value(try_catch.Exception());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003636 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
Leon Clarkef7060e22010-06-03 12:02:55 +01003637 }
3638 {
3639 v8::TryCatch try_catch;
3640 CompileRun("Object.defineProperty(obj2, 'x',"
3641 "{get: function() { return 'func'; }})");
3642 CHECK(try_catch.HasCaught());
3643 String::AsciiValue exception_value(try_catch.Exception());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003644 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
Leon Clarkef7060e22010-06-03 12:02:55 +01003645 }
3646}
3647
3648
3649static v8::Handle<Value> Get239Value(Local<String> name,
3650 const AccessorInfo& info) {
3651 ApiTestFuzzer::Fuzz();
3652 CHECK_EQ(info.Data(), v8_str("donut"));
3653 CHECK_EQ(name, v8_str("239"));
3654 return name;
3655}
3656
3657
3658THREADED_TEST(ElementAPIAccessor) {
3659 v8::HandleScope scope;
3660 Local<ObjectTemplate> templ = ObjectTemplate::New();
3661 LocalContext context;
3662
3663 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3664 CompileRun("var obj2 = {};");
3665
3666 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3667 v8_str("239"),
3668 Get239Value, NULL,
3669 v8_str("donut")));
3670 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3671 v8_str("239"),
3672 Get239Value, NULL,
3673 v8_str("donut")));
3674
3675 ExpectString("obj1[239]", "239");
3676 ExpectString("obj2[239]", "239");
3677 ExpectString("obj1['239']", "239");
3678 ExpectString("obj2['239']", "239");
3679}
3680
Steve Blocka7e24c12009-10-30 11:49:00 +00003681
3682v8::Persistent<Value> xValue;
3683
3684
3685static void SetXValue(Local<String> name,
3686 Local<Value> value,
3687 const AccessorInfo& info) {
3688 CHECK_EQ(value, v8_num(4));
3689 CHECK_EQ(info.Data(), v8_str("donut"));
3690 CHECK_EQ(name, v8_str("x"));
3691 CHECK(xValue.IsEmpty());
3692 xValue = v8::Persistent<Value>::New(value);
3693}
3694
3695
3696THREADED_TEST(SimplePropertyWrite) {
3697 v8::HandleScope scope;
3698 Local<ObjectTemplate> templ = ObjectTemplate::New();
3699 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
3700 LocalContext context;
3701 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3702 Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
3703 for (int i = 0; i < 10; i++) {
3704 CHECK(xValue.IsEmpty());
3705 script->Run();
3706 CHECK_EQ(v8_num(4), xValue);
3707 xValue.Dispose();
3708 xValue = v8::Persistent<Value>();
3709 }
3710}
3711
3712
3713static v8::Handle<Value> XPropertyGetter(Local<String> property,
3714 const AccessorInfo& info) {
3715 ApiTestFuzzer::Fuzz();
3716 CHECK(info.Data()->IsUndefined());
3717 return property;
3718}
3719
3720
3721THREADED_TEST(NamedInterceptorPropertyRead) {
3722 v8::HandleScope scope;
3723 Local<ObjectTemplate> templ = ObjectTemplate::New();
3724 templ->SetNamedPropertyHandler(XPropertyGetter);
3725 LocalContext context;
3726 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3727 Local<Script> script = Script::Compile(v8_str("obj.x"));
3728 for (int i = 0; i < 10; i++) {
3729 Local<Value> result = script->Run();
3730 CHECK_EQ(result, v8_str("x"));
3731 }
3732}
3733
3734
Steve Block6ded16b2010-05-10 14:33:55 +01003735THREADED_TEST(NamedInterceptorDictionaryIC) {
3736 v8::HandleScope scope;
3737 Local<ObjectTemplate> templ = ObjectTemplate::New();
3738 templ->SetNamedPropertyHandler(XPropertyGetter);
3739 LocalContext context;
3740 // Create an object with a named interceptor.
3741 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
3742 Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
3743 for (int i = 0; i < 10; i++) {
3744 Local<Value> result = script->Run();
3745 CHECK_EQ(result, v8_str("x"));
3746 }
3747 // Create a slow case object and a function accessing a property in
3748 // that slow case object (with dictionary probing in generated
3749 // code). Then force object with a named interceptor into slow-case,
3750 // pass it to the function, and check that the interceptor is called
3751 // instead of accessing the local property.
3752 Local<Value> result =
3753 CompileRun("function get_x(o) { return o.x; };"
3754 "var obj = { x : 42, y : 0 };"
3755 "delete obj.y;"
3756 "for (var i = 0; i < 10; i++) get_x(obj);"
3757 "interceptor_obj.x = 42;"
3758 "interceptor_obj.y = 10;"
3759 "delete interceptor_obj.y;"
3760 "get_x(interceptor_obj)");
3761 CHECK_EQ(result, v8_str("x"));
3762}
3763
3764
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003765THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
3766 v8::HandleScope scope;
3767
3768 v8::Persistent<Context> context1 = Context::New();
3769
3770 context1->Enter();
3771 Local<ObjectTemplate> templ = ObjectTemplate::New();
3772 templ->SetNamedPropertyHandler(XPropertyGetter);
3773 // Create an object with a named interceptor.
3774 v8::Local<v8::Object> object = templ->NewInstance();
3775 context1->Global()->Set(v8_str("interceptor_obj"), object);
3776
3777 // Force the object into the slow case.
3778 CompileRun("interceptor_obj.y = 0;"
3779 "delete interceptor_obj.y;");
3780 context1->Exit();
3781
3782 {
3783 // Introduce the object into a different context.
3784 // Repeat named loads to exercise ICs.
3785 LocalContext context2;
3786 context2->Global()->Set(v8_str("interceptor_obj"), object);
3787 Local<Value> result =
3788 CompileRun("function get_x(o) { return o.x; }"
3789 "interceptor_obj.x = 42;"
3790 "for (var i=0; i != 10; i++) {"
3791 " get_x(interceptor_obj);"
3792 "}"
3793 "get_x(interceptor_obj)");
3794 // Check that the interceptor was actually invoked.
3795 CHECK_EQ(result, v8_str("x"));
3796 }
3797
3798 // Return to the original context and force some object to the slow case
3799 // to cause the NormalizedMapCache to verify.
3800 context1->Enter();
3801 CompileRun("var obj = { x : 0 }; delete obj.x;");
3802 context1->Exit();
3803
3804 context1.Dispose();
3805}
3806
3807
Andrei Popescu402d9372010-02-26 13:31:12 +00003808static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
3809 const AccessorInfo& info) {
3810 // Set x on the prototype object and do not handle the get request.
3811 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
Steve Block6ded16b2010-05-10 14:33:55 +01003812 proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
Andrei Popescu402d9372010-02-26 13:31:12 +00003813 return v8::Handle<Value>();
3814}
3815
3816
3817// This is a regression test for http://crbug.com/20104. Map
3818// transitions should not interfere with post interceptor lookup.
3819THREADED_TEST(NamedInterceptorMapTransitionRead) {
3820 v8::HandleScope scope;
3821 Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
3822 Local<v8::ObjectTemplate> instance_template
3823 = function_template->InstanceTemplate();
3824 instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
3825 LocalContext context;
3826 context->Global()->Set(v8_str("F"), function_template->GetFunction());
3827 // Create an instance of F and introduce a map transition for x.
3828 CompileRun("var o = new F(); o.x = 23;");
3829 // Create an instance of F and invoke the getter. The result should be 23.
3830 Local<Value> result = CompileRun("o = new F(); o.x");
3831 CHECK_EQ(result->Int32Value(), 23);
3832}
3833
3834
Steve Blocka7e24c12009-10-30 11:49:00 +00003835static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
3836 const AccessorInfo& info) {
3837 ApiTestFuzzer::Fuzz();
3838 if (index == 37) {
3839 return v8::Handle<Value>(v8_num(625));
3840 }
3841 return v8::Handle<Value>();
3842}
3843
3844
3845static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
3846 Local<Value> value,
3847 const AccessorInfo& info) {
3848 ApiTestFuzzer::Fuzz();
3849 if (index == 39) {
3850 return value;
3851 }
3852 return v8::Handle<Value>();
3853}
3854
3855
3856THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
3857 v8::HandleScope scope;
3858 Local<ObjectTemplate> templ = ObjectTemplate::New();
3859 templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
3860 IndexedPropertySetter);
3861 LocalContext context;
3862 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3863 Local<Script> getter_script = Script::Compile(v8_str(
3864 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
3865 Local<Script> setter_script = Script::Compile(v8_str(
3866 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
3867 "obj[17] = 23;"
3868 "obj.foo;"));
3869 Local<Script> interceptor_setter_script = Script::Compile(v8_str(
3870 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
3871 "obj[39] = 47;"
3872 "obj.foo;")); // This setter should not run, due to the interceptor.
3873 Local<Script> interceptor_getter_script = Script::Compile(v8_str(
3874 "obj[37];"));
3875 Local<Value> result = getter_script->Run();
3876 CHECK_EQ(v8_num(5), result);
3877 result = setter_script->Run();
3878 CHECK_EQ(v8_num(23), result);
3879 result = interceptor_setter_script->Run();
3880 CHECK_EQ(v8_num(23), result);
3881 result = interceptor_getter_script->Run();
3882 CHECK_EQ(v8_num(625), result);
3883}
3884
3885
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003886static v8::Handle<Value> UnboxedDoubleIndexedPropertyGetter(
3887 uint32_t index,
3888 const AccessorInfo& info) {
3889 ApiTestFuzzer::Fuzz();
3890 if (index < 25) {
3891 return v8::Handle<Value>(v8_num(index));
3892 }
3893 return v8::Handle<Value>();
3894}
3895
3896
3897static v8::Handle<Value> UnboxedDoubleIndexedPropertySetter(
3898 uint32_t index,
3899 Local<Value> value,
3900 const AccessorInfo& info) {
3901 ApiTestFuzzer::Fuzz();
3902 if (index < 25) {
3903 return v8::Handle<Value>(v8_num(index));
3904 }
3905 return v8::Handle<Value>();
3906}
3907
3908
3909Handle<v8::Array> UnboxedDoubleIndexedPropertyEnumerator(
3910 const AccessorInfo& info) {
3911 // Force the list of returned keys to be stored in a FastDoubleArray.
3912 Local<Script> indexed_property_names_script = Script::Compile(v8_str(
3913 "keys = new Array(); keys[125000] = 1;"
3914 "for(i = 0; i < 80000; i++) { keys[i] = i; };"
3915 "keys.length = 25; keys;"));
3916 Local<Value> result = indexed_property_names_script->Run();
3917 return Local<v8::Array>(::v8::Array::Cast(*result));
3918}
3919
3920
3921// Make sure that the the interceptor code in the runtime properly handles
3922// merging property name lists for double-array-backed arrays.
3923THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
3924 v8::HandleScope scope;
3925 Local<ObjectTemplate> templ = ObjectTemplate::New();
3926 templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
3927 UnboxedDoubleIndexedPropertySetter,
3928 0,
3929 0,
3930 UnboxedDoubleIndexedPropertyEnumerator);
3931 LocalContext context;
3932 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3933 // When obj is created, force it to be Stored in a FastDoubleArray.
3934 Local<Script> create_unboxed_double_script = Script::Compile(v8_str(
3935 "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
3936 "key_count = 0; "
3937 "for (x in obj) {key_count++;};"
3938 "obj;"));
3939 Local<Value> result = create_unboxed_double_script->Run();
3940 CHECK(result->ToObject()->HasRealIndexedProperty(2000));
3941 Local<Script> key_count_check = Script::Compile(v8_str(
3942 "key_count;"));
3943 result = key_count_check->Run();
3944 CHECK_EQ(v8_num(40013), result);
3945}
3946
3947
3948Handle<v8::Array> NonStrictArgsIndexedPropertyEnumerator(
3949 const AccessorInfo& info) {
3950 // Force the list of returned keys to be stored in a Arguments object.
3951 Local<Script> indexed_property_names_script = Script::Compile(v8_str(
3952 "function f(w,x) {"
3953 " return arguments;"
3954 "}"
3955 "keys = f(0, 1, 2, 3);"
3956 "keys;"));
3957 Local<Value> result = indexed_property_names_script->Run();
3958 return Local<v8::Array>(static_cast<v8::Array*>(::v8::Object::Cast(*result)));
3959}
3960
3961
3962static v8::Handle<Value> NonStrictIndexedPropertyGetter(
3963 uint32_t index,
3964 const AccessorInfo& info) {
3965 ApiTestFuzzer::Fuzz();
3966 if (index < 4) {
3967 return v8::Handle<Value>(v8_num(index));
3968 }
3969 return v8::Handle<Value>();
3970}
3971
3972
3973// Make sure that the the interceptor code in the runtime properly handles
3974// merging property name lists for non-string arguments arrays.
3975THREADED_TEST(IndexedInterceptorNonStrictArgsWithIndexedAccessor) {
3976 v8::HandleScope scope;
3977 Local<ObjectTemplate> templ = ObjectTemplate::New();
3978 templ->SetIndexedPropertyHandler(NonStrictIndexedPropertyGetter,
3979 0,
3980 0,
3981 0,
3982 NonStrictArgsIndexedPropertyEnumerator);
3983 LocalContext context;
3984 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3985 Local<Script> create_args_script =
3986 Script::Compile(v8_str(
3987 "var key_count = 0;"
3988 "for (x in obj) {key_count++;} key_count;"));
3989 Local<Value> result = create_args_script->Run();
3990 CHECK_EQ(v8_num(4), result);
3991}
3992
3993
Leon Clarked91b9f72010-01-27 17:25:45 +00003994static v8::Handle<Value> IdentityIndexedPropertyGetter(
3995 uint32_t index,
3996 const AccessorInfo& info) {
Ben Murdochf87a2032010-10-22 12:50:53 +01003997 return v8::Integer::NewFromUnsigned(index);
Leon Clarked91b9f72010-01-27 17:25:45 +00003998}
3999
4000
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004001THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
4002 v8::HandleScope scope;
4003 Local<ObjectTemplate> templ = ObjectTemplate::New();
4004 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4005
4006 LocalContext context;
4007 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4008
4009 // Check fast object case.
4010 const char* fast_case_code =
4011 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
4012 ExpectString(fast_case_code, "0");
4013
4014 // Check slow case.
4015 const char* slow_case_code =
4016 "obj.x = 1; delete obj.x;"
4017 "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
4018 ExpectString(slow_case_code, "1");
4019}
4020
4021
Leon Clarked91b9f72010-01-27 17:25:45 +00004022THREADED_TEST(IndexedInterceptorWithNoSetter) {
4023 v8::HandleScope scope;
4024 Local<ObjectTemplate> templ = ObjectTemplate::New();
4025 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4026
4027 LocalContext context;
4028 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4029
4030 const char* code =
4031 "try {"
4032 " obj[0] = 239;"
4033 " for (var i = 0; i < 100; i++) {"
4034 " var v = obj[0];"
4035 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
4036 " }"
4037 " 'PASSED'"
4038 "} catch(e) {"
4039 " e"
4040 "}";
4041 ExpectString(code, "PASSED");
4042}
4043
4044
Andrei Popescu402d9372010-02-26 13:31:12 +00004045THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
4046 v8::HandleScope scope;
4047 Local<ObjectTemplate> templ = ObjectTemplate::New();
4048 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4049
4050 LocalContext context;
4051 Local<v8::Object> obj = templ->NewInstance();
4052 obj->TurnOnAccessCheck();
4053 context->Global()->Set(v8_str("obj"), obj);
4054
4055 const char* code =
4056 "try {"
4057 " for (var i = 0; i < 100; i++) {"
4058 " var v = obj[0];"
4059 " if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
4060 " }"
4061 " 'PASSED'"
4062 "} catch(e) {"
4063 " e"
4064 "}";
4065 ExpectString(code, "PASSED");
4066}
4067
4068
4069THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
4070 i::FLAG_allow_natives_syntax = true;
4071 v8::HandleScope scope;
4072 Local<ObjectTemplate> templ = ObjectTemplate::New();
4073 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4074
4075 LocalContext context;
4076 Local<v8::Object> obj = templ->NewInstance();
4077 context->Global()->Set(v8_str("obj"), obj);
4078
4079 const char* code =
4080 "try {"
4081 " for (var i = 0; i < 100; i++) {"
4082 " var expected = i;"
4083 " if (i == 5) {"
4084 " %EnableAccessChecks(obj);"
4085 " expected = undefined;"
4086 " }"
4087 " var v = obj[i];"
4088 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4089 " if (i == 5) %DisableAccessChecks(obj);"
4090 " }"
4091 " 'PASSED'"
4092 "} catch(e) {"
4093 " e"
4094 "}";
4095 ExpectString(code, "PASSED");
4096}
4097
4098
4099THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
4100 v8::HandleScope scope;
4101 Local<ObjectTemplate> templ = ObjectTemplate::New();
4102 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4103
4104 LocalContext context;
4105 Local<v8::Object> obj = templ->NewInstance();
4106 context->Global()->Set(v8_str("obj"), obj);
4107
4108 const char* code =
4109 "try {"
4110 " for (var i = 0; i < 100; i++) {"
4111 " var v = obj[i];"
4112 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
4113 " }"
4114 " 'PASSED'"
4115 "} catch(e) {"
4116 " e"
4117 "}";
4118 ExpectString(code, "PASSED");
4119}
4120
4121
Ben Murdochf87a2032010-10-22 12:50:53 +01004122THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
4123 v8::HandleScope scope;
4124 Local<ObjectTemplate> templ = ObjectTemplate::New();
4125 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4126
4127 LocalContext context;
4128 Local<v8::Object> obj = templ->NewInstance();
4129 context->Global()->Set(v8_str("obj"), obj);
4130
4131 const char* code =
4132 "try {"
4133 " for (var i = 0; i < 100; i++) {"
4134 " var expected = i;"
4135 " var key = i;"
4136 " if (i == 25) {"
4137 " key = -1;"
4138 " expected = undefined;"
4139 " }"
4140 " if (i == 50) {"
4141 " /* probe minimal Smi number on 32-bit platforms */"
4142 " key = -(1 << 30);"
4143 " expected = undefined;"
4144 " }"
4145 " if (i == 75) {"
4146 " /* probe minimal Smi number on 64-bit platforms */"
4147 " key = 1 << 31;"
4148 " expected = undefined;"
4149 " }"
4150 " var v = obj[key];"
4151 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4152 " }"
4153 " 'PASSED'"
4154 "} catch(e) {"
4155 " e"
4156 "}";
4157 ExpectString(code, "PASSED");
4158}
4159
4160
Andrei Popescu402d9372010-02-26 13:31:12 +00004161THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
4162 v8::HandleScope scope;
4163 Local<ObjectTemplate> templ = ObjectTemplate::New();
4164 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4165
4166 LocalContext context;
4167 Local<v8::Object> obj = templ->NewInstance();
4168 context->Global()->Set(v8_str("obj"), obj);
4169
4170 const char* code =
4171 "try {"
4172 " for (var i = 0; i < 100; i++) {"
4173 " var expected = i;"
Ben Murdochf87a2032010-10-22 12:50:53 +01004174 " var key = i;"
Andrei Popescu402d9372010-02-26 13:31:12 +00004175 " if (i == 50) {"
Ben Murdochf87a2032010-10-22 12:50:53 +01004176 " key = 'foobar';"
Andrei Popescu402d9372010-02-26 13:31:12 +00004177 " expected = undefined;"
4178 " }"
Ben Murdochf87a2032010-10-22 12:50:53 +01004179 " var v = obj[key];"
Andrei Popescu402d9372010-02-26 13:31:12 +00004180 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4181 " }"
4182 " 'PASSED'"
4183 "} catch(e) {"
4184 " e"
4185 "}";
4186 ExpectString(code, "PASSED");
4187}
4188
4189
4190THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
4191 v8::HandleScope scope;
4192 Local<ObjectTemplate> templ = ObjectTemplate::New();
4193 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4194
4195 LocalContext context;
4196 Local<v8::Object> obj = templ->NewInstance();
4197 context->Global()->Set(v8_str("obj"), obj);
4198
4199 const char* code =
4200 "var original = obj;"
4201 "try {"
4202 " for (var i = 0; i < 100; i++) {"
4203 " var expected = i;"
4204 " if (i == 50) {"
4205 " obj = {50: 'foobar'};"
4206 " expected = 'foobar';"
4207 " }"
4208 " var v = obj[i];"
4209 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4210 " if (i == 50) obj = original;"
4211 " }"
4212 " 'PASSED'"
4213 "} catch(e) {"
4214 " e"
4215 "}";
4216 ExpectString(code, "PASSED");
4217}
4218
4219
4220THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
4221 v8::HandleScope scope;
4222 Local<ObjectTemplate> templ = ObjectTemplate::New();
4223 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4224
4225 LocalContext context;
4226 Local<v8::Object> obj = templ->NewInstance();
4227 context->Global()->Set(v8_str("obj"), obj);
4228
4229 const char* code =
4230 "var original = obj;"
4231 "try {"
4232 " for (var i = 0; i < 100; i++) {"
4233 " var expected = i;"
4234 " if (i == 5) {"
4235 " obj = 239;"
4236 " expected = undefined;"
4237 " }"
4238 " var v = obj[i];"
4239 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4240 " if (i == 5) obj = original;"
4241 " }"
4242 " 'PASSED'"
4243 "} catch(e) {"
4244 " e"
4245 "}";
4246 ExpectString(code, "PASSED");
4247}
4248
4249
4250THREADED_TEST(IndexedInterceptorOnProto) {
4251 v8::HandleScope scope;
4252 Local<ObjectTemplate> templ = ObjectTemplate::New();
4253 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4254
4255 LocalContext context;
4256 Local<v8::Object> obj = templ->NewInstance();
4257 context->Global()->Set(v8_str("obj"), obj);
4258
4259 const char* code =
4260 "var o = {__proto__: obj};"
4261 "try {"
4262 " for (var i = 0; i < 100; i++) {"
4263 " var v = o[i];"
4264 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
4265 " }"
4266 " 'PASSED'"
4267 "} catch(e) {"
4268 " e"
4269 "}";
4270 ExpectString(code, "PASSED");
4271}
4272
4273
Steve Blocka7e24c12009-10-30 11:49:00 +00004274THREADED_TEST(MultiContexts) {
4275 v8::HandleScope scope;
4276 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
4277 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
4278
4279 Local<String> password = v8_str("Password");
4280
4281 // Create an environment
4282 LocalContext context0(0, templ);
4283 context0->SetSecurityToken(password);
4284 v8::Handle<v8::Object> global0 = context0->Global();
4285 global0->Set(v8_str("custom"), v8_num(1234));
4286 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
4287
4288 // Create an independent environment
4289 LocalContext context1(0, templ);
4290 context1->SetSecurityToken(password);
4291 v8::Handle<v8::Object> global1 = context1->Global();
4292 global1->Set(v8_str("custom"), v8_num(1234));
4293 CHECK_NE(global0, global1);
4294 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
4295 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
4296
4297 // Now create a new context with the old global
4298 LocalContext context2(0, templ, global1);
4299 context2->SetSecurityToken(password);
4300 v8::Handle<v8::Object> global2 = context2->Global();
4301 CHECK_EQ(global1, global2);
4302 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
4303 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
4304}
4305
4306
4307THREADED_TEST(FunctionPrototypeAcrossContexts) {
4308 // Make sure that functions created by cloning boilerplates cannot
4309 // communicate through their __proto__ field.
4310
4311 v8::HandleScope scope;
4312
4313 LocalContext env0;
4314 v8::Handle<v8::Object> global0 =
4315 env0->Global();
4316 v8::Handle<v8::Object> object0 =
Steve Block6ded16b2010-05-10 14:33:55 +01004317 global0->Get(v8_str("Object")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00004318 v8::Handle<v8::Object> tostring0 =
Steve Block6ded16b2010-05-10 14:33:55 +01004319 object0->Get(v8_str("toString")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00004320 v8::Handle<v8::Object> proto0 =
Steve Block6ded16b2010-05-10 14:33:55 +01004321 tostring0->Get(v8_str("__proto__")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00004322 proto0->Set(v8_str("custom"), v8_num(1234));
4323
4324 LocalContext env1;
4325 v8::Handle<v8::Object> global1 =
4326 env1->Global();
4327 v8::Handle<v8::Object> object1 =
Steve Block6ded16b2010-05-10 14:33:55 +01004328 global1->Get(v8_str("Object")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00004329 v8::Handle<v8::Object> tostring1 =
Steve Block6ded16b2010-05-10 14:33:55 +01004330 object1->Get(v8_str("toString")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00004331 v8::Handle<v8::Object> proto1 =
Steve Block6ded16b2010-05-10 14:33:55 +01004332 tostring1->Get(v8_str("__proto__")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00004333 CHECK(!proto1->Has(v8_str("custom")));
4334}
4335
4336
4337THREADED_TEST(Regress892105) {
4338 // Make sure that object and array literals created by cloning
4339 // boilerplates cannot communicate through their __proto__
4340 // field. This is rather difficult to check, but we try to add stuff
4341 // to Object.prototype and Array.prototype and create a new
4342 // environment. This should succeed.
4343
4344 v8::HandleScope scope;
4345
4346 Local<String> source = v8_str("Object.prototype.obj = 1234;"
4347 "Array.prototype.arr = 4567;"
4348 "8901");
4349
4350 LocalContext env0;
4351 Local<Script> script0 = Script::Compile(source);
4352 CHECK_EQ(8901.0, script0->Run()->NumberValue());
4353
4354 LocalContext env1;
4355 Local<Script> script1 = Script::Compile(source);
4356 CHECK_EQ(8901.0, script1->Run()->NumberValue());
4357}
4358
4359
Steve Blocka7e24c12009-10-30 11:49:00 +00004360THREADED_TEST(UndetectableObject) {
4361 v8::HandleScope scope;
4362 LocalContext env;
4363
4364 Local<v8::FunctionTemplate> desc =
4365 v8::FunctionTemplate::New(0, v8::Handle<Value>());
4366 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4367
4368 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4369 env->Global()->Set(v8_str("undetectable"), obj);
4370
4371 ExpectString("undetectable.toString()", "[object Object]");
4372 ExpectString("typeof undetectable", "undefined");
4373 ExpectString("typeof(undetectable)", "undefined");
4374 ExpectBoolean("typeof undetectable == 'undefined'", true);
4375 ExpectBoolean("typeof undetectable == 'object'", false);
4376 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
4377 ExpectBoolean("!undetectable", true);
4378
4379 ExpectObject("true&&undetectable", obj);
4380 ExpectBoolean("false&&undetectable", false);
4381 ExpectBoolean("true||undetectable", true);
4382 ExpectObject("false||undetectable", obj);
4383
4384 ExpectObject("undetectable&&true", obj);
4385 ExpectObject("undetectable&&false", obj);
4386 ExpectBoolean("undetectable||true", true);
4387 ExpectBoolean("undetectable||false", false);
4388
4389 ExpectBoolean("undetectable==null", true);
4390 ExpectBoolean("null==undetectable", true);
4391 ExpectBoolean("undetectable==undefined", true);
4392 ExpectBoolean("undefined==undetectable", true);
4393 ExpectBoolean("undetectable==undetectable", true);
4394
4395
4396 ExpectBoolean("undetectable===null", false);
4397 ExpectBoolean("null===undetectable", false);
4398 ExpectBoolean("undetectable===undefined", false);
4399 ExpectBoolean("undefined===undetectable", false);
4400 ExpectBoolean("undetectable===undetectable", true);
4401}
4402
4403
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004404THREADED_TEST(VoidLiteral) {
4405 v8::HandleScope scope;
4406 LocalContext env;
4407
4408 Local<v8::FunctionTemplate> desc =
4409 v8::FunctionTemplate::New(0, v8::Handle<Value>());
4410 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4411
4412 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4413 env->Global()->Set(v8_str("undetectable"), obj);
4414
4415 ExpectBoolean("undefined == void 0", true);
4416 ExpectBoolean("undetectable == void 0", true);
4417 ExpectBoolean("null == void 0", true);
4418 ExpectBoolean("undefined === void 0", true);
4419 ExpectBoolean("undetectable === void 0", false);
4420 ExpectBoolean("null === void 0", false);
4421
4422 ExpectBoolean("void 0 == undefined", true);
4423 ExpectBoolean("void 0 == undetectable", true);
4424 ExpectBoolean("void 0 == null", true);
4425 ExpectBoolean("void 0 === undefined", true);
4426 ExpectBoolean("void 0 === undetectable", false);
4427 ExpectBoolean("void 0 === null", false);
4428
4429 ExpectString("(function() {"
4430 " try {"
4431 " return x === void 0;"
4432 " } catch(e) {"
4433 " return e.toString();"
4434 " }"
4435 "})()",
4436 "ReferenceError: x is not defined");
4437 ExpectString("(function() {"
4438 " try {"
4439 " return void 0 === x;"
4440 " } catch(e) {"
4441 " return e.toString();"
4442 " }"
4443 "})()",
4444 "ReferenceError: x is not defined");
4445}
4446
Steve Block8defd9f2010-07-08 12:39:36 +01004447
4448THREADED_TEST(ExtensibleOnUndetectable) {
4449 v8::HandleScope scope;
4450 LocalContext env;
4451
4452 Local<v8::FunctionTemplate> desc =
4453 v8::FunctionTemplate::New(0, v8::Handle<Value>());
4454 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4455
4456 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4457 env->Global()->Set(v8_str("undetectable"), obj);
4458
4459 Local<String> source = v8_str("undetectable.x = 42;"
4460 "undetectable.x");
4461
4462 Local<Script> script = Script::Compile(source);
4463
4464 CHECK_EQ(v8::Integer::New(42), script->Run());
4465
4466 ExpectBoolean("Object.isExtensible(undetectable)", true);
4467
4468 source = v8_str("Object.preventExtensions(undetectable);");
4469 script = Script::Compile(source);
4470 script->Run();
4471 ExpectBoolean("Object.isExtensible(undetectable)", false);
4472
4473 source = v8_str("undetectable.y = 2000;");
4474 script = Script::Compile(source);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004475 script->Run();
Steve Block44f0eee2011-05-26 01:26:41 +01004476 ExpectBoolean("undetectable.y == undefined", true);
Steve Block8defd9f2010-07-08 12:39:36 +01004477}
4478
4479
4480
Steve Blocka7e24c12009-10-30 11:49:00 +00004481THREADED_TEST(UndetectableString) {
4482 v8::HandleScope scope;
4483 LocalContext env;
4484
4485 Local<String> obj = String::NewUndetectable("foo");
4486 env->Global()->Set(v8_str("undetectable"), obj);
4487
4488 ExpectString("undetectable", "foo");
4489 ExpectString("typeof undetectable", "undefined");
4490 ExpectString("typeof(undetectable)", "undefined");
4491 ExpectBoolean("typeof undetectable == 'undefined'", true);
4492 ExpectBoolean("typeof undetectable == 'string'", false);
4493 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
4494 ExpectBoolean("!undetectable", true);
4495
4496 ExpectObject("true&&undetectable", obj);
4497 ExpectBoolean("false&&undetectable", false);
4498 ExpectBoolean("true||undetectable", true);
4499 ExpectObject("false||undetectable", obj);
4500
4501 ExpectObject("undetectable&&true", obj);
4502 ExpectObject("undetectable&&false", obj);
4503 ExpectBoolean("undetectable||true", true);
4504 ExpectBoolean("undetectable||false", false);
4505
4506 ExpectBoolean("undetectable==null", true);
4507 ExpectBoolean("null==undetectable", true);
4508 ExpectBoolean("undetectable==undefined", true);
4509 ExpectBoolean("undefined==undetectable", true);
4510 ExpectBoolean("undetectable==undetectable", true);
4511
4512
4513 ExpectBoolean("undetectable===null", false);
4514 ExpectBoolean("null===undetectable", false);
4515 ExpectBoolean("undetectable===undefined", false);
4516 ExpectBoolean("undefined===undetectable", false);
4517 ExpectBoolean("undetectable===undetectable", true);
4518}
4519
4520
Ben Murdoch257744e2011-11-30 15:57:28 +00004521TEST(UndetectableOptimized) {
4522 i::FLAG_allow_natives_syntax = true;
4523 v8::HandleScope scope;
4524 LocalContext env;
4525
4526 Local<String> obj = String::NewUndetectable("foo");
4527 env->Global()->Set(v8_str("undetectable"), obj);
4528 env->Global()->Set(v8_str("detectable"), v8_str("bar"));
4529
4530 ExpectString(
4531 "function testBranch() {"
4532 " if (!%_IsUndetectableObject(undetectable)) throw 1;"
4533 " if (%_IsUndetectableObject(detectable)) throw 2;"
4534 "}\n"
4535 "function testBool() {"
4536 " var b1 = !%_IsUndetectableObject(undetectable);"
4537 " var b2 = %_IsUndetectableObject(detectable);"
4538 " if (b1) throw 3;"
4539 " if (b2) throw 4;"
4540 " return b1 == b2;"
4541 "}\n"
4542 "%OptimizeFunctionOnNextCall(testBranch);"
4543 "%OptimizeFunctionOnNextCall(testBool);"
4544 "for (var i = 0; i < 10; i++) {"
4545 " testBranch();"
4546 " testBool();"
4547 "}\n"
4548 "\"PASS\"",
4549 "PASS");
4550}
4551
4552
Steve Blocka7e24c12009-10-30 11:49:00 +00004553template <typename T> static void USE(T) { }
4554
4555
4556// This test is not intended to be run, just type checked.
Ben Murdoch589d6972011-11-30 16:04:58 +00004557static inline void PersistentHandles() {
Steve Blocka7e24c12009-10-30 11:49:00 +00004558 USE(PersistentHandles);
4559 Local<String> str = v8_str("foo");
4560 v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
4561 USE(p_str);
4562 Local<Script> scr = Script::Compile(v8_str(""));
4563 v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
4564 USE(p_scr);
4565 Local<ObjectTemplate> templ = ObjectTemplate::New();
4566 v8::Persistent<ObjectTemplate> p_templ =
4567 v8::Persistent<ObjectTemplate>::New(templ);
4568 USE(p_templ);
4569}
4570
4571
4572static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
4573 ApiTestFuzzer::Fuzz();
4574 return v8::Undefined();
4575}
4576
4577
4578THREADED_TEST(GlobalObjectTemplate) {
4579 v8::HandleScope handle_scope;
4580 Local<ObjectTemplate> global_template = ObjectTemplate::New();
4581 global_template->Set(v8_str("JSNI_Log"),
4582 v8::FunctionTemplate::New(HandleLogDelegator));
4583 v8::Persistent<Context> context = Context::New(0, global_template);
4584 Context::Scope context_scope(context);
4585 Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
4586 context.Dispose();
4587}
4588
4589
4590static const char* kSimpleExtensionSource =
4591 "function Foo() {"
4592 " return 4;"
4593 "}";
4594
4595
4596THREADED_TEST(SimpleExtensions) {
4597 v8::HandleScope handle_scope;
4598 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
4599 const char* extension_names[] = { "simpletest" };
4600 v8::ExtensionConfiguration extensions(1, extension_names);
4601 v8::Handle<Context> context = Context::New(&extensions);
4602 Context::Scope lock(context);
4603 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
4604 CHECK_EQ(result, v8::Integer::New(4));
4605}
4606
4607
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004608static const char* kEmbeddedExtensionSource =
4609 "function Ret54321(){return 54321;}~~@@$"
4610 "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
4611static const int kEmbeddedExtensionSourceValidLen = 34;
4612
4613
4614THREADED_TEST(ExtensionMissingSourceLength) {
4615 v8::HandleScope handle_scope;
4616 v8::RegisterExtension(new Extension("srclentest_fail",
4617 kEmbeddedExtensionSource));
4618 const char* extension_names[] = { "srclentest_fail" };
4619 v8::ExtensionConfiguration extensions(1, extension_names);
4620 v8::Handle<Context> context = Context::New(&extensions);
4621 CHECK_EQ(0, *context);
4622}
4623
4624
4625THREADED_TEST(ExtensionWithSourceLength) {
4626 for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
4627 source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
4628 v8::HandleScope handle_scope;
4629 i::ScopedVector<char> extension_name(32);
4630 i::OS::SNPrintF(extension_name, "ext #%d", source_len);
4631 v8::RegisterExtension(new Extension(extension_name.start(),
4632 kEmbeddedExtensionSource, 0, 0,
4633 source_len));
4634 const char* extension_names[1] = { extension_name.start() };
4635 v8::ExtensionConfiguration extensions(1, extension_names);
4636 v8::Handle<Context> context = Context::New(&extensions);
4637 if (source_len == kEmbeddedExtensionSourceValidLen) {
4638 Context::Scope lock(context);
4639 v8::Handle<Value> result = Script::Compile(v8_str("Ret54321()"))->Run();
4640 CHECK_EQ(v8::Integer::New(54321), result);
4641 } else {
4642 // Anything but exactly the right length should fail to compile.
4643 CHECK_EQ(0, *context);
4644 }
4645 }
4646}
4647
4648
Steve Blocka7e24c12009-10-30 11:49:00 +00004649static const char* kEvalExtensionSource1 =
4650 "function UseEval1() {"
4651 " var x = 42;"
4652 " return eval('x');"
4653 "}";
4654
4655
4656static const char* kEvalExtensionSource2 =
4657 "(function() {"
4658 " var x = 42;"
4659 " function e() {"
4660 " return eval('x');"
4661 " }"
4662 " this.UseEval2 = e;"
4663 "})()";
4664
4665
4666THREADED_TEST(UseEvalFromExtension) {
4667 v8::HandleScope handle_scope;
4668 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
4669 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
4670 const char* extension_names[] = { "evaltest1", "evaltest2" };
4671 v8::ExtensionConfiguration extensions(2, extension_names);
4672 v8::Handle<Context> context = Context::New(&extensions);
4673 Context::Scope lock(context);
4674 v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
4675 CHECK_EQ(result, v8::Integer::New(42));
4676 result = Script::Compile(v8_str("UseEval2()"))->Run();
4677 CHECK_EQ(result, v8::Integer::New(42));
4678}
4679
4680
4681static const char* kWithExtensionSource1 =
4682 "function UseWith1() {"
4683 " var x = 42;"
4684 " with({x:87}) { return x; }"
4685 "}";
4686
4687
4688
4689static const char* kWithExtensionSource2 =
4690 "(function() {"
4691 " var x = 42;"
4692 " function e() {"
4693 " with ({x:87}) { return x; }"
4694 " }"
4695 " this.UseWith2 = e;"
4696 "})()";
4697
4698
4699THREADED_TEST(UseWithFromExtension) {
4700 v8::HandleScope handle_scope;
4701 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
4702 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
4703 const char* extension_names[] = { "withtest1", "withtest2" };
4704 v8::ExtensionConfiguration extensions(2, extension_names);
4705 v8::Handle<Context> context = Context::New(&extensions);
4706 Context::Scope lock(context);
4707 v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
4708 CHECK_EQ(result, v8::Integer::New(87));
4709 result = Script::Compile(v8_str("UseWith2()"))->Run();
4710 CHECK_EQ(result, v8::Integer::New(87));
4711}
4712
4713
4714THREADED_TEST(AutoExtensions) {
4715 v8::HandleScope handle_scope;
4716 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
4717 extension->set_auto_enable(true);
4718 v8::RegisterExtension(extension);
4719 v8::Handle<Context> context = Context::New();
4720 Context::Scope lock(context);
4721 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
4722 CHECK_EQ(result, v8::Integer::New(4));
4723}
4724
4725
Steve Blockd0582a62009-12-15 09:54:21 +00004726static const char* kSyntaxErrorInExtensionSource =
4727 "[";
4728
4729
4730// Test that a syntax error in an extension does not cause a fatal
4731// error but results in an empty context.
4732THREADED_TEST(SyntaxErrorExtensions) {
4733 v8::HandleScope handle_scope;
4734 v8::RegisterExtension(new Extension("syntaxerror",
4735 kSyntaxErrorInExtensionSource));
4736 const char* extension_names[] = { "syntaxerror" };
4737 v8::ExtensionConfiguration extensions(1, extension_names);
4738 v8::Handle<Context> context = Context::New(&extensions);
4739 CHECK(context.IsEmpty());
4740}
4741
4742
4743static const char* kExceptionInExtensionSource =
4744 "throw 42";
4745
4746
4747// Test that an exception when installing an extension does not cause
4748// a fatal error but results in an empty context.
4749THREADED_TEST(ExceptionExtensions) {
4750 v8::HandleScope handle_scope;
4751 v8::RegisterExtension(new Extension("exception",
4752 kExceptionInExtensionSource));
4753 const char* extension_names[] = { "exception" };
4754 v8::ExtensionConfiguration extensions(1, extension_names);
4755 v8::Handle<Context> context = Context::New(&extensions);
4756 CHECK(context.IsEmpty());
4757}
4758
4759
Iain Merrick9ac36c92010-09-13 15:29:50 +01004760static const char* kNativeCallInExtensionSource =
4761 "function call_runtime_last_index_of(x) {"
4762 " return %StringLastIndexOf(x, 'bob', 10);"
4763 "}";
4764
4765
4766static const char* kNativeCallTest =
4767 "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
4768
4769// Test that a native runtime calls are supported in extensions.
4770THREADED_TEST(NativeCallInExtensions) {
4771 v8::HandleScope handle_scope;
4772 v8::RegisterExtension(new Extension("nativecall",
4773 kNativeCallInExtensionSource));
4774 const char* extension_names[] = { "nativecall" };
4775 v8::ExtensionConfiguration extensions(1, extension_names);
4776 v8::Handle<Context> context = Context::New(&extensions);
4777 Context::Scope lock(context);
4778 v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run();
4779 CHECK_EQ(result, v8::Integer::New(3));
4780}
4781
4782
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004783class NativeFunctionExtension : public Extension {
4784 public:
4785 NativeFunctionExtension(const char* name,
4786 const char* source,
4787 v8::InvocationCallback fun = &Echo)
4788 : Extension(name, source),
4789 function_(fun) { }
4790
4791 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
4792 v8::Handle<v8::String> name) {
4793 return v8::FunctionTemplate::New(function_);
4794 }
4795
4796 static v8::Handle<v8::Value> Echo(const v8::Arguments& args) {
4797 if (args.Length() >= 1) return (args[0]);
4798 return v8::Undefined();
4799 }
4800 private:
4801 v8::InvocationCallback function_;
4802};
4803
4804
4805THREADED_TEST(NativeFunctionDeclaration) {
4806 v8::HandleScope handle_scope;
4807 const char* name = "nativedecl";
4808 v8::RegisterExtension(new NativeFunctionExtension(name,
4809 "native function foo();"));
4810 const char* extension_names[] = { name };
4811 v8::ExtensionConfiguration extensions(1, extension_names);
4812 v8::Handle<Context> context = Context::New(&extensions);
4813 Context::Scope lock(context);
4814 v8::Handle<Value> result = Script::Compile(v8_str("foo(42);"))->Run();
4815 CHECK_EQ(result, v8::Integer::New(42));
4816}
4817
4818
4819THREADED_TEST(NativeFunctionDeclarationError) {
4820 v8::HandleScope handle_scope;
4821 const char* name = "nativedeclerr";
4822 // Syntax error in extension code.
4823 v8::RegisterExtension(new NativeFunctionExtension(name,
4824 "native\nfunction foo();"));
4825 const char* extension_names[] = { name };
4826 v8::ExtensionConfiguration extensions(1, extension_names);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004827 v8::Handle<Context> context(Context::New(&extensions));
4828 CHECK(context.IsEmpty());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004829}
4830
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004831
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004832THREADED_TEST(NativeFunctionDeclarationErrorEscape) {
4833 v8::HandleScope handle_scope;
4834 const char* name = "nativedeclerresc";
4835 // Syntax error in extension code - escape code in "native" means that
4836 // it's not treated as a keyword.
4837 v8::RegisterExtension(new NativeFunctionExtension(
4838 name,
4839 "nativ\\u0065 function foo();"));
4840 const char* extension_names[] = { name };
4841 v8::ExtensionConfiguration extensions(1, extension_names);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004842 v8::Handle<Context> context(Context::New(&extensions));
4843 CHECK(context.IsEmpty());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004844}
4845
4846
Steve Blocka7e24c12009-10-30 11:49:00 +00004847static void CheckDependencies(const char* name, const char* expected) {
4848 v8::HandleScope handle_scope;
4849 v8::ExtensionConfiguration config(1, &name);
4850 LocalContext context(&config);
4851 CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
4852}
4853
4854
4855/*
4856 * Configuration:
4857 *
4858 * /-- B <--\
4859 * A <- -- D <-- E
4860 * \-- C <--/
4861 */
4862THREADED_TEST(ExtensionDependency) {
4863 static const char* kEDeps[] = { "D" };
4864 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
4865 static const char* kDDeps[] = { "B", "C" };
4866 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
4867 static const char* kBCDeps[] = { "A" };
4868 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
4869 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
4870 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
4871 CheckDependencies("A", "undefinedA");
4872 CheckDependencies("B", "undefinedAB");
4873 CheckDependencies("C", "undefinedAC");
4874 CheckDependencies("D", "undefinedABCD");
4875 CheckDependencies("E", "undefinedABCDE");
4876 v8::HandleScope handle_scope;
4877 static const char* exts[2] = { "C", "E" };
4878 v8::ExtensionConfiguration config(2, exts);
4879 LocalContext context(&config);
4880 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
4881}
4882
4883
4884static const char* kExtensionTestScript =
4885 "native function A();"
4886 "native function B();"
4887 "native function C();"
4888 "function Foo(i) {"
4889 " if (i == 0) return A();"
4890 " if (i == 1) return B();"
4891 " if (i == 2) return C();"
4892 "}";
4893
4894
4895static v8::Handle<Value> CallFun(const v8::Arguments& args) {
4896 ApiTestFuzzer::Fuzz();
Leon Clarkee46be812010-01-19 14:06:41 +00004897 if (args.IsConstructCall()) {
4898 args.This()->Set(v8_str("data"), args.Data());
4899 return v8::Null();
4900 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004901 return args.Data();
4902}
4903
4904
4905class FunctionExtension : public Extension {
4906 public:
4907 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
4908 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
4909 v8::Handle<String> name);
4910};
4911
4912
4913static int lookup_count = 0;
4914v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
4915 v8::Handle<String> name) {
4916 lookup_count++;
4917 if (name->Equals(v8_str("A"))) {
4918 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
4919 } else if (name->Equals(v8_str("B"))) {
4920 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
4921 } else if (name->Equals(v8_str("C"))) {
4922 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
4923 } else {
4924 return v8::Handle<v8::FunctionTemplate>();
4925 }
4926}
4927
4928
4929THREADED_TEST(FunctionLookup) {
4930 v8::RegisterExtension(new FunctionExtension());
4931 v8::HandleScope handle_scope;
4932 static const char* exts[1] = { "functiontest" };
4933 v8::ExtensionConfiguration config(1, exts);
4934 LocalContext context(&config);
4935 CHECK_EQ(3, lookup_count);
4936 CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
4937 CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
4938 CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
4939}
4940
4941
Leon Clarkee46be812010-01-19 14:06:41 +00004942THREADED_TEST(NativeFunctionConstructCall) {
4943 v8::RegisterExtension(new FunctionExtension());
4944 v8::HandleScope handle_scope;
4945 static const char* exts[1] = { "functiontest" };
4946 v8::ExtensionConfiguration config(1, exts);
4947 LocalContext context(&config);
Leon Clarked91b9f72010-01-27 17:25:45 +00004948 for (int i = 0; i < 10; i++) {
4949 // Run a few times to ensure that allocation of objects doesn't
4950 // change behavior of a constructor function.
4951 CHECK_EQ(v8::Integer::New(8),
4952 Script::Compile(v8_str("(new A()).data"))->Run());
4953 CHECK_EQ(v8::Integer::New(7),
4954 Script::Compile(v8_str("(new B()).data"))->Run());
4955 CHECK_EQ(v8::Integer::New(6),
4956 Script::Compile(v8_str("(new C()).data"))->Run());
4957 }
Leon Clarkee46be812010-01-19 14:06:41 +00004958}
4959
4960
Steve Blocka7e24c12009-10-30 11:49:00 +00004961static const char* last_location;
4962static const char* last_message;
4963void StoringErrorCallback(const char* location, const char* message) {
4964 if (last_location == NULL) {
4965 last_location = location;
4966 last_message = message;
4967 }
4968}
4969
4970
4971// ErrorReporting creates a circular extensions configuration and
4972// tests that the fatal error handler gets called. This renders V8
4973// unusable and therefore this test cannot be run in parallel.
4974TEST(ErrorReporting) {
4975 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
4976 static const char* aDeps[] = { "B" };
4977 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
4978 static const char* bDeps[] = { "A" };
4979 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
4980 last_location = NULL;
4981 v8::ExtensionConfiguration config(1, bDeps);
4982 v8::Handle<Context> context = Context::New(&config);
4983 CHECK(context.IsEmpty());
4984 CHECK_NE(last_location, NULL);
4985}
4986
4987
4988static const char* js_code_causing_huge_string_flattening =
4989 "var str = 'X';"
4990 "for (var i = 0; i < 30; i++) {"
4991 " str = str + str;"
4992 "}"
4993 "str.match(/X/);";
4994
4995
4996void OOMCallback(const char* location, const char* message) {
4997 exit(0);
4998}
4999
5000
5001TEST(RegexpOutOfMemory) {
5002 // Execute a script that causes out of memory when flattening a string.
5003 v8::HandleScope scope;
5004 v8::V8::SetFatalErrorHandler(OOMCallback);
5005 LocalContext context;
5006 Local<Script> script =
5007 Script::Compile(String::New(js_code_causing_huge_string_flattening));
5008 last_location = NULL;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005009 script->Run();
Steve Blocka7e24c12009-10-30 11:49:00 +00005010
5011 CHECK(false); // Should not return.
5012}
5013
5014
5015static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
5016 v8::Handle<Value> data) {
5017 CHECK_EQ(v8::Undefined(), data);
5018 CHECK(message->GetScriptResourceName()->IsUndefined());
5019 CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
5020 message->GetLineNumber();
5021 message->GetSourceLine();
5022}
5023
5024
5025THREADED_TEST(ErrorWithMissingScriptInfo) {
5026 v8::HandleScope scope;
5027 LocalContext context;
5028 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
5029 Script::Compile(v8_str("throw Error()"))->Run();
5030 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
5031}
5032
5033
5034int global_index = 0;
5035
5036class Snorkel {
5037 public:
5038 Snorkel() { index_ = global_index++; }
5039 int index_;
5040};
5041
5042class Whammy {
5043 public:
5044 Whammy() {
5045 cursor_ = 0;
5046 }
5047 ~Whammy() {
5048 script_.Dispose();
5049 }
5050 v8::Handle<Script> getScript() {
5051 if (script_.IsEmpty())
5052 script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
5053 return Local<Script>(*script_);
5054 }
5055
5056 public:
5057 static const int kObjectCount = 256;
5058 int cursor_;
5059 v8::Persistent<v8::Object> objects_[kObjectCount];
5060 v8::Persistent<Script> script_;
5061};
5062
5063static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
5064 Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
5065 delete snorkel;
5066 obj.ClearWeak();
5067}
5068
5069v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
5070 const AccessorInfo& info) {
5071 Whammy* whammy =
5072 static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
5073
5074 v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
5075
5076 v8::Handle<v8::Object> obj = v8::Object::New();
5077 v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
5078 if (!prev.IsEmpty()) {
5079 prev->Set(v8_str("next"), obj);
5080 prev.MakeWeak(new Snorkel(), &HandleWeakReference);
5081 whammy->objects_[whammy->cursor_].Clear();
5082 }
5083 whammy->objects_[whammy->cursor_] = global;
5084 whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
5085 return whammy->getScript()->Run();
5086}
5087
5088THREADED_TEST(WeakReference) {
5089 v8::HandleScope handle_scope;
5090 v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
Ben Murdoch3bec4d22010-07-22 14:51:16 +01005091 Whammy* whammy = new Whammy();
Steve Blocka7e24c12009-10-30 11:49:00 +00005092 templ->SetNamedPropertyHandler(WhammyPropertyGetter,
5093 0, 0, 0, 0,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01005094 v8::External::New(whammy));
Steve Blocka7e24c12009-10-30 11:49:00 +00005095 const char* extension_list[] = { "v8/gc" };
5096 v8::ExtensionConfiguration extensions(1, extension_list);
5097 v8::Persistent<Context> context = Context::New(&extensions);
5098 Context::Scope context_scope(context);
5099
5100 v8::Handle<v8::Object> interceptor = templ->NewInstance();
5101 context->Global()->Set(v8_str("whammy"), interceptor);
5102 const char* code =
5103 "var last;"
5104 "for (var i = 0; i < 10000; i++) {"
5105 " var obj = whammy.length;"
5106 " if (last) last.next = obj;"
5107 " last = obj;"
5108 "}"
5109 "gc();"
5110 "4";
5111 v8::Handle<Value> result = CompileRun(code);
5112 CHECK_EQ(4.0, result->NumberValue());
Ben Murdoch3bec4d22010-07-22 14:51:16 +01005113 delete whammy;
Steve Blocka7e24c12009-10-30 11:49:00 +00005114 context.Dispose();
5115}
5116
5117
Ben Murdoch257744e2011-11-30 15:57:28 +00005118static void DisposeAndSetFlag(v8::Persistent<v8::Value> obj, void* data) {
Steve Blockd0582a62009-12-15 09:54:21 +00005119 obj.Dispose();
5120 obj.Clear();
Steve Blockd0582a62009-12-15 09:54:21 +00005121 *(reinterpret_cast<bool*>(data)) = true;
5122}
5123
Steve Blockd0582a62009-12-15 09:54:21 +00005124
Ben Murdoch257744e2011-11-30 15:57:28 +00005125THREADED_TEST(IndependentWeakHandle) {
Steve Blockd0582a62009-12-15 09:54:21 +00005126 v8::Persistent<Context> context = Context::New();
5127 Context::Scope context_scope(context);
5128
5129 v8::Persistent<v8::Object> object_a;
Steve Blockd0582a62009-12-15 09:54:21 +00005130
5131 {
5132 v8::HandleScope handle_scope;
Steve Blockd0582a62009-12-15 09:54:21 +00005133 object_a = v8::Persistent<v8::Object>::New(v8::Object::New());
5134 }
5135
5136 bool object_a_disposed = false;
Ben Murdoch257744e2011-11-30 15:57:28 +00005137 object_a.MakeWeak(&object_a_disposed, &DisposeAndSetFlag);
5138 object_a.MarkIndependent();
5139 HEAP->PerformScavenge();
5140 CHECK(object_a_disposed);
5141}
Steve Blockd0582a62009-12-15 09:54:21 +00005142
Ben Murdoch257744e2011-11-30 15:57:28 +00005143
5144static void InvokeScavenge() {
5145 HEAP->PerformScavenge();
5146}
5147
5148
5149static void InvokeMarkSweep() {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005150 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Ben Murdoch257744e2011-11-30 15:57:28 +00005151}
5152
5153
5154static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
5155 obj.Dispose();
5156 obj.Clear();
5157 *(reinterpret_cast<bool*>(data)) = true;
5158 InvokeScavenge();
5159}
5160
5161
5162static void ForceMarkSweep(v8::Persistent<v8::Value> obj, void* data) {
5163 obj.Dispose();
5164 obj.Clear();
5165 *(reinterpret_cast<bool*>(data)) = true;
5166 InvokeMarkSweep();
5167}
5168
5169
5170THREADED_TEST(GCFromWeakCallbacks) {
5171 v8::Persistent<Context> context = Context::New();
5172 Context::Scope context_scope(context);
5173
5174 static const int kNumberOfGCTypes = 2;
5175 v8::WeakReferenceCallback gc_forcing_callback[kNumberOfGCTypes] =
5176 {&ForceScavenge, &ForceMarkSweep};
5177
5178 typedef void (*GCInvoker)();
5179 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
5180
5181 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
5182 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
5183 v8::Persistent<v8::Object> object;
5184 {
5185 v8::HandleScope handle_scope;
5186 object = v8::Persistent<v8::Object>::New(v8::Object::New());
5187 }
5188 bool disposed = false;
5189 object.MakeWeak(&disposed, gc_forcing_callback[inner_gc]);
5190 object.MarkIndependent();
5191 invoke_gc[outer_gc]();
5192 CHECK(disposed);
5193 }
Steve Blockd0582a62009-12-15 09:54:21 +00005194 }
Ben Murdoch257744e2011-11-30 15:57:28 +00005195}
5196
5197
5198static void RevivingCallback(v8::Persistent<v8::Value> obj, void* data) {
5199 obj.ClearWeak();
5200 *(reinterpret_cast<bool*>(data)) = true;
5201}
5202
5203
5204THREADED_TEST(IndependentHandleRevival) {
5205 v8::Persistent<Context> context = Context::New();
5206 Context::Scope context_scope(context);
5207
5208 v8::Persistent<v8::Object> object;
5209 {
5210 v8::HandleScope handle_scope;
5211 object = v8::Persistent<v8::Object>::New(v8::Object::New());
5212 object->Set(v8_str("x"), v8::Integer::New(1));
5213 v8::Local<String> y_str = v8_str("y");
5214 object->Set(y_str, y_str);
5215 }
5216 bool revived = false;
5217 object.MakeWeak(&revived, &RevivingCallback);
5218 object.MarkIndependent();
5219 HEAP->PerformScavenge();
5220 CHECK(revived);
5221 HEAP->CollectAllGarbage(true);
5222 {
5223 v8::HandleScope handle_scope;
5224 v8::Local<String> y_str = v8_str("y");
5225 CHECK_EQ(v8::Integer::New(1), object->Get(v8_str("x")));
5226 CHECK(object->Get(y_str)->Equals(y_str));
5227 }
Steve Blockd0582a62009-12-15 09:54:21 +00005228}
5229
5230
Steve Blocka7e24c12009-10-30 11:49:00 +00005231v8::Handle<Function> args_fun;
5232
5233
5234static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
5235 ApiTestFuzzer::Fuzz();
5236 CHECK_EQ(args_fun, args.Callee());
5237 CHECK_EQ(3, args.Length());
5238 CHECK_EQ(v8::Integer::New(1), args[0]);
5239 CHECK_EQ(v8::Integer::New(2), args[1]);
5240 CHECK_EQ(v8::Integer::New(3), args[2]);
5241 CHECK_EQ(v8::Undefined(), args[3]);
5242 v8::HandleScope scope;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005243 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +00005244 return v8::Undefined();
5245}
5246
5247
5248THREADED_TEST(Arguments) {
5249 v8::HandleScope scope;
5250 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
5251 global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
5252 LocalContext context(NULL, global);
Steve Block6ded16b2010-05-10 14:33:55 +01005253 args_fun = context->Global()->Get(v8_str("f")).As<Function>();
Steve Blocka7e24c12009-10-30 11:49:00 +00005254 v8_compile("f(1, 2, 3)")->Run();
5255}
5256
5257
Steve Blocka7e24c12009-10-30 11:49:00 +00005258static v8::Handle<Value> NoBlockGetterX(Local<String> name,
5259 const AccessorInfo&) {
5260 return v8::Handle<Value>();
5261}
5262
5263
5264static v8::Handle<Value> NoBlockGetterI(uint32_t index,
5265 const AccessorInfo&) {
5266 return v8::Handle<Value>();
5267}
5268
5269
5270static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
5271 const AccessorInfo&) {
5272 if (!name->Equals(v8_str("foo"))) {
5273 return v8::Handle<v8::Boolean>(); // not intercepted
5274 }
5275
5276 return v8::False(); // intercepted, and don't delete the property
5277}
5278
5279
5280static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
5281 if (index != 2) {
5282 return v8::Handle<v8::Boolean>(); // not intercepted
5283 }
5284
5285 return v8::False(); // intercepted, and don't delete the property
5286}
5287
5288
5289THREADED_TEST(Deleter) {
5290 v8::HandleScope scope;
5291 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5292 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
5293 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
5294 LocalContext context;
5295 context->Global()->Set(v8_str("k"), obj->NewInstance());
5296 CompileRun(
5297 "k.foo = 'foo';"
5298 "k.bar = 'bar';"
5299 "k[2] = 2;"
5300 "k[4] = 4;");
5301 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
5302 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
5303
5304 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
5305 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
5306
5307 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
5308 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
5309
5310 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
5311 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
5312}
5313
5314
5315static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
5316 ApiTestFuzzer::Fuzz();
5317 if (name->Equals(v8_str("foo")) ||
5318 name->Equals(v8_str("bar")) ||
5319 name->Equals(v8_str("baz"))) {
5320 return v8::Undefined();
5321 }
5322 return v8::Handle<Value>();
5323}
5324
5325
5326static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
5327 ApiTestFuzzer::Fuzz();
5328 if (index == 0 || index == 1) return v8::Undefined();
5329 return v8::Handle<Value>();
5330}
5331
5332
5333static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
5334 ApiTestFuzzer::Fuzz();
5335 v8::Handle<v8::Array> result = v8::Array::New(3);
5336 result->Set(v8::Integer::New(0), v8_str("foo"));
5337 result->Set(v8::Integer::New(1), v8_str("bar"));
5338 result->Set(v8::Integer::New(2), v8_str("baz"));
5339 return result;
5340}
5341
5342
5343static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
5344 ApiTestFuzzer::Fuzz();
5345 v8::Handle<v8::Array> result = v8::Array::New(2);
5346 result->Set(v8::Integer::New(0), v8_str("0"));
5347 result->Set(v8::Integer::New(1), v8_str("1"));
5348 return result;
5349}
5350
5351
5352THREADED_TEST(Enumerators) {
5353 v8::HandleScope scope;
5354 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5355 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
5356 obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
5357 LocalContext context;
5358 context->Global()->Set(v8_str("k"), obj->NewInstance());
5359 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
5360 "k[10] = 0;"
5361 "k.a = 0;"
5362 "k[5] = 0;"
5363 "k.b = 0;"
5364 "k[4294967295] = 0;"
5365 "k.c = 0;"
5366 "k[4294967296] = 0;"
5367 "k.d = 0;"
5368 "k[140000] = 0;"
5369 "k.e = 0;"
5370 "k[30000000000] = 0;"
5371 "k.f = 0;"
5372 "var result = [];"
5373 "for (var prop in k) {"
5374 " result.push(prop);"
5375 "}"
5376 "result"));
5377 // Check that we get all the property names returned including the
5378 // ones from the enumerators in the right order: indexed properties
5379 // in numerical order, indexed interceptor properties, named
5380 // properties in insertion order, named interceptor properties.
5381 // This order is not mandated by the spec, so this test is just
5382 // documenting our behavior.
5383 CHECK_EQ(17, result->Length());
5384 // Indexed properties in numerical order.
5385 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
5386 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
5387 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
5388 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
5389 // Indexed interceptor properties in the order they are returned
5390 // from the enumerator interceptor.
5391 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
5392 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
5393 // Named properties in insertion order.
5394 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
5395 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
5396 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
5397 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
5398 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
5399 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
5400 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
5401 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
5402 // Named interceptor properties.
5403 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
5404 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
5405 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
5406}
5407
5408
5409int p_getter_count;
5410int p_getter_count2;
5411
5412
5413static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
5414 ApiTestFuzzer::Fuzz();
5415 p_getter_count++;
5416 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5417 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
5418 if (name->Equals(v8_str("p1"))) {
5419 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
5420 } else if (name->Equals(v8_str("p2"))) {
5421 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
5422 } else if (name->Equals(v8_str("p3"))) {
5423 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
5424 } else if (name->Equals(v8_str("p4"))) {
5425 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
5426 }
5427 return v8::Undefined();
5428}
5429
5430
5431static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
5432 ApiTestFuzzer::Fuzz();
5433 LocalContext context;
5434 context->Global()->Set(v8_str("o1"), obj->NewInstance());
5435 CompileRun(
5436 "o1.__proto__ = { };"
5437 "var o2 = { __proto__: o1 };"
5438 "var o3 = { __proto__: o2 };"
5439 "var o4 = { __proto__: o3 };"
5440 "for (var i = 0; i < 10; i++) o4.p4;"
5441 "for (var i = 0; i < 10; i++) o3.p3;"
5442 "for (var i = 0; i < 10; i++) o2.p2;"
5443 "for (var i = 0; i < 10; i++) o1.p1;");
5444}
5445
5446
5447static v8::Handle<Value> PGetter2(Local<String> name,
5448 const AccessorInfo& info) {
5449 ApiTestFuzzer::Fuzz();
5450 p_getter_count2++;
5451 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5452 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
5453 if (name->Equals(v8_str("p1"))) {
5454 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
5455 } else if (name->Equals(v8_str("p2"))) {
5456 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
5457 } else if (name->Equals(v8_str("p3"))) {
5458 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
5459 } else if (name->Equals(v8_str("p4"))) {
5460 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
5461 }
5462 return v8::Undefined();
5463}
5464
5465
5466THREADED_TEST(GetterHolders) {
5467 v8::HandleScope scope;
5468 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5469 obj->SetAccessor(v8_str("p1"), PGetter);
5470 obj->SetAccessor(v8_str("p2"), PGetter);
5471 obj->SetAccessor(v8_str("p3"), PGetter);
5472 obj->SetAccessor(v8_str("p4"), PGetter);
5473 p_getter_count = 0;
5474 RunHolderTest(obj);
5475 CHECK_EQ(40, p_getter_count);
5476}
5477
5478
5479THREADED_TEST(PreInterceptorHolders) {
5480 v8::HandleScope scope;
5481 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5482 obj->SetNamedPropertyHandler(PGetter2);
5483 p_getter_count2 = 0;
5484 RunHolderTest(obj);
5485 CHECK_EQ(40, p_getter_count2);
5486}
5487
5488
5489THREADED_TEST(ObjectInstantiation) {
5490 v8::HandleScope scope;
5491 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5492 templ->SetAccessor(v8_str("t"), PGetter2);
5493 LocalContext context;
5494 context->Global()->Set(v8_str("o"), templ->NewInstance());
5495 for (int i = 0; i < 100; i++) {
5496 v8::HandleScope inner_scope;
5497 v8::Handle<v8::Object> obj = templ->NewInstance();
5498 CHECK_NE(obj, context->Global()->Get(v8_str("o")));
5499 context->Global()->Set(v8_str("o2"), obj);
5500 v8::Handle<Value> value =
5501 Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
5502 CHECK_EQ(v8::True(), value);
5503 context->Global()->Set(v8_str("o"), obj);
5504 }
5505}
5506
5507
Ben Murdochb0fe1622011-05-05 13:52:32 +01005508static int StrCmp16(uint16_t* a, uint16_t* b) {
5509 while (true) {
5510 if (*a == 0 && *b == 0) return 0;
5511 if (*a != *b) return 0 + *a - *b;
5512 a++;
5513 b++;
5514 }
5515}
5516
5517
5518static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
5519 while (true) {
5520 if (n-- == 0) return 0;
5521 if (*a == 0 && *b == 0) return 0;
5522 if (*a != *b) return 0 + *a - *b;
5523 a++;
5524 b++;
5525 }
5526}
5527
5528
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005529int GetUtf8Length(Handle<String> str) {
5530 int len = str->Utf8Length();
5531 if (len < 0) {
5532 i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
5533 i::FlattenString(istr);
5534 len = str->Utf8Length();
5535 }
5536 return len;
5537}
5538
5539
Steve Blocka7e24c12009-10-30 11:49:00 +00005540THREADED_TEST(StringWrite) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005541 LocalContext context;
Steve Blocka7e24c12009-10-30 11:49:00 +00005542 v8::HandleScope scope;
5543 v8::Handle<String> str = v8_str("abcde");
Ben Murdochb0fe1622011-05-05 13:52:32 +01005544 // abc<Icelandic eth><Unicode snowman>.
5545 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005546 const int kStride = 4; // Must match stride in for loops in JS below.
5547 CompileRun(
5548 "var left = '';"
5549 "for (var i = 0; i < 0xd800; i += 4) {"
5550 " left = left + String.fromCharCode(i);"
5551 "}");
5552 CompileRun(
5553 "var right = '';"
5554 "for (var i = 0; i < 0xd800; i += 4) {"
5555 " right = String.fromCharCode(i) + right;"
5556 "}");
5557 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5558 Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
5559 Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
Ben Murdochb0fe1622011-05-05 13:52:32 +01005560
5561 CHECK_EQ(5, str2->Length());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005562 CHECK_EQ(0xd800 / kStride, left_tree->Length());
5563 CHECK_EQ(0xd800 / kStride, right_tree->Length());
Steve Blocka7e24c12009-10-30 11:49:00 +00005564
5565 char buf[100];
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005566 char utf8buf[0xd800 * 3];
Ben Murdochb0fe1622011-05-05 13:52:32 +01005567 uint16_t wbuf[100];
Steve Blocka7e24c12009-10-30 11:49:00 +00005568 int len;
Ben Murdochb0fe1622011-05-05 13:52:32 +01005569 int charlen;
5570
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005571 memset(utf8buf, 0x1, 1000);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005572 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01005573 CHECK_EQ(9, len);
5574 CHECK_EQ(5, charlen);
5575 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005576
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005577 memset(utf8buf, 0x1, 1000);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005578 len = str2->WriteUtf8(utf8buf, 8, &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01005579 CHECK_EQ(8, len);
5580 CHECK_EQ(5, charlen);
5581 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005582
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005583 memset(utf8buf, 0x1, 1000);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005584 len = str2->WriteUtf8(utf8buf, 7, &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01005585 CHECK_EQ(5, len);
5586 CHECK_EQ(4, charlen);
5587 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005588
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005589 memset(utf8buf, 0x1, 1000);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005590 len = str2->WriteUtf8(utf8buf, 6, &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01005591 CHECK_EQ(5, len);
5592 CHECK_EQ(4, charlen);
5593 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005594
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005595 memset(utf8buf, 0x1, 1000);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005596 len = str2->WriteUtf8(utf8buf, 5, &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01005597 CHECK_EQ(5, len);
5598 CHECK_EQ(4, charlen);
5599 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005600
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005601 memset(utf8buf, 0x1, 1000);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005602 len = str2->WriteUtf8(utf8buf, 4, &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01005603 CHECK_EQ(3, len);
5604 CHECK_EQ(3, charlen);
5605 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005606
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005607 memset(utf8buf, 0x1, 1000);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005608 len = str2->WriteUtf8(utf8buf, 3, &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01005609 CHECK_EQ(3, len);
5610 CHECK_EQ(3, charlen);
5611 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005612
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005613 memset(utf8buf, 0x1, 1000);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005614 len = str2->WriteUtf8(utf8buf, 2, &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01005615 CHECK_EQ(2, len);
5616 CHECK_EQ(2, charlen);
5617 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
Steve Blocka7e24c12009-10-30 11:49:00 +00005618
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005619 memset(utf8buf, 0x1, sizeof(utf8buf));
5620 len = GetUtf8Length(left_tree);
5621 int utf8_expected =
5622 (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
5623 CHECK_EQ(utf8_expected, len);
5624 len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
5625 CHECK_EQ(utf8_expected, len);
5626 CHECK_EQ(0xd800 / kStride, charlen);
5627 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
5628 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
5629 CHECK_EQ(0xc0 - kStride,
5630 static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
5631 CHECK_EQ(1, utf8buf[utf8_expected]);
5632
5633 memset(utf8buf, 0x1, sizeof(utf8buf));
5634 len = GetUtf8Length(right_tree);
5635 CHECK_EQ(utf8_expected, len);
5636 len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
5637 CHECK_EQ(utf8_expected, len);
5638 CHECK_EQ(0xd800 / kStride, charlen);
5639 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
5640 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
5641 CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
5642 CHECK_EQ(1, utf8buf[utf8_expected]);
5643
Steve Blocka7e24c12009-10-30 11:49:00 +00005644 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005645 memset(wbuf, 0x1, sizeof(wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00005646 len = str->WriteAscii(buf);
Steve Block44f0eee2011-05-26 01:26:41 +01005647 CHECK_EQ(5, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005648 len = str->Write(wbuf);
Steve Block44f0eee2011-05-26 01:26:41 +01005649 CHECK_EQ(5, len);
5650 CHECK_EQ(0, strcmp("abcde", buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005651 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
Steve Block44f0eee2011-05-26 01:26:41 +01005652 CHECK_EQ(0, StrCmp16(answer1, wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00005653
5654 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005655 memset(wbuf, 0x1, sizeof(wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00005656 len = str->WriteAscii(buf, 0, 4);
Steve Block44f0eee2011-05-26 01:26:41 +01005657 CHECK_EQ(4, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005658 len = str->Write(wbuf, 0, 4);
Steve Block44f0eee2011-05-26 01:26:41 +01005659 CHECK_EQ(4, len);
5660 CHECK_EQ(0, strncmp("abcd\1", buf, 5));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005661 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
Steve Block44f0eee2011-05-26 01:26:41 +01005662 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
Steve Blocka7e24c12009-10-30 11:49:00 +00005663
5664 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005665 memset(wbuf, 0x1, sizeof(wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00005666 len = str->WriteAscii(buf, 0, 5);
Steve Block44f0eee2011-05-26 01:26:41 +01005667 CHECK_EQ(5, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005668 len = str->Write(wbuf, 0, 5);
Steve Block44f0eee2011-05-26 01:26:41 +01005669 CHECK_EQ(5, len);
5670 CHECK_EQ(0, strncmp("abcde\1", buf, 6));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005671 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
Steve Block44f0eee2011-05-26 01:26:41 +01005672 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
Steve Blocka7e24c12009-10-30 11:49:00 +00005673
5674 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005675 memset(wbuf, 0x1, sizeof(wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00005676 len = str->WriteAscii(buf, 0, 6);
Steve Block44f0eee2011-05-26 01:26:41 +01005677 CHECK_EQ(5, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005678 len = str->Write(wbuf, 0, 6);
Steve Block44f0eee2011-05-26 01:26:41 +01005679 CHECK_EQ(5, len);
5680 CHECK_EQ(0, strcmp("abcde", buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005681 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
Steve Block44f0eee2011-05-26 01:26:41 +01005682 CHECK_EQ(0, StrCmp16(answer4, wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00005683
5684 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005685 memset(wbuf, 0x1, sizeof(wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00005686 len = str->WriteAscii(buf, 4, -1);
Steve Block44f0eee2011-05-26 01:26:41 +01005687 CHECK_EQ(1, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005688 len = str->Write(wbuf, 4, -1);
Steve Block44f0eee2011-05-26 01:26:41 +01005689 CHECK_EQ(1, len);
5690 CHECK_EQ(0, strcmp("e", buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005691 uint16_t answer5[] = {'e', '\0'};
Steve Block44f0eee2011-05-26 01:26:41 +01005692 CHECK_EQ(0, StrCmp16(answer5, wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00005693
5694 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005695 memset(wbuf, 0x1, sizeof(wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00005696 len = str->WriteAscii(buf, 4, 6);
Steve Block44f0eee2011-05-26 01:26:41 +01005697 CHECK_EQ(1, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005698 len = str->Write(wbuf, 4, 6);
Steve Block44f0eee2011-05-26 01:26:41 +01005699 CHECK_EQ(1, len);
5700 CHECK_EQ(0, strcmp("e", buf));
5701 CHECK_EQ(0, StrCmp16(answer5, wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00005702
5703 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005704 memset(wbuf, 0x1, sizeof(wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00005705 len = str->WriteAscii(buf, 4, 1);
Steve Block44f0eee2011-05-26 01:26:41 +01005706 CHECK_EQ(1, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005707 len = str->Write(wbuf, 4, 1);
Steve Block44f0eee2011-05-26 01:26:41 +01005708 CHECK_EQ(1, len);
5709 CHECK_EQ(0, strncmp("e\1", buf, 2));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005710 uint16_t answer6[] = {'e', 0x101};
Steve Block44f0eee2011-05-26 01:26:41 +01005711 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005712
5713 memset(buf, 0x1, sizeof(buf));
5714 memset(wbuf, 0x1, sizeof(wbuf));
5715 len = str->WriteAscii(buf, 3, 1);
Steve Block44f0eee2011-05-26 01:26:41 +01005716 CHECK_EQ(1, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005717 len = str->Write(wbuf, 3, 1);
Steve Block44f0eee2011-05-26 01:26:41 +01005718 CHECK_EQ(1, len);
5719 CHECK_EQ(0, strncmp("d\1", buf, 2));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005720 uint16_t answer7[] = {'d', 0x101};
Steve Block44f0eee2011-05-26 01:26:41 +01005721 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005722
5723 memset(wbuf, 0x1, sizeof(wbuf));
5724 wbuf[5] = 'X';
5725 len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
5726 CHECK_EQ(5, len);
5727 CHECK_EQ('X', wbuf[5]);
5728 uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
5729 uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
5730 CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
5731 CHECK_NE(0, StrCmp16(answer8b, wbuf));
5732 wbuf[5] = '\0';
5733 CHECK_EQ(0, StrCmp16(answer8b, wbuf));
5734
5735 memset(buf, 0x1, sizeof(buf));
5736 buf[5] = 'X';
5737 len = str->WriteAscii(buf, 0, 6, String::NO_NULL_TERMINATION);
5738 CHECK_EQ(5, len);
5739 CHECK_EQ('X', buf[5]);
5740 CHECK_EQ(0, strncmp("abcde", buf, 5));
5741 CHECK_NE(0, strcmp("abcde", buf));
5742 buf[5] = '\0';
5743 CHECK_EQ(0, strcmp("abcde", buf));
5744
5745 memset(utf8buf, 0x1, sizeof(utf8buf));
5746 utf8buf[8] = 'X';
5747 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
5748 String::NO_NULL_TERMINATION);
5749 CHECK_EQ(8, len);
5750 CHECK_EQ('X', utf8buf[8]);
5751 CHECK_EQ(5, charlen);
5752 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
5753 CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
5754 utf8buf[8] = '\0';
5755 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
Steve Blocka7e24c12009-10-30 11:49:00 +00005756}
5757
5758
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005759static void Utf16Helper(
5760 LocalContext& context,
5761 const char* name,
5762 const char* lengths_name,
5763 int len) {
5764 Local<v8::Array> a =
5765 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
5766 Local<v8::Array> alens =
5767 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
5768 for (int i = 0; i < len; i++) {
5769 Local<v8::String> string =
5770 Local<v8::String>::Cast(a->Get(i));
5771 Local<v8::Number> expected_len =
5772 Local<v8::Number>::Cast(alens->Get(i));
5773 CHECK_EQ(expected_len->Value() != string->Length(),
5774 string->MayContainNonAscii());
5775 int length = GetUtf8Length(string);
5776 CHECK_EQ(static_cast<int>(expected_len->Value()), length);
5777 }
5778}
5779
5780
5781static uint16_t StringGet(Handle<String> str, int index) {
5782 i::Handle<i::String> istring =
5783 v8::Utils::OpenHandle(String::Cast(*str));
5784 return istring->Get(index);
5785}
5786
5787
5788static void WriteUtf8Helper(
5789 LocalContext& context,
5790 const char* name,
5791 const char* lengths_name,
5792 int len) {
5793 Local<v8::Array> b =
5794 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
5795 Local<v8::Array> alens =
5796 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
5797 char buffer[1000];
5798 char buffer2[1000];
5799 for (int i = 0; i < len; i++) {
5800 Local<v8::String> string =
5801 Local<v8::String>::Cast(b->Get(i));
5802 Local<v8::Number> expected_len =
5803 Local<v8::Number>::Cast(alens->Get(i));
5804 int utf8_length = static_cast<int>(expected_len->Value());
5805 for (int j = utf8_length + 1; j >= 0; j--) {
5806 memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
5807 memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
5808 int nchars;
5809 int utf8_written =
5810 string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
5811 int utf8_written2 =
5812 string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
5813 CHECK_GE(utf8_length + 1, utf8_written);
5814 CHECK_GE(utf8_length, utf8_written2);
5815 for (int k = 0; k < utf8_written2; k++) {
5816 CHECK_EQ(buffer[k], buffer2[k]);
5817 }
5818 CHECK(nchars * 3 >= utf8_written - 1);
5819 CHECK(nchars <= utf8_written);
5820 if (j == utf8_length + 1) {
5821 CHECK_EQ(utf8_written2, utf8_length);
5822 CHECK_EQ(utf8_written2 + 1, utf8_written);
5823 }
5824 CHECK_EQ(buffer[utf8_written], 42);
5825 if (j > utf8_length) {
5826 if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
5827 if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
5828 Handle<String> roundtrip = v8_str(buffer);
5829 CHECK(roundtrip->Equals(string));
5830 } else {
5831 if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
5832 }
5833 if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
5834 if (nchars >= 2) {
5835 uint16_t trail = StringGet(string, nchars - 1);
5836 uint16_t lead = StringGet(string, nchars - 2);
5837 if (((lead & 0xfc00) == 0xd800) &&
5838 ((trail & 0xfc00) == 0xdc00)) {
5839 unsigned char u1 = buffer2[utf8_written2 - 4];
5840 unsigned char u2 = buffer2[utf8_written2 - 3];
5841 unsigned char u3 = buffer2[utf8_written2 - 2];
5842 unsigned char u4 = buffer2[utf8_written2 - 1];
5843 CHECK_EQ((u1 & 0xf8), 0xf0);
5844 CHECK_EQ((u2 & 0xc0), 0x80);
5845 CHECK_EQ((u3 & 0xc0), 0x80);
5846 CHECK_EQ((u4 & 0xc0), 0x80);
5847 uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
5848 CHECK_EQ((u4 & 0x3f), (c & 0x3f));
5849 CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
5850 CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
5851 CHECK_EQ((u1 & 0x3), c >> 18);
5852 }
5853 }
5854 }
5855 }
5856}
5857
5858
5859THREADED_TEST(Utf16) {
5860 LocalContext context;
5861 v8::HandleScope scope;
5862 CompileRun(
5863 "var pad = '01234567890123456789';"
5864 "var p = [];"
5865 "var plens = [20, 3, 3];"
5866 "p.push('01234567890123456789');"
5867 "var lead = 0xd800;"
5868 "var trail = 0xdc00;"
5869 "p.push(String.fromCharCode(0xd800));"
5870 "p.push(String.fromCharCode(0xdc00));"
5871 "var a = [];"
5872 "var b = [];"
5873 "var c = [];"
5874 "var alens = [];"
5875 "for (var i = 0; i < 3; i++) {"
5876 " p[1] = String.fromCharCode(lead++);"
5877 " for (var j = 0; j < 3; j++) {"
5878 " p[2] = String.fromCharCode(trail++);"
5879 " a.push(p[i] + p[j]);"
5880 " b.push(p[i] + p[j]);"
5881 " c.push(p[i] + p[j]);"
5882 " alens.push(plens[i] + plens[j]);"
5883 " }"
5884 "}"
5885 "alens[5] -= 2;" // Here the surrogate pairs match up.
5886 "var a2 = [];"
5887 "var b2 = [];"
5888 "var c2 = [];"
5889 "var a2lens = [];"
5890 "for (var m = 0; m < 9; m++) {"
5891 " for (var n = 0; n < 9; n++) {"
5892 " a2.push(a[m] + a[n]);"
5893 " b2.push(b[m] + b[n]);"
5894 " var newc = 'x' + c[m] + c[n] + 'y';"
5895 " c2.push(newc.substring(1, newc.length - 1));"
5896 " var utf = alens[m] + alens[n];" // And here.
5897 // The 'n's that start with 0xdc.. are 6-8
5898 // The 'm's that end with 0xd8.. are 1, 4 and 7
5899 " if ((m % 3) == 1 && n >= 6) utf -= 2;"
5900 " a2lens.push(utf);"
5901 " }"
5902 "}");
5903 Utf16Helper(context, "a", "alens", 9);
5904 Utf16Helper(context, "a2", "a2lens", 81);
5905 WriteUtf8Helper(context, "b", "alens", 9);
5906 WriteUtf8Helper(context, "b2", "a2lens", 81);
5907 WriteUtf8Helper(context, "c2", "a2lens", 81);
5908}
5909
5910
5911static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
5912 i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
5913 i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
5914 return *is1 == *is2;
5915}
5916
5917
5918static void SameSymbolHelper(const char* a, const char* b) {
5919 Handle<String> symbol1 = v8::String::NewSymbol(a);
5920 Handle<String> symbol2 = v8::String::NewSymbol(b);
5921 CHECK(SameSymbol(symbol1, symbol2));
5922}
5923
5924
5925THREADED_TEST(Utf16Symbol) {
5926 LocalContext context;
5927 v8::HandleScope scope;
5928
5929 Handle<String> symbol1 = v8::String::NewSymbol("abc");
5930 Handle<String> symbol2 = v8::String::NewSymbol("abc");
5931 CHECK(SameSymbol(symbol1, symbol2));
5932
5933 SameSymbolHelper("\360\220\220\205", // 4 byte encoding.
5934 "\355\240\201\355\260\205"); // 2 3-byte surrogates.
5935 SameSymbolHelper("\355\240\201\355\260\206", // 2 3-byte surrogates.
5936 "\360\220\220\206"); // 4 byte encoding.
5937 SameSymbolHelper("x\360\220\220\205", // 4 byte encoding.
5938 "x\355\240\201\355\260\205"); // 2 3-byte surrogates.
5939 SameSymbolHelper("x\355\240\201\355\260\206", // 2 3-byte surrogates.
5940 "x\360\220\220\206"); // 4 byte encoding.
5941 CompileRun(
5942 "var sym0 = 'benedictus';"
5943 "var sym0b = 'S\303\270ren';"
5944 "var sym1 = '\355\240\201\355\260\207';"
5945 "var sym2 = '\360\220\220\210';"
5946 "var sym3 = 'x\355\240\201\355\260\207';"
5947 "var sym4 = 'x\360\220\220\210';"
5948 "if (sym1.length != 2) throw sym1;"
5949 "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
5950 "if (sym2.length != 2) throw sym2;"
5951 "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
5952 "if (sym3.length != 3) throw sym3;"
5953 "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
5954 "if (sym4.length != 3) throw sym4;"
5955 "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
5956 Handle<String> sym0 = v8::String::NewSymbol("benedictus");
5957 Handle<String> sym0b = v8::String::NewSymbol("S\303\270ren");
5958 Handle<String> sym1 = v8::String::NewSymbol("\355\240\201\355\260\207");
5959 Handle<String> sym2 = v8::String::NewSymbol("\360\220\220\210");
5960 Handle<String> sym3 = v8::String::NewSymbol("x\355\240\201\355\260\207");
5961 Handle<String> sym4 = v8::String::NewSymbol("x\360\220\220\210");
5962 v8::Local<v8::Object> global = context->Global();
5963 Local<Value> s0 = global->Get(v8_str("sym0"));
5964 Local<Value> s0b = global->Get(v8_str("sym0b"));
5965 Local<Value> s1 = global->Get(v8_str("sym1"));
5966 Local<Value> s2 = global->Get(v8_str("sym2"));
5967 Local<Value> s3 = global->Get(v8_str("sym3"));
5968 Local<Value> s4 = global->Get(v8_str("sym4"));
5969 CHECK(SameSymbol(sym0, Handle<String>(String::Cast(*s0))));
5970 CHECK(SameSymbol(sym0b, Handle<String>(String::Cast(*s0b))));
5971 CHECK(SameSymbol(sym1, Handle<String>(String::Cast(*s1))));
5972 CHECK(SameSymbol(sym2, Handle<String>(String::Cast(*s2))));
5973 CHECK(SameSymbol(sym3, Handle<String>(String::Cast(*s3))));
5974 CHECK(SameSymbol(sym4, Handle<String>(String::Cast(*s4))));
5975}
5976
5977
Steve Blocka7e24c12009-10-30 11:49:00 +00005978THREADED_TEST(ToArrayIndex) {
5979 v8::HandleScope scope;
5980 LocalContext context;
5981
5982 v8::Handle<String> str = v8_str("42");
5983 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
5984 CHECK(!index.IsEmpty());
5985 CHECK_EQ(42.0, index->Uint32Value());
5986 str = v8_str("42asdf");
5987 index = str->ToArrayIndex();
5988 CHECK(index.IsEmpty());
5989 str = v8_str("-42");
5990 index = str->ToArrayIndex();
5991 CHECK(index.IsEmpty());
5992 str = v8_str("4294967295");
5993 index = str->ToArrayIndex();
5994 CHECK(!index.IsEmpty());
5995 CHECK_EQ(4294967295.0, index->Uint32Value());
5996 v8::Handle<v8::Number> num = v8::Number::New(1);
5997 index = num->ToArrayIndex();
5998 CHECK(!index.IsEmpty());
5999 CHECK_EQ(1.0, index->Uint32Value());
6000 num = v8::Number::New(-1);
6001 index = num->ToArrayIndex();
6002 CHECK(index.IsEmpty());
6003 v8::Handle<v8::Object> obj = v8::Object::New();
6004 index = obj->ToArrayIndex();
6005 CHECK(index.IsEmpty());
6006}
6007
6008
6009THREADED_TEST(ErrorConstruction) {
6010 v8::HandleScope scope;
6011 LocalContext context;
6012
6013 v8::Handle<String> foo = v8_str("foo");
6014 v8::Handle<String> message = v8_str("message");
6015 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
6016 CHECK(range_error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01006017 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00006018 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
6019 CHECK(reference_error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01006020 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00006021 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
6022 CHECK(syntax_error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01006023 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00006024 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
6025 CHECK(type_error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01006026 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00006027 v8::Handle<Value> error = v8::Exception::Error(foo);
6028 CHECK(error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01006029 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00006030}
6031
6032
6033static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
6034 ApiTestFuzzer::Fuzz();
6035 return v8_num(10);
6036}
6037
6038
6039static void YSetter(Local<String> name,
6040 Local<Value> value,
6041 const AccessorInfo& info) {
6042 if (info.This()->Has(name)) {
6043 info.This()->Delete(name);
6044 }
6045 info.This()->Set(name, value);
6046}
6047
6048
6049THREADED_TEST(DeleteAccessor) {
6050 v8::HandleScope scope;
6051 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
6052 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
6053 LocalContext context;
6054 v8::Handle<v8::Object> holder = obj->NewInstance();
6055 context->Global()->Set(v8_str("holder"), holder);
6056 v8::Handle<Value> result = CompileRun(
6057 "holder.y = 11; holder.y = 12; holder.y");
6058 CHECK_EQ(12, result->Uint32Value());
6059}
6060
6061
6062THREADED_TEST(TypeSwitch) {
6063 v8::HandleScope scope;
6064 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
6065 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
6066 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
6067 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
6068 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
6069 LocalContext context;
6070 v8::Handle<v8::Object> obj0 = v8::Object::New();
6071 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
6072 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
6073 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
6074 for (int i = 0; i < 10; i++) {
6075 CHECK_EQ(0, type_switch->match(obj0));
6076 CHECK_EQ(1, type_switch->match(obj1));
6077 CHECK_EQ(2, type_switch->match(obj2));
6078 CHECK_EQ(3, type_switch->match(obj3));
6079 CHECK_EQ(3, type_switch->match(obj3));
6080 CHECK_EQ(2, type_switch->match(obj2));
6081 CHECK_EQ(1, type_switch->match(obj1));
6082 CHECK_EQ(0, type_switch->match(obj0));
6083 }
6084}
6085
6086
6087// For use within the TestSecurityHandler() test.
6088static bool g_security_callback_result = false;
6089static bool NamedSecurityTestCallback(Local<v8::Object> global,
6090 Local<Value> name,
6091 v8::AccessType type,
6092 Local<Value> data) {
6093 // Always allow read access.
6094 if (type == v8::ACCESS_GET)
6095 return true;
6096
6097 // Sometimes allow other access.
6098 return g_security_callback_result;
6099}
6100
6101
6102static bool IndexedSecurityTestCallback(Local<v8::Object> global,
6103 uint32_t key,
6104 v8::AccessType type,
6105 Local<Value> data) {
6106 // Always allow read access.
6107 if (type == v8::ACCESS_GET)
6108 return true;
6109
6110 // Sometimes allow other access.
6111 return g_security_callback_result;
6112}
6113
6114
6115static int trouble_nesting = 0;
6116static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
6117 ApiTestFuzzer::Fuzz();
6118 trouble_nesting++;
6119
6120 // Call a JS function that throws an uncaught exception.
6121 Local<v8::Object> arg_this = Context::GetCurrent()->Global();
6122 Local<Value> trouble_callee = (trouble_nesting == 3) ?
6123 arg_this->Get(v8_str("trouble_callee")) :
6124 arg_this->Get(v8_str("trouble_caller"));
6125 CHECK(trouble_callee->IsFunction());
6126 return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
6127}
6128
6129
6130static int report_count = 0;
6131static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
6132 v8::Handle<Value>) {
6133 report_count++;
6134}
6135
6136
6137// Counts uncaught exceptions, but other tests running in parallel
6138// also have uncaught exceptions.
6139TEST(ApiUncaughtException) {
6140 report_count = 0;
6141 v8::HandleScope scope;
6142 LocalContext env;
6143 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
6144
6145 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
6146 v8::Local<v8::Object> global = env->Global();
6147 global->Set(v8_str("trouble"), fun->GetFunction());
6148
6149 Script::Compile(v8_str("function trouble_callee() {"
6150 " var x = null;"
6151 " return x.foo;"
6152 "};"
6153 "function trouble_caller() {"
6154 " trouble();"
6155 "};"))->Run();
6156 Local<Value> trouble = global->Get(v8_str("trouble"));
6157 CHECK(trouble->IsFunction());
6158 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
6159 CHECK(trouble_callee->IsFunction());
6160 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
6161 CHECK(trouble_caller->IsFunction());
6162 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
6163 CHECK_EQ(1, report_count);
6164 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
6165}
6166
Leon Clarke4515c472010-02-03 11:58:03 +00006167static const char* script_resource_name = "ExceptionInNativeScript.js";
6168static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
6169 v8::Handle<Value>) {
6170 v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
6171 CHECK(!name_val.IsEmpty() && name_val->IsString());
6172 v8::String::AsciiValue name(message->GetScriptResourceName());
6173 CHECK_EQ(script_resource_name, *name);
6174 CHECK_EQ(3, message->GetLineNumber());
6175 v8::String::AsciiValue source_line(message->GetSourceLine());
6176 CHECK_EQ(" new o.foo();", *source_line);
6177}
6178
6179TEST(ExceptionInNativeScript) {
6180 v8::HandleScope scope;
6181 LocalContext env;
6182 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
6183
6184 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
6185 v8::Local<v8::Object> global = env->Global();
6186 global->Set(v8_str("trouble"), fun->GetFunction());
6187
6188 Script::Compile(v8_str("function trouble() {\n"
6189 " var o = {};\n"
6190 " new o.foo();\n"
6191 "};"), v8::String::New(script_resource_name))->Run();
6192 Local<Value> trouble = global->Get(v8_str("trouble"));
6193 CHECK(trouble->IsFunction());
6194 Function::Cast(*trouble)->Call(global, 0, NULL);
6195 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
6196}
6197
Steve Blocka7e24c12009-10-30 11:49:00 +00006198
6199TEST(CompilationErrorUsingTryCatchHandler) {
6200 v8::HandleScope scope;
6201 LocalContext env;
6202 v8::TryCatch try_catch;
6203 Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
6204 CHECK_NE(NULL, *try_catch.Exception());
6205 CHECK(try_catch.HasCaught());
6206}
6207
6208
6209TEST(TryCatchFinallyUsingTryCatchHandler) {
6210 v8::HandleScope scope;
6211 LocalContext env;
6212 v8::TryCatch try_catch;
6213 Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
6214 CHECK(!try_catch.HasCaught());
6215 Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
6216 CHECK(try_catch.HasCaught());
6217 try_catch.Reset();
6218 Script::Compile(v8_str("(function() {"
6219 "try { throw ''; } finally { return; }"
6220 "})()"))->Run();
6221 CHECK(!try_catch.HasCaught());
6222 Script::Compile(v8_str("(function()"
6223 " { try { throw ''; } finally { throw 0; }"
6224 "})()"))->Run();
6225 CHECK(try_catch.HasCaught());
6226}
6227
6228
6229// SecurityHandler can't be run twice
6230TEST(SecurityHandler) {
6231 v8::HandleScope scope0;
6232 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
6233 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
6234 IndexedSecurityTestCallback);
6235 // Create an environment
6236 v8::Persistent<Context> context0 =
6237 Context::New(NULL, global_template);
6238 context0->Enter();
6239
6240 v8::Handle<v8::Object> global0 = context0->Global();
6241 v8::Handle<Script> script0 = v8_compile("foo = 111");
6242 script0->Run();
6243 global0->Set(v8_str("0"), v8_num(999));
6244 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
6245 CHECK_EQ(111, foo0->Int32Value());
6246 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
6247 CHECK_EQ(999, z0->Int32Value());
6248
6249 // Create another environment, should fail security checks.
6250 v8::HandleScope scope1;
6251
6252 v8::Persistent<Context> context1 =
6253 Context::New(NULL, global_template);
6254 context1->Enter();
6255
6256 v8::Handle<v8::Object> global1 = context1->Global();
6257 global1->Set(v8_str("othercontext"), global0);
6258 // This set will fail the security check.
6259 v8::Handle<Script> script1 =
6260 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
6261 script1->Run();
6262 // This read will pass the security check.
6263 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
6264 CHECK_EQ(111, foo1->Int32Value());
6265 // This read will pass the security check.
6266 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
6267 CHECK_EQ(999, z1->Int32Value());
6268
6269 // Create another environment, should pass security checks.
6270 { g_security_callback_result = true; // allow security handler to pass.
6271 v8::HandleScope scope2;
6272 LocalContext context2;
6273 v8::Handle<v8::Object> global2 = context2->Global();
6274 global2->Set(v8_str("othercontext"), global0);
6275 v8::Handle<Script> script2 =
6276 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
6277 script2->Run();
6278 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
6279 CHECK_EQ(333, foo2->Int32Value());
6280 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
6281 CHECK_EQ(888, z2->Int32Value());
6282 }
6283
6284 context1->Exit();
6285 context1.Dispose();
6286
6287 context0->Exit();
6288 context0.Dispose();
6289}
6290
6291
6292THREADED_TEST(SecurityChecks) {
6293 v8::HandleScope handle_scope;
6294 LocalContext env1;
6295 v8::Persistent<Context> env2 = Context::New();
6296
6297 Local<Value> foo = v8_str("foo");
6298 Local<Value> bar = v8_str("bar");
6299
6300 // Set to the same domain.
6301 env1->SetSecurityToken(foo);
6302
6303 // Create a function in env1.
6304 Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
6305 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
6306 CHECK(spy->IsFunction());
6307
6308 // Create another function accessing global objects.
6309 Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
6310 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
6311 CHECK(spy2->IsFunction());
6312
6313 // Switch to env2 in the same domain and invoke spy on env2.
6314 {
6315 env2->SetSecurityToken(foo);
6316 // Enter env2
6317 Context::Scope scope_env2(env2);
6318 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
6319 CHECK(result->IsFunction());
6320 }
6321
6322 {
6323 env2->SetSecurityToken(bar);
6324 Context::Scope scope_env2(env2);
6325
6326 // Call cross_domain_call, it should throw an exception
6327 v8::TryCatch try_catch;
6328 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
6329 CHECK(try_catch.HasCaught());
6330 }
6331
6332 env2.Dispose();
6333}
6334
6335
6336// Regression test case for issue 1183439.
6337THREADED_TEST(SecurityChecksForPrototypeChain) {
6338 v8::HandleScope scope;
6339 LocalContext current;
6340 v8::Persistent<Context> other = Context::New();
6341
6342 // Change context to be able to get to the Object function in the
6343 // other context without hitting the security checks.
6344 v8::Local<Value> other_object;
6345 { Context::Scope scope(other);
6346 other_object = other->Global()->Get(v8_str("Object"));
6347 other->Global()->Set(v8_num(42), v8_num(87));
6348 }
6349
6350 current->Global()->Set(v8_str("other"), other->Global());
6351 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
6352
6353 // Make sure the security check fails here and we get an undefined
6354 // result instead of getting the Object function. Repeat in a loop
6355 // to make sure to exercise the IC code.
6356 v8::Local<Script> access_other0 = v8_compile("other.Object");
6357 v8::Local<Script> access_other1 = v8_compile("other[42]");
6358 for (int i = 0; i < 5; i++) {
6359 CHECK(!access_other0->Run()->Equals(other_object));
6360 CHECK(access_other0->Run()->IsUndefined());
6361 CHECK(!access_other1->Run()->Equals(v8_num(87)));
6362 CHECK(access_other1->Run()->IsUndefined());
6363 }
6364
6365 // Create an object that has 'other' in its prototype chain and make
6366 // sure we cannot access the Object function indirectly through
6367 // that. Repeat in a loop to make sure to exercise the IC code.
6368 v8_compile("function F() { };"
6369 "F.prototype = other;"
6370 "var f = new F();")->Run();
6371 v8::Local<Script> access_f0 = v8_compile("f.Object");
6372 v8::Local<Script> access_f1 = v8_compile("f[42]");
6373 for (int j = 0; j < 5; j++) {
6374 CHECK(!access_f0->Run()->Equals(other_object));
6375 CHECK(access_f0->Run()->IsUndefined());
6376 CHECK(!access_f1->Run()->Equals(v8_num(87)));
6377 CHECK(access_f1->Run()->IsUndefined());
6378 }
6379
6380 // Now it gets hairy: Set the prototype for the other global object
6381 // to be the current global object. The prototype chain for 'f' now
6382 // goes through 'other' but ends up in the current global object.
6383 { Context::Scope scope(other);
6384 other->Global()->Set(v8_str("__proto__"), current->Global());
6385 }
6386 // Set a named and an index property on the current global
6387 // object. To force the lookup to go through the other global object,
6388 // the properties must not exist in the other global object.
6389 current->Global()->Set(v8_str("foo"), v8_num(100));
6390 current->Global()->Set(v8_num(99), v8_num(101));
6391 // Try to read the properties from f and make sure that the access
6392 // gets stopped by the security checks on the other global object.
6393 Local<Script> access_f2 = v8_compile("f.foo");
6394 Local<Script> access_f3 = v8_compile("f[99]");
6395 for (int k = 0; k < 5; k++) {
6396 CHECK(!access_f2->Run()->Equals(v8_num(100)));
6397 CHECK(access_f2->Run()->IsUndefined());
6398 CHECK(!access_f3->Run()->Equals(v8_num(101)));
6399 CHECK(access_f3->Run()->IsUndefined());
6400 }
6401 other.Dispose();
6402}
6403
6404
6405THREADED_TEST(CrossDomainDelete) {
6406 v8::HandleScope handle_scope;
6407 LocalContext env1;
6408 v8::Persistent<Context> env2 = Context::New();
6409
6410 Local<Value> foo = v8_str("foo");
6411 Local<Value> bar = v8_str("bar");
6412
6413 // Set to the same domain.
6414 env1->SetSecurityToken(foo);
6415 env2->SetSecurityToken(foo);
6416
6417 env1->Global()->Set(v8_str("prop"), v8_num(3));
6418 env2->Global()->Set(v8_str("env1"), env1->Global());
6419
6420 // Change env2 to a different domain and delete env1.prop.
6421 env2->SetSecurityToken(bar);
6422 {
6423 Context::Scope scope_env2(env2);
6424 Local<Value> result =
6425 Script::Compile(v8_str("delete env1.prop"))->Run();
6426 CHECK(result->IsFalse());
6427 }
6428
6429 // Check that env1.prop still exists.
6430 Local<Value> v = env1->Global()->Get(v8_str("prop"));
6431 CHECK(v->IsNumber());
6432 CHECK_EQ(3, v->Int32Value());
6433
6434 env2.Dispose();
6435}
6436
6437
6438THREADED_TEST(CrossDomainIsPropertyEnumerable) {
6439 v8::HandleScope handle_scope;
6440 LocalContext env1;
6441 v8::Persistent<Context> env2 = Context::New();
6442
6443 Local<Value> foo = v8_str("foo");
6444 Local<Value> bar = v8_str("bar");
6445
6446 // Set to the same domain.
6447 env1->SetSecurityToken(foo);
6448 env2->SetSecurityToken(foo);
6449
6450 env1->Global()->Set(v8_str("prop"), v8_num(3));
6451 env2->Global()->Set(v8_str("env1"), env1->Global());
6452
6453 // env1.prop is enumerable in env2.
6454 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
6455 {
6456 Context::Scope scope_env2(env2);
6457 Local<Value> result = Script::Compile(test)->Run();
6458 CHECK(result->IsTrue());
6459 }
6460
6461 // Change env2 to a different domain and test again.
6462 env2->SetSecurityToken(bar);
6463 {
6464 Context::Scope scope_env2(env2);
6465 Local<Value> result = Script::Compile(test)->Run();
6466 CHECK(result->IsFalse());
6467 }
6468
6469 env2.Dispose();
6470}
6471
6472
6473THREADED_TEST(CrossDomainForIn) {
6474 v8::HandleScope handle_scope;
6475 LocalContext env1;
6476 v8::Persistent<Context> env2 = Context::New();
6477
6478 Local<Value> foo = v8_str("foo");
6479 Local<Value> bar = v8_str("bar");
6480
6481 // Set to the same domain.
6482 env1->SetSecurityToken(foo);
6483 env2->SetSecurityToken(foo);
6484
6485 env1->Global()->Set(v8_str("prop"), v8_num(3));
6486 env2->Global()->Set(v8_str("env1"), env1->Global());
6487
6488 // Change env2 to a different domain and set env1's global object
6489 // as the __proto__ of an object in env2 and enumerate properties
6490 // in for-in. It shouldn't enumerate properties on env1's global
6491 // object.
6492 env2->SetSecurityToken(bar);
6493 {
6494 Context::Scope scope_env2(env2);
6495 Local<Value> result =
6496 CompileRun("(function(){var obj = {'__proto__':env1};"
6497 "for (var p in obj)"
6498 " if (p == 'prop') return false;"
6499 "return true;})()");
6500 CHECK(result->IsTrue());
6501 }
6502 env2.Dispose();
6503}
6504
6505
6506TEST(ContextDetachGlobal) {
6507 v8::HandleScope handle_scope;
6508 LocalContext env1;
6509 v8::Persistent<Context> env2 = Context::New();
6510
6511 Local<v8::Object> global1 = env1->Global();
6512
6513 Local<Value> foo = v8_str("foo");
6514
6515 // Set to the same domain.
6516 env1->SetSecurityToken(foo);
6517 env2->SetSecurityToken(foo);
6518
6519 // Enter env2
6520 env2->Enter();
6521
Andrei Popescu74b3c142010-03-29 12:03:09 +01006522 // Create a function in env2 and add a reference to it in env1.
Steve Blocka7e24c12009-10-30 11:49:00 +00006523 Local<v8::Object> global2 = env2->Global();
6524 global2->Set(v8_str("prop"), v8::Integer::New(1));
6525 CompileRun("function getProp() {return prop;}");
6526
6527 env1->Global()->Set(v8_str("getProp"),
6528 global2->Get(v8_str("getProp")));
6529
Andrei Popescu74b3c142010-03-29 12:03:09 +01006530 // Detach env2's global, and reuse the global object of env2
Steve Blocka7e24c12009-10-30 11:49:00 +00006531 env2->Exit();
6532 env2->DetachGlobal();
6533 // env2 has a new global object.
6534 CHECK(!env2->Global()->Equals(global2));
6535
6536 v8::Persistent<Context> env3 =
6537 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
6538 env3->SetSecurityToken(v8_str("bar"));
6539 env3->Enter();
6540
6541 Local<v8::Object> global3 = env3->Global();
6542 CHECK_EQ(global2, global3);
6543 CHECK(global3->Get(v8_str("prop"))->IsUndefined());
6544 CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
6545 global3->Set(v8_str("prop"), v8::Integer::New(-1));
6546 global3->Set(v8_str("prop2"), v8::Integer::New(2));
6547 env3->Exit();
6548
6549 // Call getProp in env1, and it should return the value 1
6550 {
6551 Local<Value> get_prop = global1->Get(v8_str("getProp"));
6552 CHECK(get_prop->IsFunction());
6553 v8::TryCatch try_catch;
6554 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
6555 CHECK(!try_catch.HasCaught());
6556 CHECK_EQ(1, r->Int32Value());
6557 }
6558
6559 // Check that env3 is not accessible from env1
6560 {
6561 Local<Value> r = global3->Get(v8_str("prop2"));
6562 CHECK(r->IsUndefined());
6563 }
6564
6565 env2.Dispose();
6566 env3.Dispose();
6567}
6568
6569
Andrei Popescu74b3c142010-03-29 12:03:09 +01006570TEST(DetachAndReattachGlobal) {
6571 v8::HandleScope scope;
6572 LocalContext env1;
6573
6574 // Create second environment.
6575 v8::Persistent<Context> env2 = Context::New();
6576
6577 Local<Value> foo = v8_str("foo");
6578
6579 // Set same security token for env1 and env2.
6580 env1->SetSecurityToken(foo);
6581 env2->SetSecurityToken(foo);
6582
6583 // Create a property on the global object in env2.
6584 {
6585 v8::Context::Scope scope(env2);
6586 env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
6587 }
6588
6589 // Create a reference to env2 global from env1 global.
6590 env1->Global()->Set(v8_str("other"), env2->Global());
6591
6592 // Check that we have access to other.p in env2 from env1.
6593 Local<Value> result = CompileRun("other.p");
6594 CHECK(result->IsInt32());
6595 CHECK_EQ(42, result->Int32Value());
6596
6597 // Hold on to global from env2 and detach global from env2.
6598 Local<v8::Object> global2 = env2->Global();
6599 env2->DetachGlobal();
6600
6601 // Check that the global has been detached. No other.p property can
6602 // be found.
6603 result = CompileRun("other.p");
6604 CHECK(result->IsUndefined());
6605
6606 // Reuse global2 for env3.
6607 v8::Persistent<Context> env3 =
6608 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
6609 CHECK_EQ(global2, env3->Global());
6610
6611 // Start by using the same security token for env3 as for env1 and env2.
6612 env3->SetSecurityToken(foo);
6613
6614 // Create a property on the global object in env3.
6615 {
6616 v8::Context::Scope scope(env3);
6617 env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
6618 }
6619
6620 // Check that other.p is now the property in env3 and that we have access.
6621 result = CompileRun("other.p");
6622 CHECK(result->IsInt32());
6623 CHECK_EQ(24, result->Int32Value());
6624
6625 // Change security token for env3 to something different from env1 and env2.
6626 env3->SetSecurityToken(v8_str("bar"));
6627
6628 // Check that we do not have access to other.p in env1. |other| is now
6629 // the global object for env3 which has a different security token,
6630 // so access should be blocked.
6631 result = CompileRun("other.p");
6632 CHECK(result->IsUndefined());
6633
6634 // Detach the global for env3 and reattach it to env2.
6635 env3->DetachGlobal();
6636 env2->ReattachGlobal(global2);
6637
6638 // Check that we have access to other.p again in env1. |other| is now
6639 // the global object for env2 which has the same security token as env1.
6640 result = CompileRun("other.p");
6641 CHECK(result->IsInt32());
6642 CHECK_EQ(42, result->Int32Value());
6643
6644 env2.Dispose();
6645 env3.Dispose();
6646}
6647
6648
Steve Block1e0659c2011-05-24 12:43:12 +01006649static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
Steve Blocka7e24c12009-10-30 11:49:00 +00006650static bool NamedAccessBlocker(Local<v8::Object> global,
6651 Local<Value> name,
6652 v8::AccessType type,
6653 Local<Value> data) {
Steve Block1e0659c2011-05-24 12:43:12 +01006654 return Context::GetCurrent()->Global()->Equals(global) ||
6655 allowed_access_type[type];
Steve Blocka7e24c12009-10-30 11:49:00 +00006656}
6657
6658
6659static bool IndexedAccessBlocker(Local<v8::Object> global,
6660 uint32_t key,
6661 v8::AccessType type,
6662 Local<Value> data) {
Steve Block1e0659c2011-05-24 12:43:12 +01006663 return Context::GetCurrent()->Global()->Equals(global) ||
6664 allowed_access_type[type];
Steve Blocka7e24c12009-10-30 11:49:00 +00006665}
6666
6667
6668static int g_echo_value = -1;
6669static v8::Handle<Value> EchoGetter(Local<String> name,
6670 const AccessorInfo& info) {
6671 return v8_num(g_echo_value);
6672}
6673
6674
6675static void EchoSetter(Local<String> name,
6676 Local<Value> value,
6677 const AccessorInfo&) {
6678 if (value->IsNumber())
6679 g_echo_value = value->Int32Value();
6680}
6681
6682
6683static v8::Handle<Value> UnreachableGetter(Local<String> name,
6684 const AccessorInfo& info) {
6685 CHECK(false); // This function should not be called..
6686 return v8::Undefined();
6687}
6688
6689
6690static void UnreachableSetter(Local<String>, Local<Value>,
6691 const AccessorInfo&) {
6692 CHECK(false); // This function should nto be called.
6693}
6694
6695
Steve Block1e0659c2011-05-24 12:43:12 +01006696TEST(AccessControl) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006697 v8::HandleScope handle_scope;
6698 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
6699
6700 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
6701 IndexedAccessBlocker);
6702
6703 // Add an accessor accessible by cross-domain JS code.
6704 global_template->SetAccessor(
6705 v8_str("accessible_prop"),
6706 EchoGetter, EchoSetter,
6707 v8::Handle<Value>(),
6708 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
6709
6710 // Add an accessor that is not accessible by cross-domain JS code.
6711 global_template->SetAccessor(v8_str("blocked_prop"),
6712 UnreachableGetter, UnreachableSetter,
6713 v8::Handle<Value>(),
6714 v8::DEFAULT);
6715
6716 // Create an environment
6717 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6718 context0->Enter();
6719
6720 v8::Handle<v8::Object> global0 = context0->Global();
6721
Steve Block1e0659c2011-05-24 12:43:12 +01006722 // Define a property with JS getter and setter.
6723 CompileRun(
6724 "function getter() { return 'getter'; };\n"
6725 "function setter() { return 'setter'; }\n"
6726 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
6727
6728 Local<Value> getter = global0->Get(v8_str("getter"));
6729 Local<Value> setter = global0->Get(v8_str("setter"));
6730
6731 // And define normal element.
6732 global0->Set(239, v8_str("239"));
6733
6734 // Define an element with JS getter and setter.
6735 CompileRun(
6736 "function el_getter() { return 'el_getter'; };\n"
6737 "function el_setter() { return 'el_setter'; };\n"
6738 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
6739
6740 Local<Value> el_getter = global0->Get(v8_str("el_getter"));
6741 Local<Value> el_setter = global0->Get(v8_str("el_setter"));
6742
Steve Blocka7e24c12009-10-30 11:49:00 +00006743 v8::HandleScope scope1;
6744
6745 v8::Persistent<Context> context1 = Context::New();
6746 context1->Enter();
6747
6748 v8::Handle<v8::Object> global1 = context1->Global();
6749 global1->Set(v8_str("other"), global0);
6750
Steve Block1e0659c2011-05-24 12:43:12 +01006751 // Access blocked property.
6752 CompileRun("other.blocked_prop = 1");
6753
6754 ExpectUndefined("other.blocked_prop");
6755 ExpectUndefined(
6756 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
6757 ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
6758
6759 // Enable ACCESS_HAS
6760 allowed_access_type[v8::ACCESS_HAS] = true;
6761 ExpectUndefined("other.blocked_prop");
6762 // ... and now we can get the descriptor...
6763 ExpectUndefined(
6764 "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
6765 // ... and enumerate the property.
6766 ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
6767 allowed_access_type[v8::ACCESS_HAS] = false;
6768
6769 // Access blocked element.
6770 CompileRun("other[239] = 1");
6771
6772 ExpectUndefined("other[239]");
6773 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
6774 ExpectFalse("propertyIsEnumerable.call(other, '239')");
6775
6776 // Enable ACCESS_HAS
6777 allowed_access_type[v8::ACCESS_HAS] = true;
6778 ExpectUndefined("other[239]");
6779 // ... and now we can get the descriptor...
6780 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
6781 // ... and enumerate the property.
6782 ExpectTrue("propertyIsEnumerable.call(other, '239')");
6783 allowed_access_type[v8::ACCESS_HAS] = false;
6784
6785 // Access a property with JS accessor.
6786 CompileRun("other.js_accessor_p = 2");
6787
6788 ExpectUndefined("other.js_accessor_p");
6789 ExpectUndefined(
6790 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
6791
6792 // Enable ACCESS_HAS.
6793 allowed_access_type[v8::ACCESS_HAS] = true;
6794 ExpectUndefined("other.js_accessor_p");
6795 ExpectUndefined(
6796 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
6797 ExpectUndefined(
6798 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
6799 ExpectUndefined(
6800 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6801 allowed_access_type[v8::ACCESS_HAS] = false;
6802
6803 // Enable both ACCESS_HAS and ACCESS_GET.
6804 allowed_access_type[v8::ACCESS_HAS] = true;
6805 allowed_access_type[v8::ACCESS_GET] = true;
6806
6807 ExpectString("other.js_accessor_p", "getter");
6808 ExpectObject(
6809 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
6810 ExpectUndefined(
6811 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
6812 ExpectUndefined(
6813 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6814
6815 allowed_access_type[v8::ACCESS_GET] = false;
6816 allowed_access_type[v8::ACCESS_HAS] = false;
6817
6818 // Enable both ACCESS_HAS and ACCESS_SET.
6819 allowed_access_type[v8::ACCESS_HAS] = true;
6820 allowed_access_type[v8::ACCESS_SET] = true;
6821
6822 ExpectUndefined("other.js_accessor_p");
6823 ExpectUndefined(
6824 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
6825 ExpectObject(
6826 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
6827 ExpectUndefined(
6828 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6829
6830 allowed_access_type[v8::ACCESS_SET] = false;
6831 allowed_access_type[v8::ACCESS_HAS] = false;
6832
6833 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
6834 allowed_access_type[v8::ACCESS_HAS] = true;
6835 allowed_access_type[v8::ACCESS_GET] = true;
6836 allowed_access_type[v8::ACCESS_SET] = true;
6837
6838 ExpectString("other.js_accessor_p", "getter");
6839 ExpectObject(
6840 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
6841 ExpectObject(
6842 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
6843 ExpectUndefined(
6844 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6845
6846 allowed_access_type[v8::ACCESS_SET] = false;
6847 allowed_access_type[v8::ACCESS_GET] = false;
6848 allowed_access_type[v8::ACCESS_HAS] = false;
6849
6850 // Access an element with JS accessor.
6851 CompileRun("other[42] = 2");
6852
6853 ExpectUndefined("other[42]");
6854 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
6855
6856 // Enable ACCESS_HAS.
6857 allowed_access_type[v8::ACCESS_HAS] = true;
6858 ExpectUndefined("other[42]");
6859 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
6860 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
6861 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6862 allowed_access_type[v8::ACCESS_HAS] = false;
6863
6864 // Enable both ACCESS_HAS and ACCESS_GET.
6865 allowed_access_type[v8::ACCESS_HAS] = true;
6866 allowed_access_type[v8::ACCESS_GET] = true;
6867
6868 ExpectString("other[42]", "el_getter");
6869 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
6870 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
6871 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6872
6873 allowed_access_type[v8::ACCESS_GET] = false;
6874 allowed_access_type[v8::ACCESS_HAS] = false;
6875
6876 // Enable both ACCESS_HAS and ACCESS_SET.
6877 allowed_access_type[v8::ACCESS_HAS] = true;
6878 allowed_access_type[v8::ACCESS_SET] = true;
6879
6880 ExpectUndefined("other[42]");
6881 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
6882 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
6883 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6884
6885 allowed_access_type[v8::ACCESS_SET] = false;
6886 allowed_access_type[v8::ACCESS_HAS] = false;
6887
6888 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
6889 allowed_access_type[v8::ACCESS_HAS] = true;
6890 allowed_access_type[v8::ACCESS_GET] = true;
6891 allowed_access_type[v8::ACCESS_SET] = true;
6892
6893 ExpectString("other[42]", "el_getter");
6894 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
6895 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
6896 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6897
6898 allowed_access_type[v8::ACCESS_SET] = false;
6899 allowed_access_type[v8::ACCESS_GET] = false;
6900 allowed_access_type[v8::ACCESS_HAS] = false;
6901
Steve Blocka7e24c12009-10-30 11:49:00 +00006902 v8::Handle<Value> value;
6903
Steve Blocka7e24c12009-10-30 11:49:00 +00006904 // Access accessible property
Steve Block1e0659c2011-05-24 12:43:12 +01006905 value = CompileRun("other.accessible_prop = 3");
Steve Blocka7e24c12009-10-30 11:49:00 +00006906 CHECK(value->IsNumber());
6907 CHECK_EQ(3, value->Int32Value());
Andrei Popescu31002712010-02-23 13:46:05 +00006908 CHECK_EQ(3, g_echo_value);
Steve Blocka7e24c12009-10-30 11:49:00 +00006909
Steve Block1e0659c2011-05-24 12:43:12 +01006910 value = CompileRun("other.accessible_prop");
Steve Blocka7e24c12009-10-30 11:49:00 +00006911 CHECK(value->IsNumber());
6912 CHECK_EQ(3, value->Int32Value());
6913
Steve Block1e0659c2011-05-24 12:43:12 +01006914 value = CompileRun(
6915 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
6916 CHECK(value->IsNumber());
6917 CHECK_EQ(3, value->Int32Value());
6918
6919 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
Steve Blocka7e24c12009-10-30 11:49:00 +00006920 CHECK(value->IsTrue());
6921
6922 // Enumeration doesn't enumerate accessors from inaccessible objects in
6923 // the prototype chain even if the accessors are in themselves accessible.
Steve Block1e0659c2011-05-24 12:43:12 +01006924 value =
Steve Blocka7e24c12009-10-30 11:49:00 +00006925 CompileRun("(function(){var obj = {'__proto__':other};"
6926 "for (var p in obj)"
6927 " if (p == 'accessible_prop' || p == 'blocked_prop') {"
6928 " return false;"
6929 " }"
6930 "return true;})()");
Steve Block1e0659c2011-05-24 12:43:12 +01006931 CHECK(value->IsTrue());
Steve Blocka7e24c12009-10-30 11:49:00 +00006932
6933 context1->Exit();
6934 context0->Exit();
6935 context1.Dispose();
6936 context0.Dispose();
6937}
6938
6939
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006940TEST(AccessControlES5) {
6941 v8::HandleScope handle_scope;
6942 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
6943
6944 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
6945 IndexedAccessBlocker);
6946
Steve Block44f0eee2011-05-26 01:26:41 +01006947 // Add accessible accessor.
6948 global_template->SetAccessor(
6949 v8_str("accessible_prop"),
6950 EchoGetter, EchoSetter,
6951 v8::Handle<Value>(),
6952 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
6953
6954
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006955 // Add an accessor that is not accessible by cross-domain JS code.
6956 global_template->SetAccessor(v8_str("blocked_prop"),
6957 UnreachableGetter, UnreachableSetter,
6958 v8::Handle<Value>(),
6959 v8::DEFAULT);
6960
6961 // Create an environment
6962 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6963 context0->Enter();
6964
6965 v8::Handle<v8::Object> global0 = context0->Global();
6966
6967 v8::Persistent<Context> context1 = Context::New();
6968 context1->Enter();
6969 v8::Handle<v8::Object> global1 = context1->Global();
6970 global1->Set(v8_str("other"), global0);
6971
6972 // Regression test for issue 1154.
6973 ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
6974
6975 ExpectUndefined("other.blocked_prop");
6976
6977 // Regression test for issue 1027.
6978 CompileRun("Object.defineProperty(\n"
6979 " other, 'blocked_prop', {configurable: false})");
6980 ExpectUndefined("other.blocked_prop");
6981 ExpectUndefined(
6982 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
6983
6984 // Regression test for issue 1171.
6985 ExpectTrue("Object.isExtensible(other)");
6986 CompileRun("Object.preventExtensions(other)");
6987 ExpectTrue("Object.isExtensible(other)");
6988
6989 // Object.seal and Object.freeze.
6990 CompileRun("Object.freeze(other)");
6991 ExpectTrue("Object.isExtensible(other)");
6992
6993 CompileRun("Object.seal(other)");
6994 ExpectTrue("Object.isExtensible(other)");
Steve Block44f0eee2011-05-26 01:26:41 +01006995
6996 // Regression test for issue 1250.
6997 // Make sure that we can set the accessible accessors value using normal
6998 // assignment.
6999 CompileRun("other.accessible_prop = 42");
7000 CHECK_EQ(42, g_echo_value);
7001
7002 v8::Handle<Value> value;
7003 // We follow Safari in ignoring assignments to host object accessors.
7004 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
7005 value = CompileRun("other.accessible_prop == 42");
7006 CHECK(value->IsTrue());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007007}
7008
7009
Leon Clarke4515c472010-02-03 11:58:03 +00007010static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
7011 Local<Value> name,
7012 v8::AccessType type,
7013 Local<Value> data) {
7014 return false;
7015}
7016
7017
7018static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
7019 uint32_t key,
7020 v8::AccessType type,
7021 Local<Value> data) {
7022 return false;
7023}
7024
7025
7026THREADED_TEST(AccessControlGetOwnPropertyNames) {
7027 v8::HandleScope handle_scope;
7028 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
7029
7030 obj_template->Set(v8_str("x"), v8::Integer::New(42));
7031 obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
7032 GetOwnPropertyNamesIndexedBlocker);
7033
7034 // Create an environment
7035 v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
7036 context0->Enter();
7037
7038 v8::Handle<v8::Object> global0 = context0->Global();
7039
7040 v8::HandleScope scope1;
7041
7042 v8::Persistent<Context> context1 = Context::New();
7043 context1->Enter();
7044
7045 v8::Handle<v8::Object> global1 = context1->Global();
7046 global1->Set(v8_str("other"), global0);
7047 global1->Set(v8_str("object"), obj_template->NewInstance());
7048
7049 v8::Handle<Value> value;
7050
7051 // Attempt to get the property names of the other global object and
7052 // of an object that requires access checks. Accessing the other
7053 // global object should be blocked by access checks on the global
7054 // proxy object. Accessing the object that requires access checks
7055 // is blocked by the access checks on the object itself.
7056 value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
7057 CHECK(value->IsTrue());
7058
7059 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
7060 CHECK(value->IsTrue());
7061
7062 context1->Exit();
7063 context0->Exit();
7064 context1.Dispose();
7065 context0.Dispose();
7066}
7067
7068
Steve Block8defd9f2010-07-08 12:39:36 +01007069static v8::Handle<v8::Array> NamedPropertyEnumerator(const AccessorInfo& info) {
7070 v8::Handle<v8::Array> result = v8::Array::New(1);
7071 result->Set(0, v8_str("x"));
7072 return result;
7073}
7074
7075
7076THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
7077 v8::HandleScope handle_scope;
7078 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
7079
7080 obj_template->Set(v8_str("x"), v8::Integer::New(42));
7081 obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
7082 NamedPropertyEnumerator);
7083
7084 LocalContext context;
7085 v8::Handle<v8::Object> global = context->Global();
7086 global->Set(v8_str("object"), obj_template->NewInstance());
7087
7088 v8::Handle<Value> value =
7089 CompileRun("Object.getOwnPropertyNames(object).join(',')");
7090 CHECK_EQ(v8_str("x"), value);
7091}
7092
7093
Steve Blocka7e24c12009-10-30 11:49:00 +00007094static v8::Handle<Value> ConstTenGetter(Local<String> name,
7095 const AccessorInfo& info) {
7096 return v8_num(10);
7097}
7098
7099
7100THREADED_TEST(CrossDomainAccessors) {
7101 v8::HandleScope handle_scope;
7102
7103 v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
7104
7105 v8::Handle<v8::ObjectTemplate> global_template =
7106 func_template->InstanceTemplate();
7107
7108 v8::Handle<v8::ObjectTemplate> proto_template =
7109 func_template->PrototypeTemplate();
7110
7111 // Add an accessor to proto that's accessible by cross-domain JS code.
7112 proto_template->SetAccessor(v8_str("accessible"),
7113 ConstTenGetter, 0,
7114 v8::Handle<Value>(),
7115 v8::ALL_CAN_READ);
7116
7117 // Add an accessor that is not accessible by cross-domain JS code.
7118 global_template->SetAccessor(v8_str("unreachable"),
7119 UnreachableGetter, 0,
7120 v8::Handle<Value>(),
7121 v8::DEFAULT);
7122
7123 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
7124 context0->Enter();
7125
7126 Local<v8::Object> global = context0->Global();
7127 // Add a normal property that shadows 'accessible'
7128 global->Set(v8_str("accessible"), v8_num(11));
7129
7130 // Enter a new context.
7131 v8::HandleScope scope1;
7132 v8::Persistent<Context> context1 = Context::New();
7133 context1->Enter();
7134
7135 v8::Handle<v8::Object> global1 = context1->Global();
7136 global1->Set(v8_str("other"), global);
7137
7138 // Should return 10, instead of 11
7139 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
7140 CHECK(value->IsNumber());
7141 CHECK_EQ(10, value->Int32Value());
7142
7143 value = v8_compile("other.unreachable")->Run();
7144 CHECK(value->IsUndefined());
7145
7146 context1->Exit();
7147 context0->Exit();
7148 context1.Dispose();
7149 context0.Dispose();
7150}
7151
7152
7153static int named_access_count = 0;
7154static int indexed_access_count = 0;
7155
7156static bool NamedAccessCounter(Local<v8::Object> global,
7157 Local<Value> name,
7158 v8::AccessType type,
7159 Local<Value> data) {
7160 named_access_count++;
7161 return true;
7162}
7163
7164
7165static bool IndexedAccessCounter(Local<v8::Object> global,
7166 uint32_t key,
7167 v8::AccessType type,
7168 Local<Value> data) {
7169 indexed_access_count++;
7170 return true;
7171}
7172
7173
7174// This one is too easily disturbed by other tests.
7175TEST(AccessControlIC) {
7176 named_access_count = 0;
7177 indexed_access_count = 0;
7178
7179 v8::HandleScope handle_scope;
7180
7181 // Create an environment.
7182 v8::Persistent<Context> context0 = Context::New();
7183 context0->Enter();
7184
7185 // Create an object that requires access-check functions to be
7186 // called for cross-domain access.
7187 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
7188 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
7189 IndexedAccessCounter);
7190 Local<v8::Object> object = object_template->NewInstance();
7191
7192 v8::HandleScope scope1;
7193
7194 // Create another environment.
7195 v8::Persistent<Context> context1 = Context::New();
7196 context1->Enter();
7197
7198 // Make easy access to the object from the other environment.
7199 v8::Handle<v8::Object> global1 = context1->Global();
7200 global1->Set(v8_str("obj"), object);
7201
7202 v8::Handle<Value> value;
7203
7204 // Check that the named access-control function is called every time.
7205 CompileRun("function testProp(obj) {"
7206 " for (var i = 0; i < 10; i++) obj.prop = 1;"
7207 " for (var j = 0; j < 10; j++) obj.prop;"
7208 " return obj.prop"
7209 "}");
7210 value = CompileRun("testProp(obj)");
7211 CHECK(value->IsNumber());
7212 CHECK_EQ(1, value->Int32Value());
7213 CHECK_EQ(21, named_access_count);
7214
7215 // Check that the named access-control function is called every time.
7216 CompileRun("var p = 'prop';"
7217 "function testKeyed(obj) {"
7218 " for (var i = 0; i < 10; i++) obj[p] = 1;"
7219 " for (var j = 0; j < 10; j++) obj[p];"
7220 " return obj[p];"
7221 "}");
7222 // Use obj which requires access checks. No inline caching is used
7223 // in that case.
7224 value = CompileRun("testKeyed(obj)");
7225 CHECK(value->IsNumber());
7226 CHECK_EQ(1, value->Int32Value());
7227 CHECK_EQ(42, named_access_count);
7228 // Force the inline caches into generic state and try again.
7229 CompileRun("testKeyed({ a: 0 })");
7230 CompileRun("testKeyed({ b: 0 })");
7231 value = CompileRun("testKeyed(obj)");
7232 CHECK(value->IsNumber());
7233 CHECK_EQ(1, value->Int32Value());
7234 CHECK_EQ(63, named_access_count);
7235
7236 // Check that the indexed access-control function is called every time.
7237 CompileRun("function testIndexed(obj) {"
7238 " for (var i = 0; i < 10; i++) obj[0] = 1;"
7239 " for (var j = 0; j < 10; j++) obj[0];"
7240 " return obj[0]"
7241 "}");
7242 value = CompileRun("testIndexed(obj)");
7243 CHECK(value->IsNumber());
7244 CHECK_EQ(1, value->Int32Value());
7245 CHECK_EQ(21, indexed_access_count);
7246 // Force the inline caches into generic state.
7247 CompileRun("testIndexed(new Array(1))");
7248 // Test that the indexed access check is called.
7249 value = CompileRun("testIndexed(obj)");
7250 CHECK(value->IsNumber());
7251 CHECK_EQ(1, value->Int32Value());
7252 CHECK_EQ(42, indexed_access_count);
7253
7254 // Check that the named access check is called when invoking
7255 // functions on an object that requires access checks.
7256 CompileRun("obj.f = function() {}");
7257 CompileRun("function testCallNormal(obj) {"
7258 " for (var i = 0; i < 10; i++) obj.f();"
7259 "}");
7260 CompileRun("testCallNormal(obj)");
7261 CHECK_EQ(74, named_access_count);
7262
7263 // Force obj into slow case.
7264 value = CompileRun("delete obj.prop");
7265 CHECK(value->BooleanValue());
7266 // Force inline caches into dictionary probing mode.
7267 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
7268 // Test that the named access check is called.
7269 value = CompileRun("testProp(obj);");
7270 CHECK(value->IsNumber());
7271 CHECK_EQ(1, value->Int32Value());
7272 CHECK_EQ(96, named_access_count);
7273
7274 // Force the call inline cache into dictionary probing mode.
7275 CompileRun("o.f = function() {}; testCallNormal(o)");
7276 // Test that the named access check is still called for each
7277 // invocation of the function.
7278 value = CompileRun("testCallNormal(obj)");
7279 CHECK_EQ(106, named_access_count);
7280
7281 context1->Exit();
7282 context0->Exit();
7283 context1.Dispose();
7284 context0.Dispose();
7285}
7286
7287
7288static bool NamedAccessFlatten(Local<v8::Object> global,
7289 Local<Value> name,
7290 v8::AccessType type,
7291 Local<Value> data) {
7292 char buf[100];
7293 int len;
7294
7295 CHECK(name->IsString());
7296
7297 memset(buf, 0x1, sizeof(buf));
Steve Block6ded16b2010-05-10 14:33:55 +01007298 len = name.As<String>()->WriteAscii(buf);
Steve Blocka7e24c12009-10-30 11:49:00 +00007299 CHECK_EQ(4, len);
7300
7301 uint16_t buf2[100];
7302
7303 memset(buf, 0x1, sizeof(buf));
Steve Block6ded16b2010-05-10 14:33:55 +01007304 len = name.As<String>()->Write(buf2);
Steve Blocka7e24c12009-10-30 11:49:00 +00007305 CHECK_EQ(4, len);
7306
7307 return true;
7308}
7309
7310
7311static bool IndexedAccessFlatten(Local<v8::Object> global,
7312 uint32_t key,
7313 v8::AccessType type,
7314 Local<Value> data) {
7315 return true;
7316}
7317
7318
7319// Regression test. In access checks, operations that may cause
7320// garbage collection are not allowed. It used to be the case that
7321// using the Write operation on a string could cause a garbage
7322// collection due to flattening of the string. This is no longer the
7323// case.
7324THREADED_TEST(AccessControlFlatten) {
7325 named_access_count = 0;
7326 indexed_access_count = 0;
7327
7328 v8::HandleScope handle_scope;
7329
7330 // Create an environment.
7331 v8::Persistent<Context> context0 = Context::New();
7332 context0->Enter();
7333
7334 // Create an object that requires access-check functions to be
7335 // called for cross-domain access.
7336 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
7337 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
7338 IndexedAccessFlatten);
7339 Local<v8::Object> object = object_template->NewInstance();
7340
7341 v8::HandleScope scope1;
7342
7343 // Create another environment.
7344 v8::Persistent<Context> context1 = Context::New();
7345 context1->Enter();
7346
7347 // Make easy access to the object from the other environment.
7348 v8::Handle<v8::Object> global1 = context1->Global();
7349 global1->Set(v8_str("obj"), object);
7350
7351 v8::Handle<Value> value;
7352
7353 value = v8_compile("var p = 'as' + 'df';")->Run();
7354 value = v8_compile("obj[p];")->Run();
7355
7356 context1->Exit();
7357 context0->Exit();
7358 context1.Dispose();
7359 context0.Dispose();
7360}
7361
7362
7363static v8::Handle<Value> AccessControlNamedGetter(
7364 Local<String>, const AccessorInfo&) {
7365 return v8::Integer::New(42);
7366}
7367
7368
7369static v8::Handle<Value> AccessControlNamedSetter(
7370 Local<String>, Local<Value> value, const AccessorInfo&) {
7371 return value;
7372}
7373
7374
7375static v8::Handle<Value> AccessControlIndexedGetter(
7376 uint32_t index,
7377 const AccessorInfo& info) {
7378 return v8_num(42);
7379}
7380
7381
7382static v8::Handle<Value> AccessControlIndexedSetter(
7383 uint32_t, Local<Value> value, const AccessorInfo&) {
7384 return value;
7385}
7386
7387
7388THREADED_TEST(AccessControlInterceptorIC) {
7389 named_access_count = 0;
7390 indexed_access_count = 0;
7391
7392 v8::HandleScope handle_scope;
7393
7394 // Create an environment.
7395 v8::Persistent<Context> context0 = Context::New();
7396 context0->Enter();
7397
7398 // Create an object that requires access-check functions to be
7399 // called for cross-domain access. The object also has interceptors
7400 // interceptor.
7401 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
7402 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
7403 IndexedAccessCounter);
7404 object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
7405 AccessControlNamedSetter);
7406 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
7407 AccessControlIndexedSetter);
7408 Local<v8::Object> object = object_template->NewInstance();
7409
7410 v8::HandleScope scope1;
7411
7412 // Create another environment.
7413 v8::Persistent<Context> context1 = Context::New();
7414 context1->Enter();
7415
7416 // Make easy access to the object from the other environment.
7417 v8::Handle<v8::Object> global1 = context1->Global();
7418 global1->Set(v8_str("obj"), object);
7419
7420 v8::Handle<Value> value;
7421
7422 // Check that the named access-control function is called every time
7423 // eventhough there is an interceptor on the object.
7424 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
7425 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
7426 "obj.x")->Run();
7427 CHECK(value->IsNumber());
7428 CHECK_EQ(42, value->Int32Value());
7429 CHECK_EQ(21, named_access_count);
7430
7431 value = v8_compile("var p = 'x';")->Run();
7432 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
7433 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
7434 "obj[p]")->Run();
7435 CHECK(value->IsNumber());
7436 CHECK_EQ(42, value->Int32Value());
7437 CHECK_EQ(42, named_access_count);
7438
7439 // Check that the indexed access-control function is called every
7440 // time eventhough there is an interceptor on the object.
7441 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
7442 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
7443 "obj[0]")->Run();
7444 CHECK(value->IsNumber());
7445 CHECK_EQ(42, value->Int32Value());
7446 CHECK_EQ(21, indexed_access_count);
7447
7448 context1->Exit();
7449 context0->Exit();
7450 context1.Dispose();
7451 context0.Dispose();
7452}
7453
7454
7455THREADED_TEST(Version) {
7456 v8::V8::GetVersion();
7457}
7458
7459
7460static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
7461 ApiTestFuzzer::Fuzz();
7462 return v8_num(12);
7463}
7464
7465
7466THREADED_TEST(InstanceProperties) {
7467 v8::HandleScope handle_scope;
7468 LocalContext context;
7469
7470 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7471 Local<ObjectTemplate> instance = t->InstanceTemplate();
7472
7473 instance->Set(v8_str("x"), v8_num(42));
7474 instance->Set(v8_str("f"),
7475 v8::FunctionTemplate::New(InstanceFunctionCallback));
7476
7477 Local<Value> o = t->GetFunction()->NewInstance();
7478
7479 context->Global()->Set(v8_str("i"), o);
7480 Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
7481 CHECK_EQ(42, value->Int32Value());
7482
7483 value = Script::Compile(v8_str("i.f()"))->Run();
7484 CHECK_EQ(12, value->Int32Value());
7485}
7486
7487
7488static v8::Handle<Value>
7489GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
7490 ApiTestFuzzer::Fuzz();
7491 return v8::Handle<Value>();
7492}
7493
7494
7495THREADED_TEST(GlobalObjectInstanceProperties) {
7496 v8::HandleScope handle_scope;
7497
7498 Local<Value> global_object;
7499
7500 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7501 t->InstanceTemplate()->SetNamedPropertyHandler(
7502 GlobalObjectInstancePropertiesGet);
7503 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7504 instance_template->Set(v8_str("x"), v8_num(42));
7505 instance_template->Set(v8_str("f"),
7506 v8::FunctionTemplate::New(InstanceFunctionCallback));
7507
Ben Murdochb0fe1622011-05-05 13:52:32 +01007508 // The script to check how Crankshaft compiles missing global function
7509 // invocations. function g is not defined and should throw on call.
7510 const char* script =
7511 "function wrapper(call) {"
7512 " var x = 0, y = 1;"
7513 " for (var i = 0; i < 1000; i++) {"
7514 " x += i * 100;"
7515 " y += i * 100;"
7516 " }"
7517 " if (call) g();"
7518 "}"
7519 "for (var i = 0; i < 17; i++) wrapper(false);"
7520 "var thrown = 0;"
7521 "try { wrapper(true); } catch (e) { thrown = 1; };"
7522 "thrown";
7523
Steve Blocka7e24c12009-10-30 11:49:00 +00007524 {
7525 LocalContext env(NULL, instance_template);
7526 // Hold on to the global object so it can be used again in another
7527 // environment initialization.
7528 global_object = env->Global();
7529
7530 Local<Value> value = Script::Compile(v8_str("x"))->Run();
7531 CHECK_EQ(42, value->Int32Value());
7532 value = Script::Compile(v8_str("f()"))->Run();
7533 CHECK_EQ(12, value->Int32Value());
Ben Murdochb0fe1622011-05-05 13:52:32 +01007534 value = Script::Compile(v8_str(script))->Run();
7535 CHECK_EQ(1, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00007536 }
7537
7538 {
7539 // Create new environment reusing the global object.
7540 LocalContext env(NULL, instance_template, global_object);
7541 Local<Value> value = Script::Compile(v8_str("x"))->Run();
7542 CHECK_EQ(42, value->Int32Value());
7543 value = Script::Compile(v8_str("f()"))->Run();
7544 CHECK_EQ(12, value->Int32Value());
Ben Murdochb0fe1622011-05-05 13:52:32 +01007545 value = Script::Compile(v8_str(script))->Run();
7546 CHECK_EQ(1, value->Int32Value());
7547 }
7548}
7549
7550
7551THREADED_TEST(CallKnownGlobalReceiver) {
7552 v8::HandleScope handle_scope;
7553
7554 Local<Value> global_object;
7555
7556 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7557 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7558
7559 // The script to check that we leave global object not
7560 // global object proxy on stack when we deoptimize from inside
7561 // arguments evaluation.
7562 // To provoke error we need to both force deoptimization
7563 // from arguments evaluation and to force CallIC to take
7564 // CallIC_Miss code path that can't cope with global proxy.
7565 const char* script =
7566 "function bar(x, y) { try { } finally { } }"
7567 "function baz(x) { try { } finally { } }"
7568 "function bom(x) { try { } finally { } }"
7569 "function foo(x) { bar([x], bom(2)); }"
7570 "for (var i = 0; i < 10000; i++) foo(1);"
7571 "foo";
7572
7573 Local<Value> foo;
7574 {
7575 LocalContext env(NULL, instance_template);
7576 // Hold on to the global object so it can be used again in another
7577 // environment initialization.
7578 global_object = env->Global();
7579 foo = Script::Compile(v8_str(script))->Run();
7580 }
7581
7582 {
7583 // Create new environment reusing the global object.
7584 LocalContext env(NULL, instance_template, global_object);
7585 env->Global()->Set(v8_str("foo"), foo);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007586 Script::Compile(v8_str("foo()"))->Run();
Steve Blocka7e24c12009-10-30 11:49:00 +00007587 }
7588}
7589
7590
7591static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
7592 ApiTestFuzzer::Fuzz();
7593 return v8_num(42);
7594}
7595
7596
7597static int shadow_y;
7598static int shadow_y_setter_call_count;
7599static int shadow_y_getter_call_count;
7600
7601
7602static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
7603 shadow_y_setter_call_count++;
7604 shadow_y = 42;
7605}
7606
7607
7608static v8::Handle<Value> ShadowYGetter(Local<String> name,
7609 const AccessorInfo& info) {
7610 ApiTestFuzzer::Fuzz();
7611 shadow_y_getter_call_count++;
7612 return v8_num(shadow_y);
7613}
7614
7615
7616static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
7617 const AccessorInfo& info) {
7618 return v8::Handle<Value>();
7619}
7620
7621
7622static v8::Handle<Value> ShadowNamedGet(Local<String> key,
7623 const AccessorInfo&) {
7624 return v8::Handle<Value>();
7625}
7626
7627
7628THREADED_TEST(ShadowObject) {
7629 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
7630 v8::HandleScope handle_scope;
7631
7632 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
7633 LocalContext context(NULL, global_template);
7634
7635 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7636 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
7637 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
7638 Local<ObjectTemplate> proto = t->PrototypeTemplate();
7639 Local<ObjectTemplate> instance = t->InstanceTemplate();
7640
7641 // Only allow calls of f on instances of t.
7642 Local<v8::Signature> signature = v8::Signature::New(t);
7643 proto->Set(v8_str("f"),
7644 v8::FunctionTemplate::New(ShadowFunctionCallback,
7645 Local<Value>(),
7646 signature));
7647 proto->Set(v8_str("x"), v8_num(12));
7648
7649 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
7650
7651 Local<Value> o = t->GetFunction()->NewInstance();
7652 context->Global()->Set(v8_str("__proto__"), o);
7653
7654 Local<Value> value =
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007655 Script::Compile(v8_str("this.propertyIsEnumerable(0)"))->Run();
Steve Blocka7e24c12009-10-30 11:49:00 +00007656 CHECK(value->IsBoolean());
7657 CHECK(!value->BooleanValue());
7658
7659 value = Script::Compile(v8_str("x"))->Run();
7660 CHECK_EQ(12, value->Int32Value());
7661
7662 value = Script::Compile(v8_str("f()"))->Run();
7663 CHECK_EQ(42, value->Int32Value());
7664
7665 Script::Compile(v8_str("y = 42"))->Run();
7666 CHECK_EQ(1, shadow_y_setter_call_count);
7667 value = Script::Compile(v8_str("y"))->Run();
7668 CHECK_EQ(1, shadow_y_getter_call_count);
7669 CHECK_EQ(42, value->Int32Value());
7670}
7671
7672
7673THREADED_TEST(HiddenPrototype) {
7674 v8::HandleScope handle_scope;
7675 LocalContext context;
7676
7677 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
7678 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
7679 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
7680 t1->SetHiddenPrototype(true);
7681 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
7682 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
7683 t2->SetHiddenPrototype(true);
7684 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
7685 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
7686 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
7687
7688 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
7689 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
7690 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
7691 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
7692
7693 // Setting the prototype on an object skips hidden prototypes.
7694 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7695 o0->Set(v8_str("__proto__"), o1);
7696 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7697 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7698 o0->Set(v8_str("__proto__"), o2);
7699 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7700 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7701 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7702 o0->Set(v8_str("__proto__"), o3);
7703 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7704 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7705 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7706 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
7707
7708 // Getting the prototype of o0 should get the first visible one
7709 // which is o3. Therefore, z should not be defined on the prototype
7710 // object.
7711 Local<Value> proto = o0->Get(v8_str("__proto__"));
7712 CHECK(proto->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01007713 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
Steve Blocka7e24c12009-10-30 11:49:00 +00007714}
7715
7716
Andrei Popescu402d9372010-02-26 13:31:12 +00007717THREADED_TEST(SetPrototype) {
7718 v8::HandleScope handle_scope;
7719 LocalContext context;
7720
7721 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
7722 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
7723 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
7724 t1->SetHiddenPrototype(true);
7725 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
7726 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
7727 t2->SetHiddenPrototype(true);
7728 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
7729 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
7730 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
7731
7732 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
7733 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
7734 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
7735 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
7736
7737 // Setting the prototype on an object does not skip hidden prototypes.
7738 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7739 CHECK(o0->SetPrototype(o1));
7740 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7741 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7742 CHECK(o1->SetPrototype(o2));
7743 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7744 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7745 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7746 CHECK(o2->SetPrototype(o3));
7747 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7748 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7749 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7750 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
7751
7752 // Getting the prototype of o0 should get the first visible one
7753 // which is o3. Therefore, z should not be defined on the prototype
7754 // object.
7755 Local<Value> proto = o0->Get(v8_str("__proto__"));
7756 CHECK(proto->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01007757 CHECK_EQ(proto.As<v8::Object>(), o3);
Andrei Popescu402d9372010-02-26 13:31:12 +00007758
7759 // However, Object::GetPrototype ignores hidden prototype.
7760 Local<Value> proto0 = o0->GetPrototype();
7761 CHECK(proto0->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01007762 CHECK_EQ(proto0.As<v8::Object>(), o1);
Andrei Popescu402d9372010-02-26 13:31:12 +00007763
7764 Local<Value> proto1 = o1->GetPrototype();
7765 CHECK(proto1->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01007766 CHECK_EQ(proto1.As<v8::Object>(), o2);
Andrei Popescu402d9372010-02-26 13:31:12 +00007767
7768 Local<Value> proto2 = o2->GetPrototype();
7769 CHECK(proto2->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01007770 CHECK_EQ(proto2.As<v8::Object>(), o3);
Andrei Popescu402d9372010-02-26 13:31:12 +00007771}
7772
7773
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007774// Getting property names of an object with a prototype chain that
7775// triggers dictionary elements in GetLocalPropertyNames() shouldn't
7776// crash the runtime.
7777THREADED_TEST(Regress91517) {
7778 i::FLAG_allow_natives_syntax = true;
7779 v8::HandleScope handle_scope;
7780 LocalContext context;
7781
7782 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
7783 t1->SetHiddenPrototype(true);
7784 t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
7785 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
7786 t2->SetHiddenPrototype(true);
7787 t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
7788 t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New());
7789 t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
7790 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
7791 t3->SetHiddenPrototype(true);
7792 t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
7793 Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New();
7794 t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
7795
7796 // Force dictionary-based properties.
7797 i::ScopedVector<char> name_buf(1024);
7798 for (int i = 1; i <= 1000; i++) {
7799 i::OS::SNPrintF(name_buf, "sdf%d", i);
7800 t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
7801 }
7802
7803 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
7804 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
7805 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
7806 Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
7807
7808 // Create prototype chain of hidden prototypes.
7809 CHECK(o4->SetPrototype(o3));
7810 CHECK(o3->SetPrototype(o2));
7811 CHECK(o2->SetPrototype(o1));
7812
7813 // Call the runtime version of GetLocalPropertyNames() on the natively
7814 // created object through JavaScript.
7815 context->Global()->Set(v8_str("obj"), o4);
7816 CompileRun("var names = %GetLocalPropertyNames(obj);");
7817
7818 ExpectInt32("names.length", 1006);
7819 ExpectTrue("names.indexOf(\"baz\") >= 0");
7820 ExpectTrue("names.indexOf(\"boo\") >= 0");
7821 ExpectTrue("names.indexOf(\"foo\") >= 0");
7822 ExpectTrue("names.indexOf(\"fuz1\") >= 0");
7823 ExpectTrue("names.indexOf(\"fuz2\") >= 0");
7824 ExpectFalse("names[1005] == undefined");
7825}
7826
7827
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007828THREADED_TEST(FunctionReadOnlyPrototype) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007829 v8::HandleScope handle_scope;
7830 LocalContext context;
7831
7832 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007833 t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
7834 t1->ReadOnlyPrototype();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007835 context->Global()->Set(v8_str("func1"), t1->GetFunction());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007836 // Configured value of ReadOnly flag.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007837 CHECK(CompileRun(
7838 "(function() {"
7839 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007840 " return (descriptor['writable'] == false);"
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007841 "})()")->BooleanValue());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007842 CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
7843 CHECK_EQ(42,
7844 CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007845
7846 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007847 t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007848 context->Global()->Set(v8_str("func2"), t2->GetFunction());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007849 // Default value of ReadOnly flag.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007850 CHECK(CompileRun(
7851 "(function() {"
7852 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007853 " return (descriptor['writable'] == true);"
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007854 "})()")->BooleanValue());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007855 CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007856}
7857
7858
Andrei Popescu402d9372010-02-26 13:31:12 +00007859THREADED_TEST(SetPrototypeThrows) {
7860 v8::HandleScope handle_scope;
7861 LocalContext context;
7862
7863 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7864
7865 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
7866 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
7867
7868 CHECK(o0->SetPrototype(o1));
7869 // If setting the prototype leads to the cycle, SetPrototype should
7870 // return false and keep VM in sane state.
7871 v8::TryCatch try_catch;
7872 CHECK(!o1->SetPrototype(o0));
7873 CHECK(!try_catch.HasCaught());
Steve Block44f0eee2011-05-26 01:26:41 +01007874 ASSERT(!i::Isolate::Current()->has_pending_exception());
Andrei Popescu402d9372010-02-26 13:31:12 +00007875
7876 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
7877}
7878
7879
Steve Blocka7e24c12009-10-30 11:49:00 +00007880THREADED_TEST(GetterSetterExceptions) {
7881 v8::HandleScope handle_scope;
7882 LocalContext context;
7883 CompileRun(
7884 "function Foo() { };"
7885 "function Throw() { throw 5; };"
7886 "var x = { };"
7887 "x.__defineSetter__('set', Throw);"
7888 "x.__defineGetter__('get', Throw);");
7889 Local<v8::Object> x =
7890 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
7891 v8::TryCatch try_catch;
7892 x->Set(v8_str("set"), v8::Integer::New(8));
7893 x->Get(v8_str("get"));
7894 x->Set(v8_str("set"), v8::Integer::New(8));
7895 x->Get(v8_str("get"));
7896 x->Set(v8_str("set"), v8::Integer::New(8));
7897 x->Get(v8_str("get"));
7898 x->Set(v8_str("set"), v8::Integer::New(8));
7899 x->Get(v8_str("get"));
7900}
7901
7902
7903THREADED_TEST(Constructor) {
7904 v8::HandleScope handle_scope;
7905 LocalContext context;
7906 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7907 templ->SetClassName(v8_str("Fun"));
7908 Local<Function> cons = templ->GetFunction();
7909 context->Global()->Set(v8_str("Fun"), cons);
7910 Local<v8::Object> inst = cons->NewInstance();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007911 i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
7912 CHECK(obj->IsJSObject());
Steve Blocka7e24c12009-10-30 11:49:00 +00007913 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
7914 CHECK(value->BooleanValue());
7915}
7916
Ben Murdoch257744e2011-11-30 15:57:28 +00007917
7918static Handle<Value> ConstructorCallback(const Arguments& args) {
7919 ApiTestFuzzer::Fuzz();
7920 Local<Object> This;
7921
7922 if (args.IsConstructCall()) {
7923 Local<Object> Holder = args.Holder();
7924 This = Object::New();
7925 Local<Value> proto = Holder->GetPrototype();
7926 if (proto->IsObject()) {
7927 This->SetPrototype(proto);
7928 }
7929 } else {
7930 This = args.This();
7931 }
7932
7933 This->Set(v8_str("a"), args[0]);
7934 return This;
7935}
7936
7937
7938static Handle<Value> FakeConstructorCallback(const Arguments& args) {
7939 ApiTestFuzzer::Fuzz();
7940 return args[0];
7941}
7942
7943
7944THREADED_TEST(ConstructorForObject) {
7945 v8::HandleScope handle_scope;
7946 LocalContext context;
7947
7948 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7949 instance_template->SetCallAsFunctionHandler(ConstructorCallback);
7950 Local<Object> instance = instance_template->NewInstance();
7951 context->Global()->Set(v8_str("obj"), instance);
7952 v8::TryCatch try_catch;
7953 Local<Value> value;
7954 CHECK(!try_catch.HasCaught());
7955
7956 // Call the Object's constructor with a 32-bit signed integer.
7957 value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
7958 CHECK(!try_catch.HasCaught());
7959 CHECK(value->IsInt32());
7960 CHECK_EQ(28, value->Int32Value());
7961
7962 Local<Value> args1[] = { v8_num(28) };
7963 Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
7964 CHECK(value_obj1->IsObject());
7965 Local<Object> object1 = Local<Object>::Cast(value_obj1);
7966 value = object1->Get(v8_str("a"));
7967 CHECK(value->IsInt32());
7968 CHECK(!try_catch.HasCaught());
7969 CHECK_EQ(28, value->Int32Value());
7970
7971 // Call the Object's constructor with a String.
7972 value = CompileRun(
7973 "(function() { var o = new obj('tipli'); return o.a; })()");
7974 CHECK(!try_catch.HasCaught());
7975 CHECK(value->IsString());
7976 String::AsciiValue string_value1(value->ToString());
7977 CHECK_EQ("tipli", *string_value1);
7978
7979 Local<Value> args2[] = { v8_str("tipli") };
7980 Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
7981 CHECK(value_obj2->IsObject());
7982 Local<Object> object2 = Local<Object>::Cast(value_obj2);
7983 value = object2->Get(v8_str("a"));
7984 CHECK(!try_catch.HasCaught());
7985 CHECK(value->IsString());
7986 String::AsciiValue string_value2(value->ToString());
7987 CHECK_EQ("tipli", *string_value2);
7988
7989 // Call the Object's constructor with a Boolean.
7990 value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
7991 CHECK(!try_catch.HasCaught());
7992 CHECK(value->IsBoolean());
7993 CHECK_EQ(true, value->BooleanValue());
7994
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007995 Handle<Value> args3[] = { v8::True() };
Ben Murdoch257744e2011-11-30 15:57:28 +00007996 Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
7997 CHECK(value_obj3->IsObject());
7998 Local<Object> object3 = Local<Object>::Cast(value_obj3);
7999 value = object3->Get(v8_str("a"));
8000 CHECK(!try_catch.HasCaught());
8001 CHECK(value->IsBoolean());
8002 CHECK_EQ(true, value->BooleanValue());
8003
8004 // Call the Object's constructor with undefined.
8005 Handle<Value> args4[] = { v8::Undefined() };
8006 Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
8007 CHECK(value_obj4->IsObject());
8008 Local<Object> object4 = Local<Object>::Cast(value_obj4);
8009 value = object4->Get(v8_str("a"));
8010 CHECK(!try_catch.HasCaught());
8011 CHECK(value->IsUndefined());
8012
8013 // Call the Object's constructor with null.
8014 Handle<Value> args5[] = { v8::Null() };
8015 Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
8016 CHECK(value_obj5->IsObject());
8017 Local<Object> object5 = Local<Object>::Cast(value_obj5);
8018 value = object5->Get(v8_str("a"));
8019 CHECK(!try_catch.HasCaught());
8020 CHECK(value->IsNull());
8021 }
8022
8023 // Check exception handling when there is no constructor set for the Object.
8024 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8025 Local<Object> instance = instance_template->NewInstance();
8026 context->Global()->Set(v8_str("obj2"), instance);
8027 v8::TryCatch try_catch;
8028 Local<Value> value;
8029 CHECK(!try_catch.HasCaught());
8030
8031 value = CompileRun("new obj2(28)");
8032 CHECK(try_catch.HasCaught());
8033 String::AsciiValue exception_value1(try_catch.Exception());
8034 CHECK_EQ("TypeError: object is not a function", *exception_value1);
8035 try_catch.Reset();
8036
8037 Local<Value> args[] = { v8_num(29) };
8038 value = instance->CallAsConstructor(1, args);
8039 CHECK(try_catch.HasCaught());
8040 String::AsciiValue exception_value2(try_catch.Exception());
8041 CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
8042 try_catch.Reset();
8043 }
8044
8045 // Check the case when constructor throws exception.
8046 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8047 instance_template->SetCallAsFunctionHandler(ThrowValue);
8048 Local<Object> instance = instance_template->NewInstance();
8049 context->Global()->Set(v8_str("obj3"), instance);
8050 v8::TryCatch try_catch;
8051 Local<Value> value;
8052 CHECK(!try_catch.HasCaught());
8053
8054 value = CompileRun("new obj3(22)");
8055 CHECK(try_catch.HasCaught());
8056 String::AsciiValue exception_value1(try_catch.Exception());
8057 CHECK_EQ("22", *exception_value1);
8058 try_catch.Reset();
8059
8060 Local<Value> args[] = { v8_num(23) };
8061 value = instance->CallAsConstructor(1, args);
8062 CHECK(try_catch.HasCaught());
8063 String::AsciiValue exception_value2(try_catch.Exception());
8064 CHECK_EQ("23", *exception_value2);
8065 try_catch.Reset();
8066 }
8067
8068 // Check whether constructor returns with an object or non-object.
8069 { Local<FunctionTemplate> function_template =
8070 FunctionTemplate::New(FakeConstructorCallback);
8071 Local<Function> function = function_template->GetFunction();
8072 Local<Object> instance1 = function;
8073 context->Global()->Set(v8_str("obj4"), instance1);
8074 v8::TryCatch try_catch;
8075 Local<Value> value;
8076 CHECK(!try_catch.HasCaught());
8077
8078 CHECK(instance1->IsObject());
8079 CHECK(instance1->IsFunction());
8080
8081 value = CompileRun("new obj4(28)");
8082 CHECK(!try_catch.HasCaught());
8083 CHECK(value->IsObject());
8084
8085 Local<Value> args1[] = { v8_num(28) };
8086 value = instance1->CallAsConstructor(1, args1);
8087 CHECK(!try_catch.HasCaught());
8088 CHECK(value->IsObject());
8089
8090 Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8091 instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
8092 Local<Object> instance2 = instance_template->NewInstance();
8093 context->Global()->Set(v8_str("obj5"), instance2);
8094 CHECK(!try_catch.HasCaught());
8095
8096 CHECK(instance2->IsObject());
8097 CHECK(!instance2->IsFunction());
8098
8099 value = CompileRun("new obj5(28)");
8100 CHECK(!try_catch.HasCaught());
8101 CHECK(!value->IsObject());
8102
8103 Local<Value> args2[] = { v8_num(28) };
8104 value = instance2->CallAsConstructor(1, args2);
8105 CHECK(!try_catch.HasCaught());
8106 CHECK(!value->IsObject());
8107 }
8108}
8109
8110
Steve Blocka7e24c12009-10-30 11:49:00 +00008111THREADED_TEST(FunctionDescriptorException) {
8112 v8::HandleScope handle_scope;
8113 LocalContext context;
8114 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
8115 templ->SetClassName(v8_str("Fun"));
8116 Local<Function> cons = templ->GetFunction();
8117 context->Global()->Set(v8_str("Fun"), cons);
8118 Local<Value> value = CompileRun(
8119 "function test() {"
8120 " try {"
8121 " (new Fun()).blah()"
8122 " } catch (e) {"
8123 " var str = String(e);"
8124 " if (str.indexOf('TypeError') == -1) return 1;"
8125 " if (str.indexOf('[object Fun]') != -1) return 2;"
Steve Block1e0659c2011-05-24 12:43:12 +01008126 " if (str.indexOf('#<Fun>') == -1) return 3;"
Steve Blocka7e24c12009-10-30 11:49:00 +00008127 " return 0;"
8128 " }"
8129 " return 4;"
8130 "}"
8131 "test();");
8132 CHECK_EQ(0, value->Int32Value());
8133}
8134
8135
8136THREADED_TEST(EvalAliasedDynamic) {
8137 v8::HandleScope scope;
8138 LocalContext current;
8139
8140 // Tests where aliased eval can only be resolved dynamically.
8141 Local<Script> script =
8142 Script::Compile(v8_str("function f(x) { "
8143 " var foo = 2;"
8144 " with (x) { return eval('foo'); }"
8145 "}"
8146 "foo = 0;"
8147 "result1 = f(new Object());"
8148 "result2 = f(this);"
8149 "var x = new Object();"
8150 "x.eval = function(x) { return 1; };"
8151 "result3 = f(x);"));
8152 script->Run();
8153 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
8154 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
8155 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
8156
8157 v8::TryCatch try_catch;
8158 script =
8159 Script::Compile(v8_str("function f(x) { "
8160 " var bar = 2;"
8161 " with (x) { return eval('bar'); }"
8162 "}"
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008163 "result4 = f(this)"));
Steve Blocka7e24c12009-10-30 11:49:00 +00008164 script->Run();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008165 CHECK(!try_catch.HasCaught());
8166 CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
8167
Steve Blocka7e24c12009-10-30 11:49:00 +00008168 try_catch.Reset();
8169}
8170
8171
8172THREADED_TEST(CrossEval) {
8173 v8::HandleScope scope;
8174 LocalContext other;
8175 LocalContext current;
8176
8177 Local<String> token = v8_str("<security token>");
8178 other->SetSecurityToken(token);
8179 current->SetSecurityToken(token);
8180
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008181 // Set up reference from current to other.
Steve Blocka7e24c12009-10-30 11:49:00 +00008182 current->Global()->Set(v8_str("other"), other->Global());
8183
8184 // Check that new variables are introduced in other context.
8185 Local<Script> script =
8186 Script::Compile(v8_str("other.eval('var foo = 1234')"));
8187 script->Run();
8188 Local<Value> foo = other->Global()->Get(v8_str("foo"));
8189 CHECK_EQ(1234, foo->Int32Value());
8190 CHECK(!current->Global()->Has(v8_str("foo")));
8191
8192 // Check that writing to non-existing properties introduces them in
8193 // the other context.
8194 script =
8195 Script::Compile(v8_str("other.eval('na = 1234')"));
8196 script->Run();
8197 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
8198 CHECK(!current->Global()->Has(v8_str("na")));
8199
8200 // Check that global variables in current context are not visible in other
8201 // context.
8202 v8::TryCatch try_catch;
8203 script =
8204 Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
8205 Local<Value> result = script->Run();
8206 CHECK(try_catch.HasCaught());
8207 try_catch.Reset();
8208
8209 // Check that local variables in current context are not visible in other
8210 // context.
8211 script =
8212 Script::Compile(v8_str("(function() { "
8213 " var baz = 87;"
8214 " return other.eval('baz');"
8215 "})();"));
8216 result = script->Run();
8217 CHECK(try_catch.HasCaught());
8218 try_catch.Reset();
8219
8220 // Check that global variables in the other environment are visible
8221 // when evaluting code.
8222 other->Global()->Set(v8_str("bis"), v8_num(1234));
8223 script = Script::Compile(v8_str("other.eval('bis')"));
8224 CHECK_EQ(1234, script->Run()->Int32Value());
8225 CHECK(!try_catch.HasCaught());
8226
8227 // Check that the 'this' pointer points to the global object evaluating
8228 // code.
8229 other->Global()->Set(v8_str("t"), other->Global());
8230 script = Script::Compile(v8_str("other.eval('this == t')"));
8231 result = script->Run();
8232 CHECK(result->IsTrue());
8233 CHECK(!try_catch.HasCaught());
8234
8235 // Check that variables introduced in with-statement are not visible in
8236 // other context.
8237 script =
8238 Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
8239 result = script->Run();
8240 CHECK(try_catch.HasCaught());
8241 try_catch.Reset();
8242
8243 // Check that you cannot use 'eval.call' with another object than the
8244 // current global object.
8245 script =
8246 Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
8247 result = script->Run();
8248 CHECK(try_catch.HasCaught());
8249}
8250
8251
8252// Test that calling eval in a context which has been detached from
8253// its global throws an exception. This behavior is consistent with
8254// other JavaScript implementations.
8255THREADED_TEST(EvalInDetachedGlobal) {
8256 v8::HandleScope scope;
8257
8258 v8::Persistent<Context> context0 = Context::New();
8259 v8::Persistent<Context> context1 = Context::New();
8260
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008261 // Set up function in context0 that uses eval from context0.
Steve Blocka7e24c12009-10-30 11:49:00 +00008262 context0->Enter();
8263 v8::Handle<v8::Value> fun =
8264 CompileRun("var x = 42;"
8265 "(function() {"
8266 " var e = eval;"
8267 " return function(s) { return e(s); }"
8268 "})()");
8269 context0->Exit();
8270
8271 // Put the function into context1 and call it before and after
8272 // detaching the global. Before detaching, the call succeeds and
8273 // after detaching and exception is thrown.
8274 context1->Enter();
8275 context1->Global()->Set(v8_str("fun"), fun);
8276 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
8277 CHECK_EQ(42, x_value->Int32Value());
8278 context0->DetachGlobal();
8279 v8::TryCatch catcher;
8280 x_value = CompileRun("fun('x')");
8281 CHECK(x_value.IsEmpty());
8282 CHECK(catcher.HasCaught());
8283 context1->Exit();
8284
8285 context1.Dispose();
8286 context0.Dispose();
8287}
8288
8289
8290THREADED_TEST(CrossLazyLoad) {
8291 v8::HandleScope scope;
8292 LocalContext other;
8293 LocalContext current;
8294
8295 Local<String> token = v8_str("<security token>");
8296 other->SetSecurityToken(token);
8297 current->SetSecurityToken(token);
8298
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008299 // Set up reference from current to other.
Steve Blocka7e24c12009-10-30 11:49:00 +00008300 current->Global()->Set(v8_str("other"), other->Global());
8301
8302 // Trigger lazy loading in other context.
8303 Local<Script> script =
8304 Script::Compile(v8_str("other.eval('new Date(42)')"));
8305 Local<Value> value = script->Run();
8306 CHECK_EQ(42.0, value->NumberValue());
8307}
8308
8309
8310static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
Andrei Popescu402d9372010-02-26 13:31:12 +00008311 ApiTestFuzzer::Fuzz();
Steve Blocka7e24c12009-10-30 11:49:00 +00008312 if (args.IsConstructCall()) {
8313 if (args[0]->IsInt32()) {
8314 return v8_num(-args[0]->Int32Value());
8315 }
8316 }
8317
8318 return args[0];
8319}
8320
8321
8322// Test that a call handler can be set for objects which will allow
8323// non-function objects created through the API to be called as
8324// functions.
8325THREADED_TEST(CallAsFunction) {
8326 v8::HandleScope scope;
8327 LocalContext context;
8328
Ben Murdoch257744e2011-11-30 15:57:28 +00008329 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8330 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
8331 instance_template->SetCallAsFunctionHandler(call_as_function);
8332 Local<v8::Object> instance = t->GetFunction()->NewInstance();
8333 context->Global()->Set(v8_str("obj"), instance);
8334 v8::TryCatch try_catch;
8335 Local<Value> value;
8336 CHECK(!try_catch.HasCaught());
Steve Blocka7e24c12009-10-30 11:49:00 +00008337
Ben Murdoch257744e2011-11-30 15:57:28 +00008338 value = CompileRun("obj(42)");
8339 CHECK(!try_catch.HasCaught());
8340 CHECK_EQ(42, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00008341
Ben Murdoch257744e2011-11-30 15:57:28 +00008342 value = CompileRun("(function(o){return o(49)})(obj)");
8343 CHECK(!try_catch.HasCaught());
8344 CHECK_EQ(49, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00008345
Ben Murdoch257744e2011-11-30 15:57:28 +00008346 // test special case of call as function
8347 value = CompileRun("[obj]['0'](45)");
8348 CHECK(!try_catch.HasCaught());
8349 CHECK_EQ(45, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00008350
Ben Murdoch257744e2011-11-30 15:57:28 +00008351 value = CompileRun("obj.call = Function.prototype.call;"
8352 "obj.call(null, 87)");
8353 CHECK(!try_catch.HasCaught());
8354 CHECK_EQ(87, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00008355
Ben Murdoch257744e2011-11-30 15:57:28 +00008356 // Regression tests for bug #1116356: Calling call through call/apply
8357 // must work for non-function receivers.
8358 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
8359 value = CompileRun(apply_99);
8360 CHECK(!try_catch.HasCaught());
8361 CHECK_EQ(99, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00008362
Ben Murdoch257744e2011-11-30 15:57:28 +00008363 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
8364 value = CompileRun(call_17);
8365 CHECK(!try_catch.HasCaught());
8366 CHECK_EQ(17, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00008367
Ben Murdoch257744e2011-11-30 15:57:28 +00008368 // Check that the call-as-function handler can be called through
8369 // new.
8370 value = CompileRun("new obj(43)");
8371 CHECK(!try_catch.HasCaught());
8372 CHECK_EQ(-43, value->Int32Value());
8373
8374 // Check that the call-as-function handler can be called through
8375 // the API.
8376 v8::Handle<Value> args[] = { v8_num(28) };
8377 value = instance->CallAsFunction(instance, 1, args);
8378 CHECK(!try_catch.HasCaught());
8379 CHECK_EQ(28, value->Int32Value());
8380 }
8381
8382 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008383 Local<ObjectTemplate> instance_template(t->InstanceTemplate());
8384 USE(instance_template);
Ben Murdoch257744e2011-11-30 15:57:28 +00008385 Local<v8::Object> instance = t->GetFunction()->NewInstance();
8386 context->Global()->Set(v8_str("obj2"), instance);
8387 v8::TryCatch try_catch;
8388 Local<Value> value;
8389 CHECK(!try_catch.HasCaught());
8390
8391 // Call an object without call-as-function handler through the JS
8392 value = CompileRun("obj2(28)");
8393 CHECK(value.IsEmpty());
8394 CHECK(try_catch.HasCaught());
8395 String::AsciiValue exception_value1(try_catch.Exception());
8396 CHECK_EQ("TypeError: Property 'obj2' of object #<Object> is not a function",
8397 *exception_value1);
8398 try_catch.Reset();
8399
8400 // Call an object without call-as-function handler through the API
8401 value = CompileRun("obj2(28)");
8402 v8::Handle<Value> args[] = { v8_num(28) };
8403 value = instance->CallAsFunction(instance, 1, args);
8404 CHECK(value.IsEmpty());
8405 CHECK(try_catch.HasCaught());
8406 String::AsciiValue exception_value2(try_catch.Exception());
8407 CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
8408 try_catch.Reset();
8409 }
8410
8411 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8412 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
8413 instance_template->SetCallAsFunctionHandler(ThrowValue);
8414 Local<v8::Object> instance = t->GetFunction()->NewInstance();
8415 context->Global()->Set(v8_str("obj3"), instance);
8416 v8::TryCatch try_catch;
8417 Local<Value> value;
8418 CHECK(!try_catch.HasCaught());
8419
8420 // Catch the exception which is thrown by call-as-function handler
8421 value = CompileRun("obj3(22)");
8422 CHECK(try_catch.HasCaught());
8423 String::AsciiValue exception_value1(try_catch.Exception());
8424 CHECK_EQ("22", *exception_value1);
8425 try_catch.Reset();
8426
8427 v8::Handle<Value> args[] = { v8_num(23) };
8428 value = instance->CallAsFunction(instance, 1, args);
8429 CHECK(try_catch.HasCaught());
8430 String::AsciiValue exception_value2(try_catch.Exception());
8431 CHECK_EQ("23", *exception_value2);
8432 try_catch.Reset();
8433 }
8434}
8435
8436
8437// Check whether a non-function object is callable.
8438THREADED_TEST(CallableObject) {
8439 v8::HandleScope scope;
8440 LocalContext context;
8441
8442 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8443 instance_template->SetCallAsFunctionHandler(call_as_function);
8444 Local<Object> instance = instance_template->NewInstance();
8445 v8::TryCatch try_catch;
8446
8447 CHECK(instance->IsCallable());
8448 CHECK(!try_catch.HasCaught());
8449 }
8450
8451 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8452 Local<Object> instance = instance_template->NewInstance();
8453 v8::TryCatch try_catch;
8454
8455 CHECK(!instance->IsCallable());
8456 CHECK(!try_catch.HasCaught());
8457 }
8458
8459 { Local<FunctionTemplate> function_template =
8460 FunctionTemplate::New(call_as_function);
8461 Local<Function> function = function_template->GetFunction();
8462 Local<Object> instance = function;
8463 v8::TryCatch try_catch;
8464
8465 CHECK(instance->IsCallable());
8466 CHECK(!try_catch.HasCaught());
8467 }
8468
8469 { Local<FunctionTemplate> function_template = FunctionTemplate::New();
8470 Local<Function> function = function_template->GetFunction();
8471 Local<Object> instance = function;
8472 v8::TryCatch try_catch;
8473
8474 CHECK(instance->IsCallable());
8475 CHECK(!try_catch.HasCaught());
8476 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008477}
8478
8479
8480static int CountHandles() {
8481 return v8::HandleScope::NumberOfHandles();
8482}
8483
8484
8485static int Recurse(int depth, int iterations) {
8486 v8::HandleScope scope;
8487 if (depth == 0) return CountHandles();
8488 for (int i = 0; i < iterations; i++) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008489 Local<v8::Number> n(v8::Integer::New(42));
Steve Blocka7e24c12009-10-30 11:49:00 +00008490 }
8491 return Recurse(depth - 1, iterations);
8492}
8493
8494
8495THREADED_TEST(HandleIteration) {
8496 static const int kIterations = 500;
8497 static const int kNesting = 200;
8498 CHECK_EQ(0, CountHandles());
8499 {
8500 v8::HandleScope scope1;
8501 CHECK_EQ(0, CountHandles());
8502 for (int i = 0; i < kIterations; i++) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008503 Local<v8::Number> n(v8::Integer::New(42));
Steve Blocka7e24c12009-10-30 11:49:00 +00008504 CHECK_EQ(i + 1, CountHandles());
8505 }
8506
8507 CHECK_EQ(kIterations, CountHandles());
8508 {
8509 v8::HandleScope scope2;
8510 for (int j = 0; j < kIterations; j++) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008511 Local<v8::Number> n(v8::Integer::New(42));
Steve Blocka7e24c12009-10-30 11:49:00 +00008512 CHECK_EQ(j + 1 + kIterations, CountHandles());
8513 }
8514 }
8515 CHECK_EQ(kIterations, CountHandles());
8516 }
8517 CHECK_EQ(0, CountHandles());
8518 CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
8519}
8520
8521
8522static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
8523 Local<String> name,
8524 const AccessorInfo& info) {
8525 ApiTestFuzzer::Fuzz();
8526 return v8::Handle<Value>();
8527}
8528
8529
8530THREADED_TEST(InterceptorHasOwnProperty) {
8531 v8::HandleScope scope;
8532 LocalContext context;
8533 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8534 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
8535 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
8536 Local<Function> function = fun_templ->GetFunction();
8537 context->Global()->Set(v8_str("constructor"), function);
8538 v8::Handle<Value> value = CompileRun(
8539 "var o = new constructor();"
8540 "o.hasOwnProperty('ostehaps');");
8541 CHECK_EQ(false, value->BooleanValue());
8542 value = CompileRun(
8543 "o.ostehaps = 42;"
8544 "o.hasOwnProperty('ostehaps');");
8545 CHECK_EQ(true, value->BooleanValue());
8546 value = CompileRun(
8547 "var p = new constructor();"
8548 "p.hasOwnProperty('ostehaps');");
8549 CHECK_EQ(false, value->BooleanValue());
8550}
8551
8552
8553static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
8554 Local<String> name,
8555 const AccessorInfo& info) {
8556 ApiTestFuzzer::Fuzz();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008557 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +00008558 return v8::Handle<Value>();
8559}
8560
8561
8562THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
8563 v8::HandleScope scope;
8564 LocalContext context;
8565 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8566 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
8567 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
8568 Local<Function> function = fun_templ->GetFunction();
8569 context->Global()->Set(v8_str("constructor"), function);
8570 // Let's first make some stuff so we can be sure to get a good GC.
8571 CompileRun(
8572 "function makestr(size) {"
8573 " switch (size) {"
8574 " case 1: return 'f';"
8575 " case 2: return 'fo';"
8576 " case 3: return 'foo';"
8577 " }"
8578 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
8579 "}"
8580 "var x = makestr(12345);"
8581 "x = makestr(31415);"
8582 "x = makestr(23456);");
8583 v8::Handle<Value> value = CompileRun(
8584 "var o = new constructor();"
8585 "o.__proto__ = new String(x);"
8586 "o.hasOwnProperty('ostehaps');");
8587 CHECK_EQ(false, value->BooleanValue());
8588}
8589
8590
8591typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
8592 const AccessorInfo& info);
8593
8594
8595static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
8596 const char* source,
8597 int expected) {
8598 v8::HandleScope scope;
8599 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08008600 templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
Steve Blocka7e24c12009-10-30 11:49:00 +00008601 LocalContext context;
8602 context->Global()->Set(v8_str("o"), templ->NewInstance());
8603 v8::Handle<Value> value = CompileRun(source);
8604 CHECK_EQ(expected, value->Int32Value());
8605}
8606
8607
8608static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
8609 const AccessorInfo& info) {
8610 ApiTestFuzzer::Fuzz();
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08008611 CHECK_EQ(v8_str("data"), info.Data());
8612 CHECK_EQ(v8_str("x"), name);
Steve Blocka7e24c12009-10-30 11:49:00 +00008613 return v8::Integer::New(42);
8614}
8615
8616
8617// This test should hit the load IC for the interceptor case.
8618THREADED_TEST(InterceptorLoadIC) {
8619 CheckInterceptorLoadIC(InterceptorLoadICGetter,
8620 "var result = 0;"
8621 "for (var i = 0; i < 1000; i++) {"
8622 " result = o.x;"
8623 "}",
8624 42);
8625}
8626
8627
8628// Below go several tests which verify that JITing for various
8629// configurations of interceptor and explicit fields works fine
8630// (those cases are special cased to get better performance).
8631
8632static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
8633 const AccessorInfo& info) {
8634 ApiTestFuzzer::Fuzz();
8635 return v8_str("x")->Equals(name)
8636 ? v8::Integer::New(42) : v8::Handle<v8::Value>();
8637}
8638
8639
8640THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
8641 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8642 "var result = 0;"
8643 "o.y = 239;"
8644 "for (var i = 0; i < 1000; i++) {"
8645 " result = o.y;"
8646 "}",
8647 239);
8648}
8649
8650
8651THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
8652 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8653 "var result = 0;"
8654 "o.__proto__ = { 'y': 239 };"
8655 "for (var i = 0; i < 1000; i++) {"
8656 " result = o.y + o.x;"
8657 "}",
8658 239 + 42);
8659}
8660
8661
8662THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
8663 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8664 "var result = 0;"
8665 "o.__proto__.y = 239;"
8666 "for (var i = 0; i < 1000; i++) {"
8667 " result = o.y + o.x;"
8668 "}",
8669 239 + 42);
8670}
8671
8672
8673THREADED_TEST(InterceptorLoadICUndefined) {
8674 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8675 "var result = 0;"
8676 "for (var i = 0; i < 1000; i++) {"
8677 " result = (o.y == undefined) ? 239 : 42;"
8678 "}",
8679 239);
8680}
8681
8682
8683THREADED_TEST(InterceptorLoadICWithOverride) {
8684 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8685 "fst = new Object(); fst.__proto__ = o;"
8686 "snd = new Object(); snd.__proto__ = fst;"
8687 "var result1 = 0;"
8688 "for (var i = 0; i < 1000; i++) {"
8689 " result1 = snd.x;"
8690 "}"
8691 "fst.x = 239;"
8692 "var result = 0;"
8693 "for (var i = 0; i < 1000; i++) {"
8694 " result = snd.x;"
8695 "}"
8696 "result + result1",
8697 239 + 42);
8698}
8699
8700
8701// Test the case when we stored field into
8702// a stub, but interceptor produced value on its own.
8703THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
8704 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8705 "proto = new Object();"
8706 "o.__proto__ = proto;"
8707 "proto.x = 239;"
8708 "for (var i = 0; i < 1000; i++) {"
8709 " o.x;"
8710 // Now it should be ICed and keep a reference to x defined on proto
8711 "}"
8712 "var result = 0;"
8713 "for (var i = 0; i < 1000; i++) {"
8714 " result += o.x;"
8715 "}"
8716 "result;",
8717 42 * 1000);
8718}
8719
8720
8721// Test the case when we stored field into
8722// a stub, but it got invalidated later on.
8723THREADED_TEST(InterceptorLoadICInvalidatedField) {
8724 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8725 "proto1 = new Object();"
8726 "proto2 = new Object();"
8727 "o.__proto__ = proto1;"
8728 "proto1.__proto__ = proto2;"
8729 "proto2.y = 239;"
8730 "for (var i = 0; i < 1000; i++) {"
8731 " o.y;"
8732 // Now it should be ICed and keep a reference to y defined on proto2
8733 "}"
8734 "proto1.y = 42;"
8735 "var result = 0;"
8736 "for (var i = 0; i < 1000; i++) {"
8737 " result += o.y;"
8738 "}"
8739 "result;",
8740 42 * 1000);
8741}
8742
8743
Steve Block6ded16b2010-05-10 14:33:55 +01008744static int interceptor_load_not_handled_calls = 0;
8745static v8::Handle<Value> InterceptorLoadNotHandled(Local<String> name,
8746 const AccessorInfo& info) {
8747 ++interceptor_load_not_handled_calls;
8748 return v8::Handle<v8::Value>();
8749}
8750
8751
8752// Test how post-interceptor lookups are done in the non-cacheable
8753// case: the interceptor should not be invoked during this lookup.
8754THREADED_TEST(InterceptorLoadICPostInterceptor) {
8755 interceptor_load_not_handled_calls = 0;
8756 CheckInterceptorLoadIC(InterceptorLoadNotHandled,
8757 "receiver = new Object();"
8758 "receiver.__proto__ = o;"
8759 "proto = new Object();"
8760 "/* Make proto a slow-case object. */"
8761 "for (var i = 0; i < 1000; i++) {"
8762 " proto[\"xxxxxxxx\" + i] = [];"
8763 "}"
8764 "proto.x = 17;"
8765 "o.__proto__ = proto;"
8766 "var result = 0;"
8767 "for (var i = 0; i < 1000; i++) {"
8768 " result += receiver.x;"
8769 "}"
8770 "result;",
8771 17 * 1000);
8772 CHECK_EQ(1000, interceptor_load_not_handled_calls);
8773}
8774
8775
Steve Blocka7e24c12009-10-30 11:49:00 +00008776// Test the case when we stored field into
8777// a stub, but it got invalidated later on due to override on
8778// global object which is between interceptor and fields' holders.
8779THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
8780 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8781 "o.__proto__ = this;" // set a global to be a proto of o.
8782 "this.__proto__.y = 239;"
8783 "for (var i = 0; i < 10; i++) {"
8784 " if (o.y != 239) throw 'oops: ' + o.y;"
8785 // Now it should be ICed and keep a reference to y defined on field_holder.
8786 "}"
8787 "this.y = 42;" // Assign on a global.
8788 "var result = 0;"
8789 "for (var i = 0; i < 10; i++) {"
8790 " result += o.y;"
8791 "}"
8792 "result;",
8793 42 * 10);
8794}
8795
8796
Steve Blocka7e24c12009-10-30 11:49:00 +00008797static void SetOnThis(Local<String> name,
8798 Local<Value> value,
8799 const AccessorInfo& info) {
8800 info.This()->ForceSet(name, value);
8801}
8802
8803
8804THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
8805 v8::HandleScope scope;
8806 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8807 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8808 templ->SetAccessor(v8_str("y"), Return239);
8809 LocalContext context;
8810 context->Global()->Set(v8_str("o"), templ->NewInstance());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008811
8812 // Check the case when receiver and interceptor's holder
8813 // are the same objects.
Steve Blocka7e24c12009-10-30 11:49:00 +00008814 v8::Handle<Value> value = CompileRun(
8815 "var result = 0;"
8816 "for (var i = 0; i < 7; i++) {"
8817 " result = o.y;"
8818 "}");
8819 CHECK_EQ(239, value->Int32Value());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008820
8821 // Check the case when interceptor's holder is in proto chain
8822 // of receiver.
8823 value = CompileRun(
8824 "r = { __proto__: o };"
8825 "var result = 0;"
8826 "for (var i = 0; i < 7; i++) {"
8827 " result = r.y;"
8828 "}");
8829 CHECK_EQ(239, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00008830}
8831
8832
8833THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
8834 v8::HandleScope scope;
8835 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8836 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8837 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8838 templ_p->SetAccessor(v8_str("y"), Return239);
8839
8840 LocalContext context;
8841 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8842 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8843
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008844 // Check the case when receiver and interceptor's holder
8845 // are the same objects.
Steve Blocka7e24c12009-10-30 11:49:00 +00008846 v8::Handle<Value> value = CompileRun(
8847 "o.__proto__ = p;"
8848 "var result = 0;"
8849 "for (var i = 0; i < 7; i++) {"
8850 " result = o.x + o.y;"
8851 "}");
8852 CHECK_EQ(239 + 42, value->Int32Value());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008853
8854 // Check the case when interceptor's holder is in proto chain
8855 // of receiver.
8856 value = CompileRun(
8857 "r = { __proto__: o };"
8858 "var result = 0;"
8859 "for (var i = 0; i < 7; i++) {"
8860 " result = r.x + r.y;"
8861 "}");
8862 CHECK_EQ(239 + 42, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00008863}
8864
8865
8866THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
8867 v8::HandleScope scope;
8868 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8869 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8870 templ->SetAccessor(v8_str("y"), Return239);
8871
8872 LocalContext context;
8873 context->Global()->Set(v8_str("o"), templ->NewInstance());
8874
8875 v8::Handle<Value> value = CompileRun(
8876 "fst = new Object(); fst.__proto__ = o;"
8877 "snd = new Object(); snd.__proto__ = fst;"
8878 "var result1 = 0;"
8879 "for (var i = 0; i < 7; i++) {"
8880 " result1 = snd.x;"
8881 "}"
8882 "fst.x = 239;"
8883 "var result = 0;"
8884 "for (var i = 0; i < 7; i++) {"
8885 " result = snd.x;"
8886 "}"
8887 "result + result1");
8888 CHECK_EQ(239 + 42, value->Int32Value());
8889}
8890
8891
8892// Test the case when we stored callback into
8893// a stub, but interceptor produced value on its own.
8894THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
8895 v8::HandleScope scope;
8896 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8897 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8898 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8899 templ_p->SetAccessor(v8_str("y"), Return239);
8900
8901 LocalContext context;
8902 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8903 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8904
8905 v8::Handle<Value> value = CompileRun(
8906 "o.__proto__ = p;"
8907 "for (var i = 0; i < 7; i++) {"
8908 " o.x;"
8909 // Now it should be ICed and keep a reference to x defined on p
8910 "}"
8911 "var result = 0;"
8912 "for (var i = 0; i < 7; i++) {"
8913 " result += o.x;"
8914 "}"
8915 "result");
8916 CHECK_EQ(42 * 7, value->Int32Value());
8917}
8918
8919
8920// Test the case when we stored callback into
8921// a stub, but it got invalidated later on.
8922THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
8923 v8::HandleScope scope;
8924 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8925 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8926 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8927 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
8928
8929 LocalContext context;
8930 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8931 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8932
8933 v8::Handle<Value> value = CompileRun(
8934 "inbetween = new Object();"
8935 "o.__proto__ = inbetween;"
8936 "inbetween.__proto__ = p;"
8937 "for (var i = 0; i < 10; i++) {"
8938 " o.y;"
8939 // Now it should be ICed and keep a reference to y defined on p
8940 "}"
8941 "inbetween.y = 42;"
8942 "var result = 0;"
8943 "for (var i = 0; i < 10; i++) {"
8944 " result += o.y;"
8945 "}"
8946 "result");
8947 CHECK_EQ(42 * 10, value->Int32Value());
8948}
8949
8950
8951// Test the case when we stored callback into
8952// a stub, but it got invalidated later on due to override on
8953// global object which is between interceptor and callbacks' holders.
8954THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
8955 v8::HandleScope scope;
8956 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8957 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8958 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8959 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
8960
8961 LocalContext context;
8962 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8963 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8964
8965 v8::Handle<Value> value = CompileRun(
8966 "o.__proto__ = this;"
8967 "this.__proto__ = p;"
8968 "for (var i = 0; i < 10; i++) {"
8969 " if (o.y != 239) throw 'oops: ' + o.y;"
8970 // Now it should be ICed and keep a reference to y defined on p
8971 "}"
8972 "this.y = 42;"
8973 "var result = 0;"
8974 "for (var i = 0; i < 10; i++) {"
8975 " result += o.y;"
8976 "}"
8977 "result");
8978 CHECK_EQ(42 * 10, value->Int32Value());
8979}
8980
8981
8982static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
8983 const AccessorInfo& info) {
8984 ApiTestFuzzer::Fuzz();
8985 CHECK(v8_str("x")->Equals(name));
8986 return v8::Integer::New(0);
8987}
8988
8989
8990THREADED_TEST(InterceptorReturningZero) {
8991 CheckInterceptorLoadIC(InterceptorLoadICGetter0,
8992 "o.x == undefined ? 1 : 0",
8993 0);
8994}
8995
8996
8997static v8::Handle<Value> InterceptorStoreICSetter(
8998 Local<String> key, Local<Value> value, const AccessorInfo&) {
8999 CHECK(v8_str("x")->Equals(key));
9000 CHECK_EQ(42, value->Int32Value());
9001 return value;
9002}
9003
9004
9005// This test should hit the store IC for the interceptor case.
9006THREADED_TEST(InterceptorStoreIC) {
9007 v8::HandleScope scope;
9008 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9009 templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08009010 InterceptorStoreICSetter,
9011 0, 0, 0, v8_str("data"));
Steve Blocka7e24c12009-10-30 11:49:00 +00009012 LocalContext context;
9013 context->Global()->Set(v8_str("o"), templ->NewInstance());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009014 CompileRun(
9015 "for (var i = 0; i < 1000; i++) {"
9016 " o.x = 42;"
9017 "}");
Steve Blocka7e24c12009-10-30 11:49:00 +00009018}
9019
9020
9021THREADED_TEST(InterceptorStoreICWithNoSetter) {
9022 v8::HandleScope scope;
9023 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9024 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9025 LocalContext context;
9026 context->Global()->Set(v8_str("o"), templ->NewInstance());
9027 v8::Handle<Value> value = CompileRun(
9028 "for (var i = 0; i < 1000; i++) {"
9029 " o.y = 239;"
9030 "}"
9031 "42 + o.y");
9032 CHECK_EQ(239 + 42, value->Int32Value());
9033}
9034
9035
9036
9037
9038v8::Handle<Value> call_ic_function;
9039v8::Handle<Value> call_ic_function2;
9040v8::Handle<Value> call_ic_function3;
9041
9042static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
9043 const AccessorInfo& info) {
9044 ApiTestFuzzer::Fuzz();
9045 CHECK(v8_str("x")->Equals(name));
9046 return call_ic_function;
9047}
9048
9049
9050// This test should hit the call IC for the interceptor case.
9051THREADED_TEST(InterceptorCallIC) {
9052 v8::HandleScope scope;
9053 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9054 templ->SetNamedPropertyHandler(InterceptorCallICGetter);
9055 LocalContext context;
9056 context->Global()->Set(v8_str("o"), templ->NewInstance());
9057 call_ic_function =
9058 v8_compile("function f(x) { return x + 1; }; f")->Run();
9059 v8::Handle<Value> value = CompileRun(
9060 "var result = 0;"
9061 "for (var i = 0; i < 1000; i++) {"
9062 " result = o.x(41);"
9063 "}");
9064 CHECK_EQ(42, value->Int32Value());
9065}
9066
9067
9068// This test checks that if interceptor doesn't provide
9069// a value, we can fetch regular value.
9070THREADED_TEST(InterceptorCallICSeesOthers) {
9071 v8::HandleScope scope;
9072 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9073 templ->SetNamedPropertyHandler(NoBlockGetterX);
9074 LocalContext context;
9075 context->Global()->Set(v8_str("o"), templ->NewInstance());
9076 v8::Handle<Value> value = CompileRun(
9077 "o.x = function f(x) { return x + 1; };"
9078 "var result = 0;"
9079 "for (var i = 0; i < 7; i++) {"
9080 " result = o.x(41);"
9081 "}");
9082 CHECK_EQ(42, value->Int32Value());
9083}
9084
9085
9086static v8::Handle<Value> call_ic_function4;
9087static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
9088 const AccessorInfo& info) {
9089 ApiTestFuzzer::Fuzz();
9090 CHECK(v8_str("x")->Equals(name));
9091 return call_ic_function4;
9092}
9093
9094
9095// This test checks that if interceptor provides a function,
9096// even if we cached shadowed variant, interceptor's function
9097// is invoked
9098THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
9099 v8::HandleScope scope;
9100 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9101 templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
9102 LocalContext context;
9103 context->Global()->Set(v8_str("o"), templ->NewInstance());
9104 call_ic_function4 =
9105 v8_compile("function f(x) { return x - 1; }; f")->Run();
9106 v8::Handle<Value> value = CompileRun(
9107 "o.__proto__.x = function(x) { return x + 1; };"
9108 "var result = 0;"
9109 "for (var i = 0; i < 1000; i++) {"
9110 " result = o.x(42);"
9111 "}");
9112 CHECK_EQ(41, value->Int32Value());
9113}
9114
9115
9116// Test the case when we stored cacheable lookup into
9117// a stub, but it got invalidated later on
9118THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
9119 v8::HandleScope scope;
9120 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9121 templ->SetNamedPropertyHandler(NoBlockGetterX);
9122 LocalContext context;
9123 context->Global()->Set(v8_str("o"), templ->NewInstance());
9124 v8::Handle<Value> value = CompileRun(
9125 "proto1 = new Object();"
9126 "proto2 = new Object();"
9127 "o.__proto__ = proto1;"
9128 "proto1.__proto__ = proto2;"
9129 "proto2.y = function(x) { return x + 1; };"
9130 // Invoke it many times to compile a stub
9131 "for (var i = 0; i < 7; i++) {"
9132 " o.y(42);"
9133 "}"
9134 "proto1.y = function(x) { return x - 1; };"
9135 "var result = 0;"
9136 "for (var i = 0; i < 7; i++) {"
9137 " result += o.y(42);"
9138 "}");
9139 CHECK_EQ(41 * 7, value->Int32Value());
9140}
9141
9142
Steve Blocka7e24c12009-10-30 11:49:00 +00009143// This test checks that if interceptor doesn't provide a function,
9144// cached constant function is used
9145THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
9146 v8::HandleScope scope;
9147 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9148 templ->SetNamedPropertyHandler(NoBlockGetterX);
9149 LocalContext context;
9150 context->Global()->Set(v8_str("o"), templ->NewInstance());
9151 v8::Handle<Value> value = CompileRun(
9152 "function inc(x) { return x + 1; };"
9153 "inc(1);"
9154 "o.x = inc;"
9155 "var result = 0;"
9156 "for (var i = 0; i < 1000; i++) {"
9157 " result = o.x(42);"
9158 "}");
9159 CHECK_EQ(43, value->Int32Value());
9160}
9161
9162
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009163static v8::Handle<Value> call_ic_function5;
9164static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
9165 const AccessorInfo& info) {
9166 ApiTestFuzzer::Fuzz();
9167 if (v8_str("x")->Equals(name))
9168 return call_ic_function5;
9169 else
9170 return Local<Value>();
9171}
9172
9173
Steve Blocka7e24c12009-10-30 11:49:00 +00009174// This test checks that if interceptor provides a function,
9175// even if we cached constant function, interceptor's function
9176// is invoked
9177THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
9178 v8::HandleScope scope;
9179 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9180 templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
9181 LocalContext context;
9182 context->Global()->Set(v8_str("o"), templ->NewInstance());
9183 call_ic_function5 =
9184 v8_compile("function f(x) { return x - 1; }; f")->Run();
9185 v8::Handle<Value> value = CompileRun(
9186 "function inc(x) { return x + 1; };"
9187 "inc(1);"
9188 "o.x = inc;"
9189 "var result = 0;"
9190 "for (var i = 0; i < 1000; i++) {"
9191 " result = o.x(42);"
9192 "}");
9193 CHECK_EQ(41, value->Int32Value());
9194}
9195
9196
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009197static v8::Handle<Value> call_ic_function6;
9198static v8::Handle<Value> InterceptorCallICGetter6(Local<String> name,
9199 const AccessorInfo& info) {
9200 ApiTestFuzzer::Fuzz();
9201 if (v8_str("x")->Equals(name))
9202 return call_ic_function6;
9203 else
9204 return Local<Value>();
9205}
9206
9207
9208// Same test as above, except the code is wrapped in a function
9209// to test the optimized compiler.
9210THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
9211 i::FLAG_allow_natives_syntax = true;
9212 v8::HandleScope scope;
9213 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9214 templ->SetNamedPropertyHandler(InterceptorCallICGetter6);
9215 LocalContext context;
9216 context->Global()->Set(v8_str("o"), templ->NewInstance());
9217 call_ic_function6 =
9218 v8_compile("function f(x) { return x - 1; }; f")->Run();
9219 v8::Handle<Value> value = CompileRun(
9220 "function inc(x) { return x + 1; };"
9221 "inc(1);"
9222 "o.x = inc;"
9223 "function test() {"
9224 " var result = 0;"
9225 " for (var i = 0; i < 1000; i++) {"
9226 " result = o.x(42);"
9227 " }"
9228 " return result;"
9229 "};"
9230 "test();"
9231 "test();"
9232 "test();"
9233 "%OptimizeFunctionOnNextCall(test);"
9234 "test()");
9235 CHECK_EQ(41, value->Int32Value());
9236}
9237
9238
Steve Blocka7e24c12009-10-30 11:49:00 +00009239// Test the case when we stored constant function into
9240// a stub, but it got invalidated later on
9241THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
9242 v8::HandleScope scope;
9243 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9244 templ->SetNamedPropertyHandler(NoBlockGetterX);
9245 LocalContext context;
9246 context->Global()->Set(v8_str("o"), templ->NewInstance());
9247 v8::Handle<Value> value = CompileRun(
9248 "function inc(x) { return x + 1; };"
9249 "inc(1);"
9250 "proto1 = new Object();"
9251 "proto2 = new Object();"
9252 "o.__proto__ = proto1;"
9253 "proto1.__proto__ = proto2;"
9254 "proto2.y = inc;"
9255 // Invoke it many times to compile a stub
9256 "for (var i = 0; i < 7; i++) {"
9257 " o.y(42);"
9258 "}"
9259 "proto1.y = function(x) { return x - 1; };"
9260 "var result = 0;"
9261 "for (var i = 0; i < 7; i++) {"
9262 " result += o.y(42);"
9263 "}");
9264 CHECK_EQ(41 * 7, value->Int32Value());
9265}
9266
9267
9268// Test the case when we stored constant function into
9269// a stub, but it got invalidated later on due to override on
9270// global object which is between interceptor and constant function' holders.
9271THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
9272 v8::HandleScope scope;
9273 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9274 templ->SetNamedPropertyHandler(NoBlockGetterX);
9275 LocalContext context;
9276 context->Global()->Set(v8_str("o"), templ->NewInstance());
9277 v8::Handle<Value> value = CompileRun(
9278 "function inc(x) { return x + 1; };"
9279 "inc(1);"
9280 "o.__proto__ = this;"
9281 "this.__proto__.y = inc;"
9282 // Invoke it many times to compile a stub
9283 "for (var i = 0; i < 7; i++) {"
9284 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
9285 "}"
9286 "this.y = function(x) { return x - 1; };"
9287 "var result = 0;"
9288 "for (var i = 0; i < 7; i++) {"
9289 " result += o.y(42);"
9290 "}");
9291 CHECK_EQ(41 * 7, value->Int32Value());
9292}
9293
9294
Leon Clarke4515c472010-02-03 11:58:03 +00009295// Test the case when actual function to call sits on global object.
9296THREADED_TEST(InterceptorCallICCachedFromGlobal) {
9297 v8::HandleScope scope;
9298 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9299 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9300
9301 LocalContext context;
9302 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9303
9304 v8::Handle<Value> value = CompileRun(
9305 "try {"
9306 " o.__proto__ = this;"
9307 " for (var i = 0; i < 10; i++) {"
9308 " var v = o.parseFloat('239');"
9309 " if (v != 239) throw v;"
9310 // Now it should be ICed and keep a reference to parseFloat.
9311 " }"
9312 " var result = 0;"
9313 " for (var i = 0; i < 10; i++) {"
9314 " result += o.parseFloat('239');"
9315 " }"
9316 " result"
9317 "} catch(e) {"
9318 " e"
9319 "};");
9320 CHECK_EQ(239 * 10, value->Int32Value());
9321}
9322
Andrei Popescu402d9372010-02-26 13:31:12 +00009323static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
9324 const AccessorInfo& info) {
9325 ApiTestFuzzer::Fuzz();
9326 int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data()));
9327 ++(*call_count);
9328 if ((*call_count) % 20 == 0) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009329 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Andrei Popescu402d9372010-02-26 13:31:12 +00009330 }
9331 return v8::Handle<Value>();
9332}
9333
9334static v8::Handle<Value> FastApiCallback_TrivialSignature(
9335 const v8::Arguments& args) {
9336 ApiTestFuzzer::Fuzz();
9337 CHECK_EQ(args.This(), args.Holder());
9338 CHECK(args.Data()->Equals(v8_str("method_data")));
9339 return v8::Integer::New(args[0]->Int32Value() + 1);
9340}
9341
9342static v8::Handle<Value> FastApiCallback_SimpleSignature(
9343 const v8::Arguments& args) {
9344 ApiTestFuzzer::Fuzz();
9345 CHECK_EQ(args.This()->GetPrototype(), args.Holder());
9346 CHECK(args.Data()->Equals(v8_str("method_data")));
9347 // Note, we're using HasRealNamedProperty instead of Has to avoid
9348 // invoking the interceptor again.
9349 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
9350 return v8::Integer::New(args[0]->Int32Value() + 1);
9351}
9352
9353// Helper to maximize the odds of object moving.
9354static void GenerateSomeGarbage() {
9355 CompileRun(
9356 "var garbage;"
9357 "for (var i = 0; i < 1000; i++) {"
9358 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
9359 "}"
9360 "garbage = undefined;");
9361}
9362
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009363
Steve Block1e0659c2011-05-24 12:43:12 +01009364v8::Handle<v8::Value> DirectApiCallback(const v8::Arguments& args) {
9365 static int count = 0;
9366 if (count++ % 3 == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01009367 HEAP-> CollectAllGarbage(true); // This should move the stub
Steve Block1e0659c2011-05-24 12:43:12 +01009368 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
9369 }
9370 return v8::Handle<v8::Value>();
9371}
9372
9373
9374THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
9375 v8::HandleScope scope;
9376 LocalContext context;
9377 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
9378 nativeobject_templ->Set("callback",
9379 v8::FunctionTemplate::New(DirectApiCallback));
9380 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
9381 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
9382 // call the api function multiple times to ensure direct call stub creation.
9383 CompileRun(
9384 "function f() {"
9385 " for (var i = 1; i <= 30; i++) {"
9386 " nativeobject.callback();"
9387 " }"
9388 "}"
9389 "f();");
9390}
9391
9392
9393v8::Handle<v8::Value> ThrowingDirectApiCallback(const v8::Arguments& args) {
9394 return v8::ThrowException(v8_str("g"));
9395}
9396
9397
9398THREADED_TEST(CallICFastApi_DirectCall_Throw) {
9399 v8::HandleScope scope;
9400 LocalContext context;
9401 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
9402 nativeobject_templ->Set("callback",
9403 v8::FunctionTemplate::New(ThrowingDirectApiCallback));
9404 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
9405 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
9406 // call the api function multiple times to ensure direct call stub creation.
9407 v8::Handle<Value> result = CompileRun(
9408 "var result = '';"
9409 "function f() {"
9410 " for (var i = 1; i <= 5; i++) {"
9411 " try { nativeobject.callback(); } catch (e) { result += e; }"
9412 " }"
9413 "}"
9414 "f(); result;");
9415 CHECK_EQ(v8_str("ggggg"), result);
9416}
9417
9418
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009419v8::Handle<v8::Value> DirectGetterCallback(Local<String> name,
9420 const v8::AccessorInfo& info) {
9421 if (++p_getter_count % 3 == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01009422 HEAP->CollectAllGarbage(true);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009423 GenerateSomeGarbage();
9424 }
9425 return v8::Handle<v8::Value>();
9426}
9427
9428
9429THREADED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
9430 v8::HandleScope scope;
9431 LocalContext context;
9432 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
9433 obj->SetAccessor(v8_str("p1"), DirectGetterCallback);
9434 context->Global()->Set(v8_str("o1"), obj->NewInstance());
9435 p_getter_count = 0;
9436 CompileRun(
9437 "function f() {"
9438 " for (var i = 0; i < 30; i++) o1.p1;"
9439 "}"
9440 "f();");
9441 CHECK_EQ(30, p_getter_count);
9442}
9443
9444
9445v8::Handle<v8::Value> ThrowingDirectGetterCallback(
9446 Local<String> name, const v8::AccessorInfo& info) {
9447 return v8::ThrowException(v8_str("g"));
9448}
9449
9450
9451THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
9452 v8::HandleScope scope;
9453 LocalContext context;
9454 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
9455 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
9456 context->Global()->Set(v8_str("o1"), obj->NewInstance());
9457 v8::Handle<Value> result = CompileRun(
9458 "var result = '';"
9459 "for (var i = 0; i < 5; i++) {"
9460 " try { o1.p1; } catch (e) { result += e; }"
9461 "}"
9462 "result;");
9463 CHECK_EQ(v8_str("ggggg"), result);
9464}
9465
9466
Andrei Popescu402d9372010-02-26 13:31:12 +00009467THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
9468 int interceptor_call_count = 0;
9469 v8::HandleScope scope;
9470 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9471 v8::Handle<v8::FunctionTemplate> method_templ =
9472 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
9473 v8_str("method_data"),
9474 v8::Handle<v8::Signature>());
9475 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9476 proto_templ->Set(v8_str("method"), method_templ);
9477 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9478 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9479 NULL, NULL, NULL, NULL,
9480 v8::External::Wrap(&interceptor_call_count));
9481 LocalContext context;
9482 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9483 GenerateSomeGarbage();
9484 context->Global()->Set(v8_str("o"), fun->NewInstance());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009485 CompileRun(
Andrei Popescu402d9372010-02-26 13:31:12 +00009486 "var result = 0;"
9487 "for (var i = 0; i < 100; i++) {"
9488 " result = o.method(41);"
Ben Murdochc7cc0282012-03-05 14:35:55 +00009489 "}");
Andrei Popescu402d9372010-02-26 13:31:12 +00009490 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9491 CHECK_EQ(100, interceptor_call_count);
9492}
9493
9494THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
9495 int interceptor_call_count = 0;
9496 v8::HandleScope scope;
9497 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9498 v8::Handle<v8::FunctionTemplate> method_templ =
9499 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9500 v8_str("method_data"),
9501 v8::Signature::New(fun_templ));
9502 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9503 proto_templ->Set(v8_str("method"), method_templ);
9504 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9505 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9506 NULL, NULL, NULL, NULL,
9507 v8::External::Wrap(&interceptor_call_count));
9508 LocalContext context;
9509 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9510 GenerateSomeGarbage();
9511 context->Global()->Set(v8_str("o"), fun->NewInstance());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009512 CompileRun(
Andrei Popescu402d9372010-02-26 13:31:12 +00009513 "o.foo = 17;"
9514 "var receiver = {};"
9515 "receiver.__proto__ = o;"
9516 "var result = 0;"
9517 "for (var i = 0; i < 100; i++) {"
9518 " result = receiver.method(41);"
Ben Murdochc7cc0282012-03-05 14:35:55 +00009519 "}");
Andrei Popescu402d9372010-02-26 13:31:12 +00009520 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9521 CHECK_EQ(100, interceptor_call_count);
9522}
9523
9524THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
9525 int interceptor_call_count = 0;
9526 v8::HandleScope scope;
9527 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9528 v8::Handle<v8::FunctionTemplate> method_templ =
9529 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9530 v8_str("method_data"),
9531 v8::Signature::New(fun_templ));
9532 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9533 proto_templ->Set(v8_str("method"), method_templ);
9534 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9535 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9536 NULL, NULL, NULL, NULL,
9537 v8::External::Wrap(&interceptor_call_count));
9538 LocalContext context;
9539 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9540 GenerateSomeGarbage();
9541 context->Global()->Set(v8_str("o"), fun->NewInstance());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009542 CompileRun(
Andrei Popescu402d9372010-02-26 13:31:12 +00009543 "o.foo = 17;"
9544 "var receiver = {};"
9545 "receiver.__proto__ = o;"
9546 "var result = 0;"
9547 "var saved_result = 0;"
9548 "for (var i = 0; i < 100; i++) {"
9549 " result = receiver.method(41);"
9550 " if (i == 50) {"
9551 " saved_result = result;"
9552 " receiver = {method: function(x) { return x - 1 }};"
9553 " }"
Ben Murdochc7cc0282012-03-05 14:35:55 +00009554 "}");
Andrei Popescu402d9372010-02-26 13:31:12 +00009555 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
9556 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9557 CHECK_GE(interceptor_call_count, 50);
9558}
9559
9560THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
9561 int interceptor_call_count = 0;
9562 v8::HandleScope scope;
9563 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9564 v8::Handle<v8::FunctionTemplate> method_templ =
9565 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9566 v8_str("method_data"),
9567 v8::Signature::New(fun_templ));
9568 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9569 proto_templ->Set(v8_str("method"), method_templ);
9570 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9571 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9572 NULL, NULL, NULL, NULL,
9573 v8::External::Wrap(&interceptor_call_count));
9574 LocalContext context;
9575 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9576 GenerateSomeGarbage();
9577 context->Global()->Set(v8_str("o"), fun->NewInstance());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009578 CompileRun(
Andrei Popescu402d9372010-02-26 13:31:12 +00009579 "o.foo = 17;"
9580 "var receiver = {};"
9581 "receiver.__proto__ = o;"
9582 "var result = 0;"
9583 "var saved_result = 0;"
9584 "for (var i = 0; i < 100; i++) {"
9585 " result = receiver.method(41);"
9586 " if (i == 50) {"
9587 " saved_result = result;"
9588 " o.method = function(x) { return x - 1 };"
9589 " }"
Ben Murdochc7cc0282012-03-05 14:35:55 +00009590 "}");
Andrei Popescu402d9372010-02-26 13:31:12 +00009591 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
9592 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9593 CHECK_GE(interceptor_call_count, 50);
9594}
9595
Steve Block6ded16b2010-05-10 14:33:55 +01009596THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
9597 int interceptor_call_count = 0;
9598 v8::HandleScope scope;
9599 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9600 v8::Handle<v8::FunctionTemplate> method_templ =
9601 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9602 v8_str("method_data"),
9603 v8::Signature::New(fun_templ));
9604 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9605 proto_templ->Set(v8_str("method"), method_templ);
9606 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9607 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9608 NULL, NULL, NULL, NULL,
9609 v8::External::Wrap(&interceptor_call_count));
9610 LocalContext context;
9611 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9612 GenerateSomeGarbage();
9613 context->Global()->Set(v8_str("o"), fun->NewInstance());
9614 v8::TryCatch try_catch;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009615 CompileRun(
Steve Block6ded16b2010-05-10 14:33:55 +01009616 "o.foo = 17;"
9617 "var receiver = {};"
9618 "receiver.__proto__ = o;"
9619 "var result = 0;"
9620 "var saved_result = 0;"
9621 "for (var i = 0; i < 100; i++) {"
9622 " result = receiver.method(41);"
9623 " if (i == 50) {"
9624 " saved_result = result;"
9625 " receiver = 333;"
9626 " }"
Ben Murdochc7cc0282012-03-05 14:35:55 +00009627 "}");
Steve Block6ded16b2010-05-10 14:33:55 +01009628 CHECK(try_catch.HasCaught());
9629 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
9630 try_catch.Exception()->ToString());
9631 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9632 CHECK_GE(interceptor_call_count, 50);
9633}
9634
Andrei Popescu402d9372010-02-26 13:31:12 +00009635THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
9636 int interceptor_call_count = 0;
9637 v8::HandleScope scope;
9638 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9639 v8::Handle<v8::FunctionTemplate> method_templ =
9640 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9641 v8_str("method_data"),
9642 v8::Signature::New(fun_templ));
9643 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9644 proto_templ->Set(v8_str("method"), method_templ);
9645 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9646 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9647 NULL, NULL, NULL, NULL,
9648 v8::External::Wrap(&interceptor_call_count));
9649 LocalContext context;
9650 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9651 GenerateSomeGarbage();
9652 context->Global()->Set(v8_str("o"), fun->NewInstance());
9653 v8::TryCatch try_catch;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009654 CompileRun(
Andrei Popescu402d9372010-02-26 13:31:12 +00009655 "o.foo = 17;"
9656 "var receiver = {};"
9657 "receiver.__proto__ = o;"
9658 "var result = 0;"
9659 "var saved_result = 0;"
9660 "for (var i = 0; i < 100; i++) {"
9661 " result = receiver.method(41);"
9662 " if (i == 50) {"
9663 " saved_result = result;"
9664 " receiver = {method: receiver.method};"
9665 " }"
Ben Murdochc7cc0282012-03-05 14:35:55 +00009666 "}");
Andrei Popescu402d9372010-02-26 13:31:12 +00009667 CHECK(try_catch.HasCaught());
9668 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
9669 try_catch.Exception()->ToString());
9670 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9671 CHECK_GE(interceptor_call_count, 50);
9672}
9673
9674THREADED_TEST(CallICFastApi_TrivialSignature) {
9675 v8::HandleScope scope;
9676 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9677 v8::Handle<v8::FunctionTemplate> method_templ =
9678 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
9679 v8_str("method_data"),
9680 v8::Handle<v8::Signature>());
9681 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9682 proto_templ->Set(v8_str("method"), method_templ);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009683 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
9684 USE(templ);
Andrei Popescu402d9372010-02-26 13:31:12 +00009685 LocalContext context;
9686 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9687 GenerateSomeGarbage();
9688 context->Global()->Set(v8_str("o"), fun->NewInstance());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009689 CompileRun(
Andrei Popescu402d9372010-02-26 13:31:12 +00009690 "var result = 0;"
9691 "for (var i = 0; i < 100; i++) {"
9692 " result = o.method(41);"
Ben Murdochc7cc0282012-03-05 14:35:55 +00009693 "}");
Andrei Popescu402d9372010-02-26 13:31:12 +00009694
9695 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9696}
9697
9698THREADED_TEST(CallICFastApi_SimpleSignature) {
9699 v8::HandleScope scope;
9700 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9701 v8::Handle<v8::FunctionTemplate> method_templ =
9702 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9703 v8_str("method_data"),
9704 v8::Signature::New(fun_templ));
9705 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9706 proto_templ->Set(v8_str("method"), method_templ);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009707 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
9708 CHECK(!templ.IsEmpty());
Andrei Popescu402d9372010-02-26 13:31:12 +00009709 LocalContext context;
9710 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9711 GenerateSomeGarbage();
9712 context->Global()->Set(v8_str("o"), fun->NewInstance());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009713 CompileRun(
Andrei Popescu402d9372010-02-26 13:31:12 +00009714 "o.foo = 17;"
9715 "var receiver = {};"
9716 "receiver.__proto__ = o;"
9717 "var result = 0;"
9718 "for (var i = 0; i < 100; i++) {"
9719 " result = receiver.method(41);"
Ben Murdochc7cc0282012-03-05 14:35:55 +00009720 "}");
Andrei Popescu402d9372010-02-26 13:31:12 +00009721
9722 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9723}
9724
Steve Block6ded16b2010-05-10 14:33:55 +01009725THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) {
Andrei Popescu402d9372010-02-26 13:31:12 +00009726 v8::HandleScope scope;
9727 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9728 v8::Handle<v8::FunctionTemplate> method_templ =
9729 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9730 v8_str("method_data"),
9731 v8::Signature::New(fun_templ));
9732 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9733 proto_templ->Set(v8_str("method"), method_templ);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009734 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
9735 CHECK(!templ.IsEmpty());
Andrei Popescu402d9372010-02-26 13:31:12 +00009736 LocalContext context;
9737 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9738 GenerateSomeGarbage();
9739 context->Global()->Set(v8_str("o"), fun->NewInstance());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009740 CompileRun(
Andrei Popescu402d9372010-02-26 13:31:12 +00009741 "o.foo = 17;"
9742 "var receiver = {};"
9743 "receiver.__proto__ = o;"
9744 "var result = 0;"
9745 "var saved_result = 0;"
9746 "for (var i = 0; i < 100; i++) {"
9747 " result = receiver.method(41);"
9748 " if (i == 50) {"
9749 " saved_result = result;"
9750 " receiver = {method: function(x) { return x - 1 }};"
9751 " }"
Ben Murdochc7cc0282012-03-05 14:35:55 +00009752 "}");
Andrei Popescu402d9372010-02-26 13:31:12 +00009753 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
9754 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9755}
9756
Steve Block6ded16b2010-05-10 14:33:55 +01009757THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) {
9758 v8::HandleScope scope;
9759 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9760 v8::Handle<v8::FunctionTemplate> method_templ =
9761 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9762 v8_str("method_data"),
9763 v8::Signature::New(fun_templ));
9764 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9765 proto_templ->Set(v8_str("method"), method_templ);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009766 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
9767 CHECK(!templ.IsEmpty());
Steve Block6ded16b2010-05-10 14:33:55 +01009768 LocalContext context;
9769 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9770 GenerateSomeGarbage();
9771 context->Global()->Set(v8_str("o"), fun->NewInstance());
9772 v8::TryCatch try_catch;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009773 CompileRun(
Steve Block6ded16b2010-05-10 14:33:55 +01009774 "o.foo = 17;"
9775 "var receiver = {};"
9776 "receiver.__proto__ = o;"
9777 "var result = 0;"
9778 "var saved_result = 0;"
9779 "for (var i = 0; i < 100; i++) {"
9780 " result = receiver.method(41);"
9781 " if (i == 50) {"
9782 " saved_result = result;"
9783 " receiver = 333;"
9784 " }"
Ben Murdochc7cc0282012-03-05 14:35:55 +00009785 "}");
Steve Block6ded16b2010-05-10 14:33:55 +01009786 CHECK(try_catch.HasCaught());
9787 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
9788 try_catch.Exception()->ToString());
9789 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9790}
9791
Leon Clarke4515c472010-02-03 11:58:03 +00009792
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009793v8::Handle<Value> keyed_call_ic_function;
9794
9795static v8::Handle<Value> InterceptorKeyedCallICGetter(
9796 Local<String> name, const AccessorInfo& info) {
9797 ApiTestFuzzer::Fuzz();
9798 if (v8_str("x")->Equals(name)) {
9799 return keyed_call_ic_function;
9800 }
9801 return v8::Handle<Value>();
9802}
9803
9804
9805// Test the case when we stored cacheable lookup into
9806// a stub, but the function name changed (to another cacheable function).
9807THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
9808 v8::HandleScope scope;
9809 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9810 templ->SetNamedPropertyHandler(NoBlockGetterX);
9811 LocalContext context;
9812 context->Global()->Set(v8_str("o"), templ->NewInstance());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009813 CompileRun(
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009814 "proto = new Object();"
9815 "proto.y = function(x) { return x + 1; };"
9816 "proto.z = function(x) { return x - 1; };"
9817 "o.__proto__ = proto;"
9818 "var result = 0;"
9819 "var method = 'y';"
9820 "for (var i = 0; i < 10; i++) {"
9821 " if (i == 5) { method = 'z'; };"
9822 " result += o[method](41);"
Ben Murdochc7cc0282012-03-05 14:35:55 +00009823 "}");
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009824 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9825}
9826
9827
9828// Test the case when we stored cacheable lookup into
9829// a stub, but the function name changed (and the new function is present
9830// both before and after the interceptor in the prototype chain).
9831THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
9832 v8::HandleScope scope;
9833 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9834 templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
9835 LocalContext context;
9836 context->Global()->Set(v8_str("proto1"), templ->NewInstance());
9837 keyed_call_ic_function =
9838 v8_compile("function f(x) { return x - 1; }; f")->Run();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009839 CompileRun(
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009840 "o = new Object();"
9841 "proto2 = new Object();"
9842 "o.y = function(x) { return x + 1; };"
9843 "proto2.y = function(x) { return x + 2; };"
9844 "o.__proto__ = proto1;"
9845 "proto1.__proto__ = proto2;"
9846 "var result = 0;"
9847 "var method = 'x';"
9848 "for (var i = 0; i < 10; i++) {"
9849 " if (i == 5) { method = 'y'; };"
9850 " result += o[method](41);"
Ben Murdochc7cc0282012-03-05 14:35:55 +00009851 "}");
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009852 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9853}
9854
9855
9856// Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
9857// on the global object.
9858THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
9859 v8::HandleScope scope;
9860 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9861 templ->SetNamedPropertyHandler(NoBlockGetterX);
9862 LocalContext context;
9863 context->Global()->Set(v8_str("o"), templ->NewInstance());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009864 CompileRun(
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009865 "function inc(x) { return x + 1; };"
9866 "inc(1);"
9867 "function dec(x) { return x - 1; };"
9868 "dec(1);"
9869 "o.__proto__ = this;"
9870 "this.__proto__.x = inc;"
9871 "this.__proto__.y = dec;"
9872 "var result = 0;"
9873 "var method = 'x';"
9874 "for (var i = 0; i < 10; i++) {"
9875 " if (i == 5) { method = 'y'; };"
9876 " result += o[method](41);"
Ben Murdochc7cc0282012-03-05 14:35:55 +00009877 "}");
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009878 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9879}
9880
9881
9882// Test the case when actual function to call sits on global object.
9883THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
9884 v8::HandleScope scope;
9885 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9886 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9887 LocalContext context;
9888 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9889
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009890 CompileRun(
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009891 "function len(x) { return x.length; };"
9892 "o.__proto__ = this;"
9893 "var m = 'parseFloat';"
9894 "var result = 0;"
9895 "for (var i = 0; i < 10; i++) {"
9896 " if (i == 5) {"
9897 " m = 'len';"
9898 " saved_result = result;"
9899 " };"
9900 " result = o[m]('239');"
Ben Murdochc7cc0282012-03-05 14:35:55 +00009901 "}");
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009902 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
9903 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9904}
9905
9906// Test the map transition before the interceptor.
9907THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
9908 v8::HandleScope scope;
9909 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9910 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9911 LocalContext context;
9912 context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
9913
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009914 CompileRun(
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009915 "var o = new Object();"
9916 "o.__proto__ = proto;"
9917 "o.method = function(x) { return x + 1; };"
9918 "var m = 'method';"
9919 "var result = 0;"
9920 "for (var i = 0; i < 10; i++) {"
9921 " if (i == 5) { o.method = function(x) { return x - 1; }; };"
9922 " result += o[m](41);"
Ben Murdochc7cc0282012-03-05 14:35:55 +00009923 "}");
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009924 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9925}
9926
9927
9928// Test the map transition after the interceptor.
9929THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
9930 v8::HandleScope scope;
9931 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9932 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9933 LocalContext context;
9934 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9935
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009936 CompileRun(
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009937 "var proto = new Object();"
9938 "o.__proto__ = proto;"
9939 "proto.method = function(x) { return x + 1; };"
9940 "var m = 'method';"
9941 "var result = 0;"
9942 "for (var i = 0; i < 10; i++) {"
9943 " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
9944 " result += o[m](41);"
Ben Murdochc7cc0282012-03-05 14:35:55 +00009945 "}");
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009946 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9947}
9948
9949
Steve Blocka7e24c12009-10-30 11:49:00 +00009950static int interceptor_call_count = 0;
9951
9952static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
9953 const AccessorInfo& info) {
9954 ApiTestFuzzer::Fuzz();
9955 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
9956 return call_ic_function2;
9957 }
9958 return v8::Handle<Value>();
9959}
9960
9961
9962// This test should hit load and call ICs for the interceptor case.
9963// Once in a while, the interceptor will reply that a property was not
9964// found in which case we should get a reference error.
9965THREADED_TEST(InterceptorICReferenceErrors) {
9966 v8::HandleScope scope;
9967 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9968 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
9969 LocalContext context(0, templ, v8::Handle<Value>());
9970 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
9971 v8::Handle<Value> value = CompileRun(
9972 "function f() {"
9973 " for (var i = 0; i < 1000; i++) {"
9974 " try { x; } catch(e) { return true; }"
9975 " }"
9976 " return false;"
9977 "};"
9978 "f();");
9979 CHECK_EQ(true, value->BooleanValue());
9980 interceptor_call_count = 0;
9981 value = CompileRun(
9982 "function g() {"
9983 " for (var i = 0; i < 1000; i++) {"
9984 " try { x(42); } catch(e) { return true; }"
9985 " }"
9986 " return false;"
9987 "};"
9988 "g();");
9989 CHECK_EQ(true, value->BooleanValue());
9990}
9991
9992
9993static int interceptor_ic_exception_get_count = 0;
9994
9995static v8::Handle<Value> InterceptorICExceptionGetter(
9996 Local<String> name,
9997 const AccessorInfo& info) {
9998 ApiTestFuzzer::Fuzz();
9999 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
10000 return call_ic_function3;
10001 }
10002 if (interceptor_ic_exception_get_count == 20) {
10003 return v8::ThrowException(v8_num(42));
10004 }
10005 // Do not handle get for properties other than x.
10006 return v8::Handle<Value>();
10007}
10008
10009// Test interceptor load/call IC where the interceptor throws an
10010// exception once in a while.
10011THREADED_TEST(InterceptorICGetterExceptions) {
10012 interceptor_ic_exception_get_count = 0;
10013 v8::HandleScope scope;
10014 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10015 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
10016 LocalContext context(0, templ, v8::Handle<Value>());
10017 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
10018 v8::Handle<Value> value = CompileRun(
10019 "function f() {"
10020 " for (var i = 0; i < 100; i++) {"
10021 " try { x; } catch(e) { return true; }"
10022 " }"
10023 " return false;"
10024 "};"
10025 "f();");
10026 CHECK_EQ(true, value->BooleanValue());
10027 interceptor_ic_exception_get_count = 0;
10028 value = CompileRun(
10029 "function f() {"
10030 " for (var i = 0; i < 100; i++) {"
10031 " try { x(42); } catch(e) { return true; }"
10032 " }"
10033 " return false;"
10034 "};"
10035 "f();");
10036 CHECK_EQ(true, value->BooleanValue());
10037}
10038
10039
10040static int interceptor_ic_exception_set_count = 0;
10041
10042static v8::Handle<Value> InterceptorICExceptionSetter(
10043 Local<String> key, Local<Value> value, const AccessorInfo&) {
10044 ApiTestFuzzer::Fuzz();
10045 if (++interceptor_ic_exception_set_count > 20) {
10046 return v8::ThrowException(v8_num(42));
10047 }
10048 // Do not actually handle setting.
10049 return v8::Handle<Value>();
10050}
10051
10052// Test interceptor store IC where the interceptor throws an exception
10053// once in a while.
10054THREADED_TEST(InterceptorICSetterExceptions) {
10055 interceptor_ic_exception_set_count = 0;
10056 v8::HandleScope scope;
10057 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10058 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
10059 LocalContext context(0, templ, v8::Handle<Value>());
10060 v8::Handle<Value> value = CompileRun(
10061 "function f() {"
10062 " for (var i = 0; i < 100; i++) {"
10063 " try { x = 42; } catch(e) { return true; }"
10064 " }"
10065 " return false;"
10066 "};"
10067 "f();");
10068 CHECK_EQ(true, value->BooleanValue());
10069}
10070
10071
10072// Test that we ignore null interceptors.
10073THREADED_TEST(NullNamedInterceptor) {
10074 v8::HandleScope scope;
10075 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10076 templ->SetNamedPropertyHandler(0);
10077 LocalContext context;
10078 templ->Set("x", v8_num(42));
10079 v8::Handle<v8::Object> obj = templ->NewInstance();
10080 context->Global()->Set(v8_str("obj"), obj);
10081 v8::Handle<Value> value = CompileRun("obj.x");
10082 CHECK(value->IsInt32());
10083 CHECK_EQ(42, value->Int32Value());
10084}
10085
10086
10087// Test that we ignore null interceptors.
10088THREADED_TEST(NullIndexedInterceptor) {
10089 v8::HandleScope scope;
10090 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10091 templ->SetIndexedPropertyHandler(0);
10092 LocalContext context;
10093 templ->Set("42", v8_num(42));
10094 v8::Handle<v8::Object> obj = templ->NewInstance();
10095 context->Global()->Set(v8_str("obj"), obj);
10096 v8::Handle<Value> value = CompileRun("obj[42]");
10097 CHECK(value->IsInt32());
10098 CHECK_EQ(42, value->Int32Value());
10099}
10100
10101
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010010102THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
10103 v8::HandleScope scope;
10104 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
10105 templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
10106 LocalContext env;
10107 env->Global()->Set(v8_str("obj"),
10108 templ->GetFunction()->NewInstance());
10109 ExpectTrue("obj.x === 42");
10110 ExpectTrue("!obj.propertyIsEnumerable('x')");
10111}
10112
10113
Ben Murdoch8b112d22011-06-08 16:22:53 +010010114static Handle<Value> ThrowingGetter(Local<String> name,
10115 const AccessorInfo& info) {
10116 ApiTestFuzzer::Fuzz();
10117 ThrowException(Handle<Value>());
10118 return Undefined();
10119}
10120
10121
10122THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
10123 HandleScope scope;
10124 LocalContext context;
10125
10126 Local<FunctionTemplate> templ = FunctionTemplate::New();
10127 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
10128 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
10129
10130 Local<Object> instance = templ->GetFunction()->NewInstance();
10131
10132 Local<Object> another = Object::New();
10133 another->SetPrototype(instance);
10134
10135 Local<Object> with_js_getter = CompileRun(
10136 "o = {};\n"
10137 "o.__defineGetter__('f', function() { throw undefined; });\n"
10138 "o\n").As<Object>();
10139 CHECK(!with_js_getter.IsEmpty());
10140
10141 TryCatch try_catch;
10142
10143 Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
10144 CHECK(try_catch.HasCaught());
10145 try_catch.Reset();
10146 CHECK(result.IsEmpty());
10147
10148 result = another->GetRealNamedProperty(v8_str("f"));
10149 CHECK(try_catch.HasCaught());
10150 try_catch.Reset();
10151 CHECK(result.IsEmpty());
10152
10153 result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
10154 CHECK(try_catch.HasCaught());
10155 try_catch.Reset();
10156 CHECK(result.IsEmpty());
10157
10158 result = another->Get(v8_str("f"));
10159 CHECK(try_catch.HasCaught());
10160 try_catch.Reset();
10161 CHECK(result.IsEmpty());
10162
10163 result = with_js_getter->GetRealNamedProperty(v8_str("f"));
10164 CHECK(try_catch.HasCaught());
10165 try_catch.Reset();
10166 CHECK(result.IsEmpty());
10167
10168 result = with_js_getter->Get(v8_str("f"));
10169 CHECK(try_catch.HasCaught());
10170 try_catch.Reset();
10171 CHECK(result.IsEmpty());
10172}
10173
10174
10175static Handle<Value> ThrowingCallbackWithTryCatch(const Arguments& args) {
10176 TryCatch try_catch;
10177 // Verboseness is important: it triggers message delivery which can call into
10178 // external code.
10179 try_catch.SetVerbose(true);
10180 CompileRun("throw 'from JS';");
10181 CHECK(try_catch.HasCaught());
10182 CHECK(!i::Isolate::Current()->has_pending_exception());
10183 CHECK(!i::Isolate::Current()->has_scheduled_exception());
10184 return Undefined();
10185}
10186
10187
10188static int call_depth;
10189
10190
10191static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
10192 TryCatch try_catch;
10193}
10194
10195
10196static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
10197 if (--call_depth) CompileRun("throw 'ThrowInJS';");
10198}
10199
10200
10201static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
10202 if (--call_depth) ThrowException(v8_str("ThrowViaApi"));
10203}
10204
10205
10206static void WebKitLike(Handle<Message> message, Handle<Value> data) {
10207 Handle<String> errorMessageString = message->Get();
10208 CHECK(!errorMessageString.IsEmpty());
10209 message->GetStackTrace();
10210 message->GetScriptResourceName();
10211}
10212
10213THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
10214 HandleScope scope;
10215 LocalContext context;
10216
10217 Local<Function> func =
10218 FunctionTemplate::New(ThrowingCallbackWithTryCatch)->GetFunction();
10219 context->Global()->Set(v8_str("func"), func);
10220
10221 MessageCallback callbacks[] =
10222 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
10223 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
10224 MessageCallback callback = callbacks[i];
10225 if (callback != NULL) {
10226 V8::AddMessageListener(callback);
10227 }
Ben Murdoch257744e2011-11-30 15:57:28 +000010228 // Some small number to control number of times message handler should
10229 // throw an exception.
Ben Murdoch8b112d22011-06-08 16:22:53 +010010230 call_depth = 5;
10231 ExpectFalse(
10232 "var thrown = false;\n"
10233 "try { func(); } catch(e) { thrown = true; }\n"
10234 "thrown\n");
10235 if (callback != NULL) {
10236 V8::RemoveMessageListeners(callback);
10237 }
10238 }
10239}
10240
10241
Steve Blocka7e24c12009-10-30 11:49:00 +000010242static v8::Handle<Value> ParentGetter(Local<String> name,
10243 const AccessorInfo& info) {
10244 ApiTestFuzzer::Fuzz();
10245 return v8_num(1);
10246}
10247
10248
10249static v8::Handle<Value> ChildGetter(Local<String> name,
10250 const AccessorInfo& info) {
10251 ApiTestFuzzer::Fuzz();
10252 return v8_num(42);
10253}
10254
10255
10256THREADED_TEST(Overriding) {
10257 v8::HandleScope scope;
10258 LocalContext context;
10259
10260 // Parent template.
10261 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
10262 Local<ObjectTemplate> parent_instance_templ =
10263 parent_templ->InstanceTemplate();
10264 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
10265
10266 // Template that inherits from the parent template.
10267 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
10268 Local<ObjectTemplate> child_instance_templ =
10269 child_templ->InstanceTemplate();
10270 child_templ->Inherit(parent_templ);
10271 // Override 'f'. The child version of 'f' should get called for child
10272 // instances.
10273 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
10274 // Add 'g' twice. The 'g' added last should get called for instances.
10275 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
10276 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
10277
10278 // Add 'h' as an accessor to the proto template with ReadOnly attributes
10279 // so 'h' can be shadowed on the instance object.
10280 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
10281 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
10282 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
10283
10284 // Add 'i' as an accessor to the instance template with ReadOnly attributes
10285 // but the attribute does not have effect because it is duplicated with
10286 // NULL setter.
10287 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
10288 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
10289
10290
10291
10292 // Instantiate the child template.
10293 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
10294
10295 // Check that the child function overrides the parent one.
10296 context->Global()->Set(v8_str("o"), instance);
10297 Local<Value> value = v8_compile("o.f")->Run();
10298 // Check that the 'g' that was added last is hit.
10299 CHECK_EQ(42, value->Int32Value());
10300 value = v8_compile("o.g")->Run();
10301 CHECK_EQ(42, value->Int32Value());
10302
10303 // Check 'h' can be shadowed.
10304 value = v8_compile("o.h = 3; o.h")->Run();
10305 CHECK_EQ(3, value->Int32Value());
10306
10307 // Check 'i' is cannot be shadowed or changed.
10308 value = v8_compile("o.i = 3; o.i")->Run();
10309 CHECK_EQ(42, value->Int32Value());
10310}
10311
10312
10313static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
10314 ApiTestFuzzer::Fuzz();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010315 return v8::Boolean::New(args.IsConstructCall());
Steve Blocka7e24c12009-10-30 11:49:00 +000010316}
10317
10318
10319THREADED_TEST(IsConstructCall) {
10320 v8::HandleScope scope;
10321
10322 // Function template with call handler.
10323 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
10324 templ->SetCallHandler(IsConstructHandler);
10325
10326 LocalContext context;
10327
10328 context->Global()->Set(v8_str("f"), templ->GetFunction());
10329 Local<Value> value = v8_compile("f()")->Run();
10330 CHECK(!value->BooleanValue());
10331 value = v8_compile("new f()")->Run();
10332 CHECK(value->BooleanValue());
10333}
10334
10335
10336THREADED_TEST(ObjectProtoToString) {
10337 v8::HandleScope scope;
10338 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
10339 templ->SetClassName(v8_str("MyClass"));
10340
10341 LocalContext context;
10342
10343 Local<String> customized_tostring = v8_str("customized toString");
10344
10345 // Replace Object.prototype.toString
10346 v8_compile("Object.prototype.toString = function() {"
10347 " return 'customized toString';"
10348 "}")->Run();
10349
10350 // Normal ToString call should call replaced Object.prototype.toString
10351 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
10352 Local<String> value = instance->ToString();
10353 CHECK(value->IsString() && value->Equals(customized_tostring));
10354
10355 // ObjectProtoToString should not call replace toString function.
10356 value = instance->ObjectProtoToString();
10357 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
10358
10359 // Check global
10360 value = context->Global()->ObjectProtoToString();
10361 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
10362
10363 // Check ordinary object
10364 Local<Value> object = v8_compile("new Object()")->Run();
Steve Block6ded16b2010-05-10 14:33:55 +010010365 value = object.As<v8::Object>()->ObjectProtoToString();
Steve Blocka7e24c12009-10-30 11:49:00 +000010366 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
10367}
10368
10369
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -080010370THREADED_TEST(ObjectGetConstructorName) {
10371 v8::HandleScope scope;
10372 LocalContext context;
10373 v8_compile("function Parent() {};"
10374 "function Child() {};"
10375 "Child.prototype = new Parent();"
10376 "var outer = { inner: function() { } };"
10377 "var p = new Parent();"
10378 "var c = new Child();"
10379 "var x = new outer.inner();")->Run();
10380
10381 Local<v8::Value> p = context->Global()->Get(v8_str("p"));
10382 CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
10383 v8_str("Parent")));
10384
10385 Local<v8::Value> c = context->Global()->Get(v8_str("c"));
10386 CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
10387 v8_str("Child")));
10388
10389 Local<v8::Value> x = context->Global()->Get(v8_str("x"));
10390 CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
10391 v8_str("outer.inner")));
10392}
10393
10394
Steve Blocka7e24c12009-10-30 11:49:00 +000010395bool ApiTestFuzzer::fuzzing_ = false;
Steve Block8defd9f2010-07-08 12:39:36 +010010396i::Semaphore* ApiTestFuzzer::all_tests_done_=
10397 i::OS::CreateSemaphore(0);
Steve Blocka7e24c12009-10-30 11:49:00 +000010398int ApiTestFuzzer::active_tests_;
10399int ApiTestFuzzer::tests_being_run_;
10400int ApiTestFuzzer::current_;
10401
10402
10403// We are in a callback and want to switch to another thread (if we
10404// are currently running the thread fuzzing test).
10405void ApiTestFuzzer::Fuzz() {
10406 if (!fuzzing_) return;
10407 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
10408 test->ContextSwitch();
10409}
10410
10411
10412// Let the next thread go. Since it is also waiting on the V8 lock it may
10413// not start immediately.
10414bool ApiTestFuzzer::NextThread() {
10415 int test_position = GetNextTestNumber();
Steve Blockd0582a62009-12-15 09:54:21 +000010416 const char* test_name = RegisterThreadedTest::nth(current_)->name();
Steve Blocka7e24c12009-10-30 11:49:00 +000010417 if (test_position == current_) {
Steve Blockd0582a62009-12-15 09:54:21 +000010418 if (kLogThreading)
10419 printf("Stay with %s\n", test_name);
Steve Blocka7e24c12009-10-30 11:49:00 +000010420 return false;
10421 }
Steve Blockd0582a62009-12-15 09:54:21 +000010422 if (kLogThreading) {
10423 printf("Switch from %s to %s\n",
10424 test_name,
10425 RegisterThreadedTest::nth(test_position)->name());
10426 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010427 current_ = test_position;
10428 RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
10429 return true;
10430}
10431
10432
10433void ApiTestFuzzer::Run() {
10434 // When it is our turn...
10435 gate_->Wait();
10436 {
10437 // ... get the V8 lock and start running the test.
10438 v8::Locker locker;
10439 CallTest();
10440 }
10441 // This test finished.
10442 active_ = false;
10443 active_tests_--;
10444 // If it was the last then signal that fact.
10445 if (active_tests_ == 0) {
10446 all_tests_done_->Signal();
10447 } else {
10448 // Otherwise select a new test and start that.
10449 NextThread();
10450 }
10451}
10452
10453
10454static unsigned linear_congruential_generator;
10455
10456
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010457void ApiTestFuzzer::SetUp(PartOfTest part) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010458 linear_congruential_generator = i::FLAG_testing_prng_seed;
10459 fuzzing_ = true;
Ben Murdoch257744e2011-11-30 15:57:28 +000010460 int count = RegisterThreadedTest::count();
10461 int start = count * part / (LAST_PART + 1);
10462 int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
10463 active_tests_ = tests_being_run_ = end - start + 1;
Steve Blocka7e24c12009-10-30 11:49:00 +000010464 for (int i = 0; i < tests_being_run_; i++) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010465 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
Steve Blocka7e24c12009-10-30 11:49:00 +000010466 }
10467 for (int i = 0; i < active_tests_; i++) {
10468 RegisterThreadedTest::nth(i)->fuzzer_->Start();
10469 }
10470}
10471
10472
10473static void CallTestNumber(int test_number) {
10474 (RegisterThreadedTest::nth(test_number)->callback())();
10475}
10476
10477
10478void ApiTestFuzzer::RunAllTests() {
10479 // Set off the first test.
10480 current_ = -1;
10481 NextThread();
10482 // Wait till they are all done.
10483 all_tests_done_->Wait();
10484}
10485
10486
10487int ApiTestFuzzer::GetNextTestNumber() {
10488 int next_test;
10489 do {
10490 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
10491 linear_congruential_generator *= 1664525u;
10492 linear_congruential_generator += 1013904223u;
10493 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
10494 return next_test;
10495}
10496
10497
10498void ApiTestFuzzer::ContextSwitch() {
10499 // If the new thread is the same as the current thread there is nothing to do.
10500 if (NextThread()) {
10501 // Now it can start.
10502 v8::Unlocker unlocker;
10503 // Wait till someone starts us again.
10504 gate_->Wait();
10505 // And we're off.
10506 }
10507}
10508
10509
10510void ApiTestFuzzer::TearDown() {
10511 fuzzing_ = false;
10512 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
10513 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
10514 if (fuzzer != NULL) fuzzer->Join();
10515 }
10516}
10517
10518
10519// Lets not be needlessly self-referential.
10520TEST(Threading) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010521 ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
Steve Blocka7e24c12009-10-30 11:49:00 +000010522 ApiTestFuzzer::RunAllTests();
10523 ApiTestFuzzer::TearDown();
10524}
10525
10526TEST(Threading2) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010527 ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
Steve Blocka7e24c12009-10-30 11:49:00 +000010528 ApiTestFuzzer::RunAllTests();
10529 ApiTestFuzzer::TearDown();
10530}
10531
Ben Murdoch257744e2011-11-30 15:57:28 +000010532TEST(Threading3) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010533 ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
Ben Murdoch257744e2011-11-30 15:57:28 +000010534 ApiTestFuzzer::RunAllTests();
10535 ApiTestFuzzer::TearDown();
10536}
10537
10538TEST(Threading4) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010539 ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
Ben Murdoch257744e2011-11-30 15:57:28 +000010540 ApiTestFuzzer::RunAllTests();
10541 ApiTestFuzzer::TearDown();
10542}
Steve Blocka7e24c12009-10-30 11:49:00 +000010543
10544void ApiTestFuzzer::CallTest() {
Steve Blockd0582a62009-12-15 09:54:21 +000010545 if (kLogThreading)
10546 printf("Start test %d\n", test_number_);
Steve Blocka7e24c12009-10-30 11:49:00 +000010547 CallTestNumber(test_number_);
Steve Blockd0582a62009-12-15 09:54:21 +000010548 if (kLogThreading)
10549 printf("End test %d\n", test_number_);
Steve Blocka7e24c12009-10-30 11:49:00 +000010550}
10551
10552
10553static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
10554 CHECK(v8::Locker::IsLocked());
10555 ApiTestFuzzer::Fuzz();
10556 v8::Unlocker unlocker;
10557 const char* code = "throw 7;";
10558 {
10559 v8::Locker nested_locker;
10560 v8::HandleScope scope;
10561 v8::Handle<Value> exception;
10562 { v8::TryCatch try_catch;
10563 v8::Handle<Value> value = CompileRun(code);
10564 CHECK(value.IsEmpty());
10565 CHECK(try_catch.HasCaught());
10566 // Make sure to wrap the exception in a new handle because
10567 // the handle returned from the TryCatch is destroyed
10568 // when the TryCatch is destroyed.
10569 exception = Local<Value>::New(try_catch.Exception());
10570 }
10571 return v8::ThrowException(exception);
10572 }
10573}
10574
10575
10576static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
10577 CHECK(v8::Locker::IsLocked());
10578 ApiTestFuzzer::Fuzz();
10579 v8::Unlocker unlocker;
10580 const char* code = "throw 7;";
10581 {
10582 v8::Locker nested_locker;
10583 v8::HandleScope scope;
10584 v8::Handle<Value> value = CompileRun(code);
10585 CHECK(value.IsEmpty());
10586 return v8_str("foo");
10587 }
10588}
10589
10590
10591// These are locking tests that don't need to be run again
10592// as part of the locking aggregation tests.
10593TEST(NestedLockers) {
10594 v8::Locker locker;
10595 CHECK(v8::Locker::IsLocked());
10596 v8::HandleScope scope;
10597 LocalContext env;
10598 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
10599 Local<Function> fun = fun_templ->GetFunction();
10600 env->Global()->Set(v8_str("throw_in_js"), fun);
10601 Local<Script> script = v8_compile("(function () {"
10602 " try {"
10603 " throw_in_js();"
10604 " return 42;"
10605 " } catch (e) {"
10606 " return e * 13;"
10607 " }"
10608 "})();");
10609 CHECK_EQ(91, script->Run()->Int32Value());
10610}
10611
10612
10613// These are locking tests that don't need to be run again
10614// as part of the locking aggregation tests.
10615TEST(NestedLockersNoTryCatch) {
10616 v8::Locker locker;
10617 v8::HandleScope scope;
10618 LocalContext env;
10619 Local<v8::FunctionTemplate> fun_templ =
10620 v8::FunctionTemplate::New(ThrowInJSNoCatch);
10621 Local<Function> fun = fun_templ->GetFunction();
10622 env->Global()->Set(v8_str("throw_in_js"), fun);
10623 Local<Script> script = v8_compile("(function () {"
10624 " try {"
10625 " throw_in_js();"
10626 " return 42;"
10627 " } catch (e) {"
10628 " return e * 13;"
10629 " }"
10630 "})();");
10631 CHECK_EQ(91, script->Run()->Int32Value());
10632}
10633
10634
10635THREADED_TEST(RecursiveLocking) {
10636 v8::Locker locker;
10637 {
10638 v8::Locker locker2;
10639 CHECK(v8::Locker::IsLocked());
10640 }
10641}
10642
10643
10644static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
10645 ApiTestFuzzer::Fuzz();
10646 v8::Unlocker unlocker;
10647 return v8::Undefined();
10648}
10649
10650
10651THREADED_TEST(LockUnlockLock) {
10652 {
10653 v8::Locker locker;
10654 v8::HandleScope scope;
10655 LocalContext env;
10656 Local<v8::FunctionTemplate> fun_templ =
10657 v8::FunctionTemplate::New(UnlockForAMoment);
10658 Local<Function> fun = fun_templ->GetFunction();
10659 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
10660 Local<Script> script = v8_compile("(function () {"
10661 " unlock_for_a_moment();"
10662 " return 42;"
10663 "})();");
10664 CHECK_EQ(42, script->Run()->Int32Value());
10665 }
10666 {
10667 v8::Locker locker;
10668 v8::HandleScope scope;
10669 LocalContext env;
10670 Local<v8::FunctionTemplate> fun_templ =
10671 v8::FunctionTemplate::New(UnlockForAMoment);
10672 Local<Function> fun = fun_templ->GetFunction();
10673 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
10674 Local<Script> script = v8_compile("(function () {"
10675 " unlock_for_a_moment();"
10676 " return 42;"
10677 "})();");
10678 CHECK_EQ(42, script->Run()->Int32Value());
10679 }
10680}
10681
10682
Leon Clarked91b9f72010-01-27 17:25:45 +000010683static int GetGlobalObjectsCount() {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010684 i::Isolate::Current()->heap()->EnsureHeapIsIterable();
Leon Clarkeeab96aa2010-01-27 16:31:12 +000010685 int count = 0;
Steve Block8defd9f2010-07-08 12:39:36 +010010686 i::HeapIterator it;
Leon Clarked91b9f72010-01-27 17:25:45 +000010687 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
10688 if (object->IsJSGlobalObject()) count++;
10689 return count;
10690}
10691
10692
Ben Murdochf87a2032010-10-22 12:50:53 +010010693static void CheckSurvivingGlobalObjectsCount(int expected) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010694 // We need to collect all garbage twice to be sure that everything
10695 // has been collected. This is because inline caches are cleared in
10696 // the first garbage collection but some of the maps have already
10697 // been marked at that point. Therefore some of the maps are not
10698 // collected until the second garbage collection.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010699 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
10700 HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
Leon Clarked91b9f72010-01-27 17:25:45 +000010701 int count = GetGlobalObjectsCount();
Steve Blocka7e24c12009-10-30 11:49:00 +000010702#ifdef DEBUG
Steve Block44f0eee2011-05-26 01:26:41 +010010703 if (count != expected) HEAP->TracePathToGlobal();
Steve Blocka7e24c12009-10-30 11:49:00 +000010704#endif
Ben Murdochf87a2032010-10-22 12:50:53 +010010705 CHECK_EQ(expected, count);
Steve Blocka7e24c12009-10-30 11:49:00 +000010706}
10707
10708
10709TEST(DontLeakGlobalObjects) {
10710 // Regression test for issues 1139850 and 1174891.
10711
10712 v8::V8::Initialize();
10713
Steve Blocka7e24c12009-10-30 11:49:00 +000010714 for (int i = 0; i < 5; i++) {
10715 { v8::HandleScope scope;
10716 LocalContext context;
10717 }
Ben Murdochf87a2032010-10-22 12:50:53 +010010718 CheckSurvivingGlobalObjectsCount(0);
Steve Blocka7e24c12009-10-30 11:49:00 +000010719
10720 { v8::HandleScope scope;
10721 LocalContext context;
10722 v8_compile("Date")->Run();
10723 }
Ben Murdochf87a2032010-10-22 12:50:53 +010010724 CheckSurvivingGlobalObjectsCount(0);
Steve Blocka7e24c12009-10-30 11:49:00 +000010725
10726 { v8::HandleScope scope;
10727 LocalContext context;
10728 v8_compile("/aaa/")->Run();
10729 }
Ben Murdochf87a2032010-10-22 12:50:53 +010010730 CheckSurvivingGlobalObjectsCount(0);
Steve Blocka7e24c12009-10-30 11:49:00 +000010731
10732 { v8::HandleScope scope;
10733 const char* extension_list[] = { "v8/gc" };
10734 v8::ExtensionConfiguration extensions(1, extension_list);
10735 LocalContext context(&extensions);
10736 v8_compile("gc();")->Run();
10737 }
Ben Murdochf87a2032010-10-22 12:50:53 +010010738 CheckSurvivingGlobalObjectsCount(0);
Steve Blocka7e24c12009-10-30 11:49:00 +000010739 }
10740}
10741
10742
10743v8::Persistent<v8::Object> some_object;
10744v8::Persistent<v8::Object> bad_handle;
10745
Kristian Monsen50ef84f2010-07-29 15:18:00 +010010746void NewPersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010747 v8::HandleScope scope;
10748 bad_handle = v8::Persistent<v8::Object>::New(some_object);
Kristian Monsen50ef84f2010-07-29 15:18:00 +010010749 handle.Dispose();
Steve Blocka7e24c12009-10-30 11:49:00 +000010750}
10751
10752
10753THREADED_TEST(NewPersistentHandleFromWeakCallback) {
10754 LocalContext context;
10755
10756 v8::Persistent<v8::Object> handle1, handle2;
10757 {
10758 v8::HandleScope scope;
10759 some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
10760 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
10761 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
10762 }
10763 // Note: order is implementation dependent alas: currently
10764 // global handle nodes are processed by PostGarbageCollectionProcessing
10765 // in reverse allocation order, so if second allocated handle is deleted,
10766 // weak callback of the first handle would be able to 'reallocate' it.
10767 handle1.MakeWeak(NULL, NewPersistentHandleCallback);
10768 handle2.Dispose();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010769 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +000010770}
10771
10772
10773v8::Persistent<v8::Object> to_be_disposed;
10774
10775void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
10776 to_be_disposed.Dispose();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010777 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Kristian Monsen50ef84f2010-07-29 15:18:00 +010010778 handle.Dispose();
Steve Blocka7e24c12009-10-30 11:49:00 +000010779}
10780
10781
10782THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
10783 LocalContext context;
10784
10785 v8::Persistent<v8::Object> handle1, handle2;
10786 {
10787 v8::HandleScope scope;
10788 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
10789 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
10790 }
10791 handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
10792 to_be_disposed = handle2;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010793 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +000010794}
10795
Steve Blockd0582a62009-12-15 09:54:21 +000010796void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
10797 handle.Dispose();
10798}
10799
10800void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
10801 v8::HandleScope scope;
10802 v8::Persistent<v8::Object>::New(v8::Object::New());
Kristian Monsen50ef84f2010-07-29 15:18:00 +010010803 handle.Dispose();
Steve Blockd0582a62009-12-15 09:54:21 +000010804}
10805
10806
10807THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
10808 LocalContext context;
10809
10810 v8::Persistent<v8::Object> handle1, handle2, handle3;
10811 {
10812 v8::HandleScope scope;
10813 handle3 = v8::Persistent<v8::Object>::New(v8::Object::New());
10814 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
10815 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
10816 }
10817 handle2.MakeWeak(NULL, DisposingCallback);
10818 handle3.MakeWeak(NULL, HandleCreatingCallback);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010819 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blockd0582a62009-12-15 09:54:21 +000010820}
10821
Steve Blocka7e24c12009-10-30 11:49:00 +000010822
10823THREADED_TEST(CheckForCrossContextObjectLiterals) {
10824 v8::V8::Initialize();
10825
10826 const int nof = 2;
10827 const char* sources[nof] = {
10828 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
10829 "Object()"
10830 };
10831
10832 for (int i = 0; i < nof; i++) {
10833 const char* source = sources[i];
10834 { v8::HandleScope scope;
10835 LocalContext context;
10836 CompileRun(source);
10837 }
10838 { v8::HandleScope scope;
10839 LocalContext context;
10840 CompileRun(source);
10841 }
10842 }
10843}
10844
10845
10846static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
10847 v8::HandleScope inner;
10848 env->Enter();
10849 v8::Handle<Value> three = v8_num(3);
10850 v8::Handle<Value> value = inner.Close(three);
10851 env->Exit();
10852 return value;
10853}
10854
10855
10856THREADED_TEST(NestedHandleScopeAndContexts) {
10857 v8::HandleScope outer;
10858 v8::Persistent<Context> env = Context::New();
10859 env->Enter();
10860 v8::Handle<Value> value = NestedScope(env);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010861 v8::Handle<String> str(value->ToString());
10862 CHECK(!str.IsEmpty());
Steve Blocka7e24c12009-10-30 11:49:00 +000010863 env->Exit();
10864 env.Dispose();
10865}
10866
10867
10868THREADED_TEST(ExternalAllocatedMemory) {
10869 v8::HandleScope outer;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010870 v8::Persistent<Context> env(Context::New());
10871 CHECK(!env.IsEmpty());
Steve Blocka7e24c12009-10-30 11:49:00 +000010872 const int kSize = 1024*1024;
10873 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
10874 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
10875}
10876
10877
10878THREADED_TEST(DisposeEnteredContext) {
10879 v8::HandleScope scope;
10880 LocalContext outer;
10881 { v8::Persistent<v8::Context> inner = v8::Context::New();
10882 inner->Enter();
10883 inner.Dispose();
10884 inner.Clear();
10885 inner->Exit();
10886 }
10887}
10888
10889
10890// Regression test for issue 54, object templates with internal fields
10891// but no accessors or interceptors did not get their internal field
10892// count set on instances.
10893THREADED_TEST(Regress54) {
10894 v8::HandleScope outer;
10895 LocalContext context;
10896 static v8::Persistent<v8::ObjectTemplate> templ;
10897 if (templ.IsEmpty()) {
10898 v8::HandleScope inner;
10899 v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
10900 local->SetInternalFieldCount(1);
10901 templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
10902 }
10903 v8::Handle<v8::Object> result = templ->NewInstance();
10904 CHECK_EQ(1, result->InternalFieldCount());
10905}
10906
10907
10908// If part of the threaded tests, this test makes ThreadingTest fail
10909// on mac.
10910TEST(CatchStackOverflow) {
10911 v8::HandleScope scope;
10912 LocalContext context;
10913 v8::TryCatch try_catch;
10914 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
10915 "function f() {"
10916 " return f();"
10917 "}"
10918 ""
10919 "f();"));
10920 v8::Handle<v8::Value> result = script->Run();
10921 CHECK(result.IsEmpty());
10922}
10923
10924
10925static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
10926 const char* resource_name,
10927 int line_offset) {
10928 v8::HandleScope scope;
10929 v8::TryCatch try_catch;
10930 v8::Handle<v8::Value> result = script->Run();
10931 CHECK(result.IsEmpty());
10932 CHECK(try_catch.HasCaught());
10933 v8::Handle<v8::Message> message = try_catch.Message();
10934 CHECK(!message.IsEmpty());
10935 CHECK_EQ(10 + line_offset, message->GetLineNumber());
10936 CHECK_EQ(91, message->GetStartPosition());
10937 CHECK_EQ(92, message->GetEndPosition());
10938 CHECK_EQ(2, message->GetStartColumn());
10939 CHECK_EQ(3, message->GetEndColumn());
10940 v8::String::AsciiValue line(message->GetSourceLine());
10941 CHECK_EQ(" throw 'nirk';", *line);
10942 v8::String::AsciiValue name(message->GetScriptResourceName());
10943 CHECK_EQ(resource_name, *name);
10944}
10945
10946
10947THREADED_TEST(TryCatchSourceInfo) {
10948 v8::HandleScope scope;
10949 LocalContext context;
10950 v8::Handle<v8::String> source = v8::String::New(
10951 "function Foo() {\n"
10952 " return Bar();\n"
10953 "}\n"
10954 "\n"
10955 "function Bar() {\n"
10956 " return Baz();\n"
10957 "}\n"
10958 "\n"
10959 "function Baz() {\n"
10960 " throw 'nirk';\n"
10961 "}\n"
10962 "\n"
10963 "Foo();\n");
10964
10965 const char* resource_name;
10966 v8::Handle<v8::Script> script;
10967 resource_name = "test.js";
10968 script = v8::Script::Compile(source, v8::String::New(resource_name));
10969 CheckTryCatchSourceInfo(script, resource_name, 0);
10970
10971 resource_name = "test1.js";
10972 v8::ScriptOrigin origin1(v8::String::New(resource_name));
10973 script = v8::Script::Compile(source, &origin1);
10974 CheckTryCatchSourceInfo(script, resource_name, 0);
10975
10976 resource_name = "test2.js";
10977 v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
10978 script = v8::Script::Compile(source, &origin2);
10979 CheckTryCatchSourceInfo(script, resource_name, 7);
10980}
10981
10982
10983THREADED_TEST(CompilationCache) {
10984 v8::HandleScope scope;
10985 LocalContext context;
10986 v8::Handle<v8::String> source0 = v8::String::New("1234");
10987 v8::Handle<v8::String> source1 = v8::String::New("1234");
10988 v8::Handle<v8::Script> script0 =
10989 v8::Script::Compile(source0, v8::String::New("test.js"));
10990 v8::Handle<v8::Script> script1 =
10991 v8::Script::Compile(source1, v8::String::New("test.js"));
10992 v8::Handle<v8::Script> script2 =
10993 v8::Script::Compile(source0); // different origin
10994 CHECK_EQ(1234, script0->Run()->Int32Value());
10995 CHECK_EQ(1234, script1->Run()->Int32Value());
10996 CHECK_EQ(1234, script2->Run()->Int32Value());
10997}
10998
10999
11000static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
11001 ApiTestFuzzer::Fuzz();
11002 return v8_num(42);
11003}
11004
11005
11006THREADED_TEST(CallbackFunctionName) {
11007 v8::HandleScope scope;
11008 LocalContext context;
11009 Local<ObjectTemplate> t = ObjectTemplate::New();
11010 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
11011 context->Global()->Set(v8_str("obj"), t->NewInstance());
11012 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
11013 CHECK(value->IsString());
11014 v8::String::AsciiValue name(value);
11015 CHECK_EQ("asdf", *name);
11016}
11017
11018
11019THREADED_TEST(DateAccess) {
11020 v8::HandleScope scope;
11021 LocalContext context;
11022 v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
11023 CHECK(date->IsDate());
Steve Block6ded16b2010-05-10 14:33:55 +010011024 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue());
Steve Blocka7e24c12009-10-30 11:49:00 +000011025}
11026
11027
11028void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
Steve Block6ded16b2010-05-10 14:33:55 +010011029 v8::Handle<v8::Object> obj = val.As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +000011030 v8::Handle<v8::Array> props = obj->GetPropertyNames();
11031 CHECK_EQ(elmc, props->Length());
11032 for (int i = 0; i < elmc; i++) {
11033 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
11034 CHECK_EQ(elmv[i], *elm);
11035 }
11036}
11037
11038
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011039void CheckOwnProperties(v8::Handle<v8::Value> val,
11040 int elmc,
11041 const char* elmv[]) {
11042 v8::Handle<v8::Object> obj = val.As<v8::Object>();
11043 v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
11044 CHECK_EQ(elmc, props->Length());
11045 for (int i = 0; i < elmc; i++) {
11046 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
11047 CHECK_EQ(elmv[i], *elm);
11048 }
11049}
11050
11051
Steve Blocka7e24c12009-10-30 11:49:00 +000011052THREADED_TEST(PropertyEnumeration) {
11053 v8::HandleScope scope;
11054 LocalContext context;
11055 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
11056 "var result = [];"
11057 "result[0] = {};"
11058 "result[1] = {a: 1, b: 2};"
11059 "result[2] = [1, 2, 3];"
11060 "var proto = {x: 1, y: 2, z: 3};"
11061 "var x = { __proto__: proto, w: 0, z: 1 };"
11062 "result[3] = x;"
11063 "result;"))->Run();
Steve Block6ded16b2010-05-10 14:33:55 +010011064 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +000011065 CHECK_EQ(4, elms->Length());
11066 int elmc0 = 0;
11067 const char** elmv0 = NULL;
11068 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011069 CheckOwnProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
Steve Blocka7e24c12009-10-30 11:49:00 +000011070 int elmc1 = 2;
11071 const char* elmv1[] = {"a", "b"};
11072 CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011073 CheckOwnProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
Steve Blocka7e24c12009-10-30 11:49:00 +000011074 int elmc2 = 3;
11075 const char* elmv2[] = {"0", "1", "2"};
11076 CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011077 CheckOwnProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
Steve Blocka7e24c12009-10-30 11:49:00 +000011078 int elmc3 = 4;
11079 const char* elmv3[] = {"w", "z", "x", "y"};
11080 CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011081 int elmc4 = 2;
11082 const char* elmv4[] = {"w", "z"};
11083 CheckOwnProperties(elms->Get(v8::Integer::New(3)), elmc4, elmv4);
Steve Blocka7e24c12009-10-30 11:49:00 +000011084}
11085
Steve Block44f0eee2011-05-26 01:26:41 +010011086THREADED_TEST(PropertyEnumeration2) {
11087 v8::HandleScope scope;
11088 LocalContext context;
11089 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
11090 "var result = [];"
11091 "result[0] = {};"
11092 "result[1] = {a: 1, b: 2};"
11093 "result[2] = [1, 2, 3];"
11094 "var proto = {x: 1, y: 2, z: 3};"
11095 "var x = { __proto__: proto, w: 0, z: 1 };"
11096 "result[3] = x;"
11097 "result;"))->Run();
11098 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
11099 CHECK_EQ(4, elms->Length());
11100 int elmc0 = 0;
11101 const char** elmv0 = NULL;
11102 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
11103
11104 v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(0));
11105 v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
11106 CHECK_EQ(0, props->Length());
11107 for (uint32_t i = 0; i < props->Length(); i++) {
11108 printf("p[%d]\n", i);
11109 }
11110}
Steve Blocka7e24c12009-10-30 11:49:00 +000011111
Steve Blocka7e24c12009-10-30 11:49:00 +000011112static bool NamedSetAccessBlocker(Local<v8::Object> obj,
11113 Local<Value> name,
11114 v8::AccessType type,
11115 Local<Value> data) {
11116 return type != v8::ACCESS_SET;
11117}
11118
11119
11120static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
11121 uint32_t key,
11122 v8::AccessType type,
11123 Local<Value> data) {
11124 return type != v8::ACCESS_SET;
11125}
11126
11127
11128THREADED_TEST(DisableAccessChecksWhileConfiguring) {
11129 v8::HandleScope scope;
11130 LocalContext context;
11131 Local<ObjectTemplate> templ = ObjectTemplate::New();
11132 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
11133 IndexedSetAccessBlocker);
11134 templ->Set(v8_str("x"), v8::True());
11135 Local<v8::Object> instance = templ->NewInstance();
11136 context->Global()->Set(v8_str("obj"), instance);
11137 Local<Value> value = CompileRun("obj.x");
11138 CHECK(value->BooleanValue());
11139}
11140
11141
11142static bool NamedGetAccessBlocker(Local<v8::Object> obj,
11143 Local<Value> name,
11144 v8::AccessType type,
11145 Local<Value> data) {
11146 return false;
11147}
11148
11149
11150static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
11151 uint32_t key,
11152 v8::AccessType type,
11153 Local<Value> data) {
11154 return false;
11155}
11156
11157
11158
11159THREADED_TEST(AccessChecksReenabledCorrectly) {
11160 v8::HandleScope scope;
11161 LocalContext context;
11162 Local<ObjectTemplate> templ = ObjectTemplate::New();
11163 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
11164 IndexedGetAccessBlocker);
11165 templ->Set(v8_str("a"), v8_str("a"));
11166 // Add more than 8 (see kMaxFastProperties) properties
11167 // so that the constructor will force copying map.
11168 // Cannot sprintf, gcc complains unsafety.
11169 char buf[4];
11170 for (char i = '0'; i <= '9' ; i++) {
11171 buf[0] = i;
11172 for (char j = '0'; j <= '9'; j++) {
11173 buf[1] = j;
11174 for (char k = '0'; k <= '9'; k++) {
11175 buf[2] = k;
11176 buf[3] = 0;
11177 templ->Set(v8_str(buf), v8::Number::New(k));
11178 }
11179 }
11180 }
11181
11182 Local<v8::Object> instance_1 = templ->NewInstance();
11183 context->Global()->Set(v8_str("obj_1"), instance_1);
11184
11185 Local<Value> value_1 = CompileRun("obj_1.a");
11186 CHECK(value_1->IsUndefined());
11187
11188 Local<v8::Object> instance_2 = templ->NewInstance();
11189 context->Global()->Set(v8_str("obj_2"), instance_2);
11190
11191 Local<Value> value_2 = CompileRun("obj_2.a");
11192 CHECK(value_2->IsUndefined());
11193}
11194
11195
11196// This tests that access check information remains on the global
11197// object template when creating contexts.
11198THREADED_TEST(AccessControlRepeatedContextCreation) {
11199 v8::HandleScope handle_scope;
11200 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
11201 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
11202 IndexedSetAccessBlocker);
11203 i::Handle<i::ObjectTemplateInfo> internal_template =
11204 v8::Utils::OpenHandle(*global_template);
11205 CHECK(!internal_template->constructor()->IsUndefined());
11206 i::Handle<i::FunctionTemplateInfo> constructor(
11207 i::FunctionTemplateInfo::cast(internal_template->constructor()));
11208 CHECK(!constructor->access_check_info()->IsUndefined());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011209 v8::Persistent<Context> context0(Context::New(NULL, global_template));
11210 CHECK(!context0.IsEmpty());
Steve Blocka7e24c12009-10-30 11:49:00 +000011211 CHECK(!constructor->access_check_info()->IsUndefined());
11212}
11213
11214
11215THREADED_TEST(TurnOnAccessCheck) {
11216 v8::HandleScope handle_scope;
11217
11218 // Create an environment with access check to the global object disabled by
11219 // default.
11220 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
11221 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
11222 IndexedGetAccessBlocker,
11223 v8::Handle<v8::Value>(),
11224 false);
11225 v8::Persistent<Context> context = Context::New(NULL, global_template);
11226 Context::Scope context_scope(context);
11227
11228 // Set up a property and a number of functions.
11229 context->Global()->Set(v8_str("a"), v8_num(1));
11230 CompileRun("function f1() {return a;}"
11231 "function f2() {return a;}"
11232 "function g1() {return h();}"
11233 "function g2() {return h();}"
11234 "function h() {return 1;}");
11235 Local<Function> f1 =
11236 Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
11237 Local<Function> f2 =
11238 Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
11239 Local<Function> g1 =
11240 Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
11241 Local<Function> g2 =
11242 Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
11243 Local<Function> h =
11244 Local<Function>::Cast(context->Global()->Get(v8_str("h")));
11245
11246 // Get the global object.
11247 v8::Handle<v8::Object> global = context->Global();
11248
11249 // Call f1 one time and f2 a number of times. This will ensure that f1 still
11250 // uses the runtime system to retreive property a whereas f2 uses global load
11251 // inline cache.
11252 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
11253 for (int i = 0; i < 4; i++) {
11254 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
11255 }
11256
11257 // Same for g1 and g2.
11258 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
11259 for (int i = 0; i < 4; i++) {
11260 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
11261 }
11262
11263 // Detach the global and turn on access check.
11264 context->DetachGlobal();
11265 context->Global()->TurnOnAccessCheck();
11266
11267 // Failing access check to property get results in undefined.
11268 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
11269 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
11270
11271 // Failing access check to function call results in exception.
11272 CHECK(g1->Call(global, 0, NULL).IsEmpty());
11273 CHECK(g2->Call(global, 0, NULL).IsEmpty());
11274
11275 // No failing access check when just returning a constant.
11276 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
11277}
11278
11279
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011280static const char* kPropertyA = "a";
11281static const char* kPropertyH = "h";
Ben Murdochb0fe1622011-05-05 13:52:32 +010011282
11283static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
11284 Local<Value> name,
11285 v8::AccessType type,
11286 Local<Value> data) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011287 if (!name->IsString()) return false;
11288 i::Handle<i::String> name_handle =
11289 v8::Utils::OpenHandle(String::Cast(*name));
11290 return !name_handle->IsEqualTo(i::CStrVector(kPropertyA))
11291 && !name_handle->IsEqualTo(i::CStrVector(kPropertyH));
Ben Murdochb0fe1622011-05-05 13:52:32 +010011292}
11293
11294
11295THREADED_TEST(TurnOnAccessCheckAndRecompile) {
11296 v8::HandleScope handle_scope;
11297
11298 // Create an environment with access check to the global object disabled by
11299 // default. When the registered access checker will block access to properties
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011300 // a and h.
Ben Murdochb0fe1622011-05-05 13:52:32 +010011301 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
11302 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
11303 IndexedGetAccessBlocker,
11304 v8::Handle<v8::Value>(),
11305 false);
11306 v8::Persistent<Context> context = Context::New(NULL, global_template);
11307 Context::Scope context_scope(context);
11308
11309 // Set up a property and a number of functions.
11310 context->Global()->Set(v8_str("a"), v8_num(1));
11311 static const char* source = "function f1() {return a;}"
11312 "function f2() {return a;}"
11313 "function g1() {return h();}"
11314 "function g2() {return h();}"
11315 "function h() {return 1;}";
11316
11317 CompileRun(source);
11318 Local<Function> f1;
11319 Local<Function> f2;
11320 Local<Function> g1;
11321 Local<Function> g2;
11322 Local<Function> h;
11323 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
11324 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
11325 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
11326 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
11327 h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
11328
11329 // Get the global object.
11330 v8::Handle<v8::Object> global = context->Global();
11331
11332 // Call f1 one time and f2 a number of times. This will ensure that f1 still
11333 // uses the runtime system to retreive property a whereas f2 uses global load
11334 // inline cache.
11335 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
11336 for (int i = 0; i < 4; i++) {
11337 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
11338 }
11339
11340 // Same for g1 and g2.
11341 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
11342 for (int i = 0; i < 4; i++) {
11343 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
11344 }
11345
11346 // Detach the global and turn on access check now blocking access to property
11347 // a and function h.
11348 context->DetachGlobal();
11349 context->Global()->TurnOnAccessCheck();
11350
11351 // Failing access check to property get results in undefined.
11352 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
11353 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
11354
11355 // Failing access check to function call results in exception.
11356 CHECK(g1->Call(global, 0, NULL).IsEmpty());
11357 CHECK(g2->Call(global, 0, NULL).IsEmpty());
11358
11359 // No failing access check when just returning a constant.
11360 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
11361
11362 // Now compile the source again. And get the newly compiled functions, except
11363 // for h for which access is blocked.
11364 CompileRun(source);
11365 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
11366 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
11367 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
11368 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
11369 CHECK(context->Global()->Get(v8_str("h"))->IsUndefined());
11370
11371 // Failing access check to property get results in undefined.
11372 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
11373 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
11374
11375 // Failing access check to function call results in exception.
11376 CHECK(g1->Call(global, 0, NULL).IsEmpty());
11377 CHECK(g2->Call(global, 0, NULL).IsEmpty());
11378}
11379
11380
Steve Blocka7e24c12009-10-30 11:49:00 +000011381// This test verifies that pre-compilation (aka preparsing) can be called
11382// without initializing the whole VM. Thus we cannot run this test in a
11383// multi-threaded setup.
11384TEST(PreCompile) {
11385 // TODO(155): This test would break without the initialization of V8. This is
11386 // a workaround for now to make this test not fail.
11387 v8::V8::Initialize();
Leon Clarkef7060e22010-06-03 12:02:55 +010011388 const char* script = "function foo(a) { return a+1; }";
11389 v8::ScriptData* sd =
Steve Blockd0582a62009-12-15 09:54:21 +000011390 v8::ScriptData::PreCompile(script, i::StrLength(script));
Steve Blocka7e24c12009-10-30 11:49:00 +000011391 CHECK_NE(sd->Length(), 0);
11392 CHECK_NE(sd->Data(), NULL);
Leon Clarkee46be812010-01-19 14:06:41 +000011393 CHECK(!sd->HasError());
11394 delete sd;
11395}
11396
11397
11398TEST(PreCompileWithError) {
11399 v8::V8::Initialize();
Leon Clarkef7060e22010-06-03 12:02:55 +010011400 const char* script = "function foo(a) { return 1 * * 2; }";
11401 v8::ScriptData* sd =
Leon Clarkee46be812010-01-19 14:06:41 +000011402 v8::ScriptData::PreCompile(script, i::StrLength(script));
11403 CHECK(sd->HasError());
11404 delete sd;
11405}
11406
11407
11408TEST(Regress31661) {
11409 v8::V8::Initialize();
Leon Clarkef7060e22010-06-03 12:02:55 +010011410 const char* script = " The Definintive Guide";
11411 v8::ScriptData* sd =
Leon Clarkee46be812010-01-19 14:06:41 +000011412 v8::ScriptData::PreCompile(script, i::StrLength(script));
11413 CHECK(sd->HasError());
Steve Blocka7e24c12009-10-30 11:49:00 +000011414 delete sd;
11415}
11416
11417
Leon Clarkef7060e22010-06-03 12:02:55 +010011418// Tests that ScriptData can be serialized and deserialized.
11419TEST(PreCompileSerialization) {
11420 v8::V8::Initialize();
11421 const char* script = "function foo(a) { return a+1; }";
11422 v8::ScriptData* sd =
11423 v8::ScriptData::PreCompile(script, i::StrLength(script));
11424
11425 // Serialize.
11426 int serialized_data_length = sd->Length();
11427 char* serialized_data = i::NewArray<char>(serialized_data_length);
11428 memcpy(serialized_data, sd->Data(), serialized_data_length);
11429
11430 // Deserialize.
11431 v8::ScriptData* deserialized_sd =
11432 v8::ScriptData::New(serialized_data, serialized_data_length);
11433
11434 // Verify that the original is the same as the deserialized.
11435 CHECK_EQ(sd->Length(), deserialized_sd->Length());
11436 CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
11437 CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
11438
11439 delete sd;
11440 delete deserialized_sd;
11441}
11442
11443
11444// Attempts to deserialize bad data.
11445TEST(PreCompileDeserializationError) {
11446 v8::V8::Initialize();
11447 const char* data = "DONT CARE";
11448 int invalid_size = 3;
11449 v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
11450
11451 CHECK_EQ(0, sd->Length());
11452
11453 delete sd;
11454}
11455
11456
Leon Clarkeac952652010-07-15 11:15:24 +010011457// Attempts to deserialize bad data.
11458TEST(PreCompileInvalidPreparseDataError) {
11459 v8::V8::Initialize();
11460 v8::HandleScope scope;
11461 LocalContext context;
11462
11463 const char* script = "function foo(){ return 5;}\n"
11464 "function bar(){ return 6 + 7;} foo();";
11465 v8::ScriptData* sd =
11466 v8::ScriptData::PreCompile(script, i::StrLength(script));
11467 CHECK(!sd->HasError());
11468 // ScriptDataImpl private implementation details
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -080011469 const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
Iain Merrick9ac36c92010-09-13 15:29:50 +010011470 const int kFunctionEntrySize = i::FunctionEntry::kSize;
Leon Clarkeac952652010-07-15 11:15:24 +010011471 const int kFunctionEntryStartOffset = 0;
11472 const int kFunctionEntryEndOffset = 1;
11473 unsigned* sd_data =
11474 reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
Leon Clarkeac952652010-07-15 11:15:24 +010011475
11476 // Overwrite function bar's end position with 0.
11477 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
11478 v8::TryCatch try_catch;
11479
11480 Local<String> source = String::New(script);
11481 Local<Script> compiled_script = Script::New(source, NULL, sd);
11482 CHECK(try_catch.HasCaught());
11483 String::AsciiValue exception_value(try_catch.Message()->Get());
11484 CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
11485 *exception_value);
11486
11487 try_catch.Reset();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011488
Leon Clarkeac952652010-07-15 11:15:24 +010011489 // Overwrite function bar's start position with 200. The function entry
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011490 // will not be found when searching for it by position and we should fall
11491 // back on eager compilation.
Kristian Monsen80d68ea2010-09-08 11:05:35 +010011492 sd = v8::ScriptData::PreCompile(script, i::StrLength(script));
11493 sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
Leon Clarkeac952652010-07-15 11:15:24 +010011494 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
11495 200;
11496 compiled_script = Script::New(source, NULL, sd);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011497 CHECK(!try_catch.HasCaught());
Leon Clarkeac952652010-07-15 11:15:24 +010011498
11499 delete sd;
11500}
11501
11502
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010011503// Verifies that the Handle<String> and const char* versions of the API produce
11504// the same results (at least for one trivial case).
11505TEST(PreCompileAPIVariationsAreSame) {
11506 v8::V8::Initialize();
11507 v8::HandleScope scope;
11508
11509 const char* cstring = "function foo(a) { return a+1; }";
Ben Murdoch3bec4d22010-07-22 14:51:16 +010011510
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010011511 v8::ScriptData* sd_from_cstring =
11512 v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
11513
11514 TestAsciiResource* resource = new TestAsciiResource(cstring);
Ben Murdoch3bec4d22010-07-22 14:51:16 +010011515 v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile(
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010011516 v8::String::NewExternal(resource));
11517
Ben Murdoch3bec4d22010-07-22 14:51:16 +010011518 v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile(
11519 v8::String::New(cstring));
11520
11521 CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010011522 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
Ben Murdoch3bec4d22010-07-22 14:51:16 +010011523 sd_from_external_string->Data(),
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010011524 sd_from_cstring->Length()));
11525
Ben Murdoch3bec4d22010-07-22 14:51:16 +010011526 CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length());
11527 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
11528 sd_from_string->Data(),
11529 sd_from_cstring->Length()));
11530
11531
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010011532 delete sd_from_cstring;
Ben Murdoch3bec4d22010-07-22 14:51:16 +010011533 delete sd_from_external_string;
11534 delete sd_from_string;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010011535}
11536
11537
Steve Blocka7e24c12009-10-30 11:49:00 +000011538// This tests that we do not allow dictionary load/call inline caches
11539// to use functions that have not yet been compiled. The potential
11540// problem of loading a function that has not yet been compiled can
11541// arise because we share code between contexts via the compilation
11542// cache.
11543THREADED_TEST(DictionaryICLoadedFunction) {
11544 v8::HandleScope scope;
11545 // Test LoadIC.
11546 for (int i = 0; i < 2; i++) {
11547 LocalContext context;
11548 context->Global()->Set(v8_str("tmp"), v8::True());
11549 context->Global()->Delete(v8_str("tmp"));
11550 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
11551 }
11552 // Test CallIC.
11553 for (int i = 0; i < 2; i++) {
11554 LocalContext context;
11555 context->Global()->Set(v8_str("tmp"), v8::True());
11556 context->Global()->Delete(v8_str("tmp"));
11557 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
11558 }
11559}
11560
11561
11562// Test that cross-context new calls use the context of the callee to
11563// create the new JavaScript object.
11564THREADED_TEST(CrossContextNew) {
11565 v8::HandleScope scope;
11566 v8::Persistent<Context> context0 = Context::New();
11567 v8::Persistent<Context> context1 = Context::New();
11568
11569 // Allow cross-domain access.
11570 Local<String> token = v8_str("<security token>");
11571 context0->SetSecurityToken(token);
11572 context1->SetSecurityToken(token);
11573
11574 // Set an 'x' property on the Object prototype and define a
11575 // constructor function in context0.
11576 context0->Enter();
11577 CompileRun("Object.prototype.x = 42; function C() {};");
11578 context0->Exit();
11579
11580 // Call the constructor function from context0 and check that the
11581 // result has the 'x' property.
11582 context1->Enter();
11583 context1->Global()->Set(v8_str("other"), context0->Global());
11584 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
11585 CHECK(value->IsInt32());
11586 CHECK_EQ(42, value->Int32Value());
11587 context1->Exit();
11588
11589 // Dispose the contexts to allow them to be garbage collected.
11590 context0.Dispose();
11591 context1.Dispose();
11592}
11593
11594
11595class RegExpInterruptTest {
11596 public:
11597 RegExpInterruptTest() : block_(NULL) {}
11598 ~RegExpInterruptTest() { delete block_; }
11599 void RunTest() {
11600 block_ = i::OS::CreateSemaphore(0);
11601 gc_count_ = 0;
11602 gc_during_regexp_ = 0;
11603 regexp_success_ = false;
11604 gc_success_ = false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011605 GCThread gc_thread(this);
Steve Blocka7e24c12009-10-30 11:49:00 +000011606 gc_thread.Start();
11607 v8::Locker::StartPreemption(1);
11608
11609 LongRunningRegExp();
11610 {
11611 v8::Unlocker unlock;
11612 gc_thread.Join();
11613 }
11614 v8::Locker::StopPreemption();
11615 CHECK(regexp_success_);
11616 CHECK(gc_success_);
11617 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011618
Steve Blocka7e24c12009-10-30 11:49:00 +000011619 private:
11620 // Number of garbage collections required.
11621 static const int kRequiredGCs = 5;
11622
11623 class GCThread : public i::Thread {
11624 public:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011625 explicit GCThread(RegExpInterruptTest* test)
11626 : Thread("GCThread"), test_(test) {}
Steve Blocka7e24c12009-10-30 11:49:00 +000011627 virtual void Run() {
11628 test_->CollectGarbage();
11629 }
11630 private:
11631 RegExpInterruptTest* test_;
11632 };
11633
11634 void CollectGarbage() {
11635 block_->Wait();
11636 while (gc_during_regexp_ < kRequiredGCs) {
11637 {
11638 v8::Locker lock;
11639 // TODO(lrn): Perhaps create some garbage before collecting.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011640 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +000011641 gc_count_++;
11642 }
11643 i::OS::Sleep(1);
11644 }
11645 gc_success_ = true;
11646 }
11647
11648 void LongRunningRegExp() {
11649 block_->Signal(); // Enable garbage collection thread on next preemption.
11650 int rounds = 0;
11651 while (gc_during_regexp_ < kRequiredGCs) {
11652 int gc_before = gc_count_;
11653 {
11654 // Match 15-30 "a"'s against 14 and a "b".
11655 const char* c_source =
11656 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
11657 ".exec('aaaaaaaaaaaaaaab') === null";
11658 Local<String> source = String::New(c_source);
11659 Local<Script> script = Script::Compile(source);
11660 Local<Value> result = script->Run();
11661 if (!result->BooleanValue()) {
11662 gc_during_regexp_ = kRequiredGCs; // Allow gc thread to exit.
11663 return;
11664 }
11665 }
11666 {
11667 // Match 15-30 "a"'s against 15 and a "b".
11668 const char* c_source =
11669 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
11670 ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
11671 Local<String> source = String::New(c_source);
11672 Local<Script> script = Script::Compile(source);
11673 Local<Value> result = script->Run();
11674 if (!result->BooleanValue()) {
11675 gc_during_regexp_ = kRequiredGCs;
11676 return;
11677 }
11678 }
11679 int gc_after = gc_count_;
11680 gc_during_regexp_ += gc_after - gc_before;
11681 rounds++;
11682 i::OS::Sleep(1);
11683 }
11684 regexp_success_ = true;
11685 }
11686
11687 i::Semaphore* block_;
11688 int gc_count_;
11689 int gc_during_regexp_;
11690 bool regexp_success_;
11691 bool gc_success_;
11692};
11693
11694
11695// Test that a regular expression execution can be interrupted and
11696// survive a garbage collection.
11697TEST(RegExpInterruption) {
11698 v8::Locker lock;
11699 v8::V8::Initialize();
11700 v8::HandleScope scope;
11701 Local<Context> local_env;
11702 {
11703 LocalContext env;
11704 local_env = env.local();
11705 }
11706
11707 // Local context should still be live.
11708 CHECK(!local_env.IsEmpty());
11709 local_env->Enter();
11710
11711 // Should complete without problems.
11712 RegExpInterruptTest().RunTest();
11713
11714 local_env->Exit();
11715}
11716
11717
11718class ApplyInterruptTest {
11719 public:
11720 ApplyInterruptTest() : block_(NULL) {}
11721 ~ApplyInterruptTest() { delete block_; }
11722 void RunTest() {
11723 block_ = i::OS::CreateSemaphore(0);
11724 gc_count_ = 0;
11725 gc_during_apply_ = 0;
11726 apply_success_ = false;
11727 gc_success_ = false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011728 GCThread gc_thread(this);
Steve Blocka7e24c12009-10-30 11:49:00 +000011729 gc_thread.Start();
11730 v8::Locker::StartPreemption(1);
11731
11732 LongRunningApply();
11733 {
11734 v8::Unlocker unlock;
11735 gc_thread.Join();
11736 }
11737 v8::Locker::StopPreemption();
11738 CHECK(apply_success_);
11739 CHECK(gc_success_);
11740 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011741
Steve Blocka7e24c12009-10-30 11:49:00 +000011742 private:
11743 // Number of garbage collections required.
11744 static const int kRequiredGCs = 2;
11745
11746 class GCThread : public i::Thread {
11747 public:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011748 explicit GCThread(ApplyInterruptTest* test)
11749 : Thread("GCThread"), test_(test) {}
Steve Blocka7e24c12009-10-30 11:49:00 +000011750 virtual void Run() {
11751 test_->CollectGarbage();
11752 }
11753 private:
11754 ApplyInterruptTest* test_;
11755 };
11756
11757 void CollectGarbage() {
11758 block_->Wait();
11759 while (gc_during_apply_ < kRequiredGCs) {
11760 {
11761 v8::Locker lock;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011762 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +000011763 gc_count_++;
11764 }
11765 i::OS::Sleep(1);
11766 }
11767 gc_success_ = true;
11768 }
11769
11770 void LongRunningApply() {
11771 block_->Signal();
11772 int rounds = 0;
11773 while (gc_during_apply_ < kRequiredGCs) {
11774 int gc_before = gc_count_;
11775 {
11776 const char* c_source =
11777 "function do_very_little(bar) {"
11778 " this.foo = bar;"
11779 "}"
11780 "for (var i = 0; i < 100000; i++) {"
11781 " do_very_little.apply(this, ['bar']);"
11782 "}";
11783 Local<String> source = String::New(c_source);
11784 Local<Script> script = Script::Compile(source);
11785 Local<Value> result = script->Run();
11786 // Check that no exception was thrown.
11787 CHECK(!result.IsEmpty());
11788 }
11789 int gc_after = gc_count_;
11790 gc_during_apply_ += gc_after - gc_before;
11791 rounds++;
11792 }
11793 apply_success_ = true;
11794 }
11795
11796 i::Semaphore* block_;
11797 int gc_count_;
11798 int gc_during_apply_;
11799 bool apply_success_;
11800 bool gc_success_;
11801};
11802
11803
11804// Test that nothing bad happens if we get a preemption just when we were
11805// about to do an apply().
11806TEST(ApplyInterruption) {
11807 v8::Locker lock;
11808 v8::V8::Initialize();
11809 v8::HandleScope scope;
11810 Local<Context> local_env;
11811 {
11812 LocalContext env;
11813 local_env = env.local();
11814 }
11815
11816 // Local context should still be live.
11817 CHECK(!local_env.IsEmpty());
11818 local_env->Enter();
11819
11820 // Should complete without problems.
11821 ApplyInterruptTest().RunTest();
11822
11823 local_env->Exit();
11824}
11825
11826
11827// Verify that we can clone an object
11828TEST(ObjectClone) {
11829 v8::HandleScope scope;
11830 LocalContext env;
11831
11832 const char* sample =
11833 "var rv = {};" \
11834 "rv.alpha = 'hello';" \
11835 "rv.beta = 123;" \
11836 "rv;";
11837
11838 // Create an object, verify basics.
11839 Local<Value> val = CompileRun(sample);
11840 CHECK(val->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +010011841 Local<v8::Object> obj = val.As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +000011842 obj->Set(v8_str("gamma"), v8_str("cloneme"));
11843
11844 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
11845 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
11846 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
11847
11848 // Clone it.
11849 Local<v8::Object> clone = obj->Clone();
11850 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
11851 CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
11852 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
11853
11854 // Set a property on the clone, verify each object.
11855 clone->Set(v8_str("beta"), v8::Integer::New(456));
11856 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
11857 CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
11858}
11859
11860
11861class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
11862 public:
11863 explicit AsciiVectorResource(i::Vector<const char> vector)
11864 : data_(vector) {}
11865 virtual ~AsciiVectorResource() {}
11866 virtual size_t length() const { return data_.length(); }
11867 virtual const char* data() const { return data_.start(); }
11868 private:
11869 i::Vector<const char> data_;
11870};
11871
11872
11873class UC16VectorResource : public v8::String::ExternalStringResource {
11874 public:
11875 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
11876 : data_(vector) {}
11877 virtual ~UC16VectorResource() {}
11878 virtual size_t length() const { return data_.length(); }
11879 virtual const i::uc16* data() const { return data_.start(); }
11880 private:
11881 i::Vector<const i::uc16> data_;
11882};
11883
11884
11885static void MorphAString(i::String* string,
11886 AsciiVectorResource* ascii_resource,
11887 UC16VectorResource* uc16_resource) {
11888 CHECK(i::StringShape(string).IsExternal());
11889 if (string->IsAsciiRepresentation()) {
11890 // Check old map is not symbol or long.
Steve Block44f0eee2011-05-26 01:26:41 +010011891 CHECK(string->map() == HEAP->external_ascii_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +000011892 // Morph external string to be TwoByte string.
Steve Block44f0eee2011-05-26 01:26:41 +010011893 string->set_map(HEAP->external_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +000011894 i::ExternalTwoByteString* morphed =
11895 i::ExternalTwoByteString::cast(string);
11896 morphed->set_resource(uc16_resource);
11897 } else {
11898 // Check old map is not symbol or long.
Steve Block44f0eee2011-05-26 01:26:41 +010011899 CHECK(string->map() == HEAP->external_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +000011900 // Morph external string to be ASCII string.
Steve Block44f0eee2011-05-26 01:26:41 +010011901 string->set_map(HEAP->external_ascii_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +000011902 i::ExternalAsciiString* morphed =
11903 i::ExternalAsciiString::cast(string);
11904 morphed->set_resource(ascii_resource);
11905 }
11906}
11907
11908
11909// Test that we can still flatten a string if the components it is built up
11910// from have been turned into 16 bit strings in the mean time.
11911THREADED_TEST(MorphCompositeStringTest) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011912 char utf_buffer[129];
Steve Blocka7e24c12009-10-30 11:49:00 +000011913 const char* c_string = "Now is the time for all good men"
11914 " to come to the aid of the party";
11915 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
11916 {
11917 v8::HandleScope scope;
11918 LocalContext env;
11919 AsciiVectorResource ascii_resource(
Steve Blockd0582a62009-12-15 09:54:21 +000011920 i::Vector<const char>(c_string, i::StrLength(c_string)));
Steve Blocka7e24c12009-10-30 11:49:00 +000011921 UC16VectorResource uc16_resource(
Steve Blockd0582a62009-12-15 09:54:21 +000011922 i::Vector<const uint16_t>(two_byte_string,
11923 i::StrLength(c_string)));
Steve Blocka7e24c12009-10-30 11:49:00 +000011924
11925 Local<String> lhs(v8::Utils::ToLocal(
Steve Block44f0eee2011-05-26 01:26:41 +010011926 FACTORY->NewExternalStringFromAscii(&ascii_resource)));
Steve Blocka7e24c12009-10-30 11:49:00 +000011927 Local<String> rhs(v8::Utils::ToLocal(
Steve Block44f0eee2011-05-26 01:26:41 +010011928 FACTORY->NewExternalStringFromAscii(&ascii_resource)));
Steve Blocka7e24c12009-10-30 11:49:00 +000011929
11930 env->Global()->Set(v8_str("lhs"), lhs);
11931 env->Global()->Set(v8_str("rhs"), rhs);
11932
11933 CompileRun(
11934 "var cons = lhs + rhs;"
11935 "var slice = lhs.substring(1, lhs.length - 1);"
11936 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
11937
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011938 CHECK(!lhs->MayContainNonAscii());
11939 CHECK(!rhs->MayContainNonAscii());
11940
Steve Blocka7e24c12009-10-30 11:49:00 +000011941 MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
11942 MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
11943
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011944 // This should UTF-8 without flattening, since everything is ASCII.
11945 Handle<String> cons = v8_compile("cons")->Run().As<String>();
11946 CHECK_EQ(128, cons->Utf8Length());
11947 int nchars = -1;
11948 CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
11949 CHECK_EQ(128, nchars);
11950 CHECK_EQ(0, strcmp(
11951 utf_buffer,
11952 "Now is the time for all good men to come to the aid of the party"
11953 "Now is the time for all good men to come to the aid of the party"));
11954
Steve Blocka7e24c12009-10-30 11:49:00 +000011955 // Now do some stuff to make sure the strings are flattened, etc.
11956 CompileRun(
11957 "/[^a-z]/.test(cons);"
11958 "/[^a-z]/.test(slice);"
11959 "/[^a-z]/.test(slice_on_cons);");
11960 const char* expected_cons =
11961 "Now is the time for all good men to come to the aid of the party"
11962 "Now is the time for all good men to come to the aid of the party";
11963 const char* expected_slice =
11964 "ow is the time for all good men to come to the aid of the part";
11965 const char* expected_slice_on_cons =
11966 "ow is the time for all good men to come to the aid of the party"
11967 "Now is the time for all good men to come to the aid of the part";
11968 CHECK_EQ(String::New(expected_cons),
11969 env->Global()->Get(v8_str("cons")));
11970 CHECK_EQ(String::New(expected_slice),
11971 env->Global()->Get(v8_str("slice")));
11972 CHECK_EQ(String::New(expected_slice_on_cons),
11973 env->Global()->Get(v8_str("slice_on_cons")));
11974 }
Ben Murdoch3bec4d22010-07-22 14:51:16 +010011975 i::DeleteArray(two_byte_string);
Steve Blocka7e24c12009-10-30 11:49:00 +000011976}
11977
11978
11979TEST(CompileExternalTwoByteSource) {
11980 v8::HandleScope scope;
11981 LocalContext context;
11982
11983 // This is a very short list of sources, which currently is to check for a
11984 // regression caused by r2703.
11985 const char* ascii_sources[] = {
11986 "0.5",
11987 "-0.5", // This mainly testes PushBack in the Scanner.
11988 "--0.5", // This mainly testes PushBack in the Scanner.
11989 NULL
11990 };
11991
11992 // Compile the sources as external two byte strings.
11993 for (int i = 0; ascii_sources[i] != NULL; i++) {
11994 uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
11995 UC16VectorResource uc16_resource(
Steve Blockd0582a62009-12-15 09:54:21 +000011996 i::Vector<const uint16_t>(two_byte_string,
11997 i::StrLength(ascii_sources[i])));
Steve Blocka7e24c12009-10-30 11:49:00 +000011998 v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
11999 v8::Script::Compile(source);
Ben Murdoch3bec4d22010-07-22 14:51:16 +010012000 i::DeleteArray(two_byte_string);
Steve Blocka7e24c12009-10-30 11:49:00 +000012001 }
12002}
12003
12004
12005class RegExpStringModificationTest {
12006 public:
12007 RegExpStringModificationTest()
12008 : block_(i::OS::CreateSemaphore(0)),
12009 morphs_(0),
12010 morphs_during_regexp_(0),
12011 ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
12012 uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
12013 ~RegExpStringModificationTest() { delete block_; }
12014 void RunTest() {
12015 regexp_success_ = false;
12016 morph_success_ = false;
12017
12018 // Initialize the contents of two_byte_content_ to be a uc16 representation
12019 // of "aaaaaaaaaaaaaab".
12020 for (int i = 0; i < 14; i++) {
12021 two_byte_content_[i] = 'a';
12022 }
12023 two_byte_content_[14] = 'b';
12024
12025 // Create the input string for the regexp - the one we are going to change
12026 // properties of.
Steve Block44f0eee2011-05-26 01:26:41 +010012027 input_ = FACTORY->NewExternalStringFromAscii(&ascii_resource_);
Steve Blocka7e24c12009-10-30 11:49:00 +000012028
12029 // Inject the input as a global variable.
12030 i::Handle<i::String> input_name =
Steve Block44f0eee2011-05-26 01:26:41 +010012031 FACTORY->NewStringFromAscii(i::Vector<const char>("input", 5));
12032 i::Isolate::Current()->global_context()->global()->SetProperty(
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012033 *input_name,
12034 *input_,
12035 NONE,
12036 i::kNonStrictMode)->ToObjectChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +000012037
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012038 MorphThread morph_thread(this);
Steve Blocka7e24c12009-10-30 11:49:00 +000012039 morph_thread.Start();
12040 v8::Locker::StartPreemption(1);
12041 LongRunningRegExp();
12042 {
12043 v8::Unlocker unlock;
12044 morph_thread.Join();
12045 }
12046 v8::Locker::StopPreemption();
12047 CHECK(regexp_success_);
12048 CHECK(morph_success_);
12049 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012050
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012051 private:
Steve Blocka7e24c12009-10-30 11:49:00 +000012052 // Number of string modifications required.
12053 static const int kRequiredModifications = 5;
12054 static const int kMaxModifications = 100;
12055
12056 class MorphThread : public i::Thread {
12057 public:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012058 explicit MorphThread(RegExpStringModificationTest* test)
12059 : Thread("MorphThread"), test_(test) {}
Steve Blocka7e24c12009-10-30 11:49:00 +000012060 virtual void Run() {
12061 test_->MorphString();
12062 }
12063 private:
12064 RegExpStringModificationTest* test_;
12065 };
12066
12067 void MorphString() {
12068 block_->Wait();
12069 while (morphs_during_regexp_ < kRequiredModifications &&
12070 morphs_ < kMaxModifications) {
12071 {
12072 v8::Locker lock;
12073 // Swap string between ascii and two-byte representation.
12074 i::String* string = *input_;
12075 MorphAString(string, &ascii_resource_, &uc16_resource_);
12076 morphs_++;
12077 }
12078 i::OS::Sleep(1);
12079 }
12080 morph_success_ = true;
12081 }
12082
12083 void LongRunningRegExp() {
12084 block_->Signal(); // Enable morphing thread on next preemption.
12085 while (morphs_during_regexp_ < kRequiredModifications &&
12086 morphs_ < kMaxModifications) {
12087 int morphs_before = morphs_;
12088 {
Steve Block791712a2010-08-27 10:21:07 +010012089 v8::HandleScope scope;
Steve Blocka7e24c12009-10-30 11:49:00 +000012090 // Match 15-30 "a"'s against 14 and a "b".
12091 const char* c_source =
12092 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
12093 ".exec(input) === null";
12094 Local<String> source = String::New(c_source);
12095 Local<Script> script = Script::Compile(source);
12096 Local<Value> result = script->Run();
12097 CHECK(result->IsTrue());
12098 }
12099 int morphs_after = morphs_;
12100 morphs_during_regexp_ += morphs_after - morphs_before;
12101 }
12102 regexp_success_ = true;
12103 }
12104
12105 i::uc16 two_byte_content_[15];
12106 i::Semaphore* block_;
12107 int morphs_;
12108 int morphs_during_regexp_;
12109 bool regexp_success_;
12110 bool morph_success_;
12111 i::Handle<i::String> input_;
12112 AsciiVectorResource ascii_resource_;
12113 UC16VectorResource uc16_resource_;
12114};
12115
12116
12117// Test that a regular expression execution can be interrupted and
12118// the string changed without failing.
12119TEST(RegExpStringModification) {
12120 v8::Locker lock;
12121 v8::V8::Initialize();
12122 v8::HandleScope scope;
12123 Local<Context> local_env;
12124 {
12125 LocalContext env;
12126 local_env = env.local();
12127 }
12128
12129 // Local context should still be live.
12130 CHECK(!local_env.IsEmpty());
12131 local_env->Enter();
12132
12133 // Should complete without problems.
12134 RegExpStringModificationTest().RunTest();
12135
12136 local_env->Exit();
12137}
12138
12139
12140// Test that we can set a property on the global object even if there
12141// is a read-only property in the prototype chain.
12142TEST(ReadOnlyPropertyInGlobalProto) {
12143 v8::HandleScope scope;
12144 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12145 LocalContext context(0, templ);
12146 v8::Handle<v8::Object> global = context->Global();
12147 v8::Handle<v8::Object> global_proto =
12148 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
12149 global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
12150 global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
12151 // Check without 'eval' or 'with'.
12152 v8::Handle<v8::Value> res =
12153 CompileRun("function f() { x = 42; return x; }; f()");
12154 // Check with 'eval'.
12155 res = CompileRun("function f() { eval('1'); y = 42; return y; }; f()");
12156 CHECK_EQ(v8::Integer::New(42), res);
12157 // Check with 'with'.
12158 res = CompileRun("function f() { with (this) { y = 42 }; return y; }; f()");
12159 CHECK_EQ(v8::Integer::New(42), res);
12160}
12161
12162static int force_set_set_count = 0;
12163static int force_set_get_count = 0;
12164bool pass_on_get = false;
12165
12166static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
12167 const v8::AccessorInfo& info) {
12168 force_set_get_count++;
12169 if (pass_on_get) {
12170 return v8::Handle<v8::Value>();
12171 } else {
12172 return v8::Int32::New(3);
12173 }
12174}
12175
12176static void ForceSetSetter(v8::Local<v8::String> name,
12177 v8::Local<v8::Value> value,
12178 const v8::AccessorInfo& info) {
12179 force_set_set_count++;
12180}
12181
12182static v8::Handle<v8::Value> ForceSetInterceptSetter(
12183 v8::Local<v8::String> name,
12184 v8::Local<v8::Value> value,
12185 const v8::AccessorInfo& info) {
12186 force_set_set_count++;
12187 return v8::Undefined();
12188}
12189
12190TEST(ForceSet) {
12191 force_set_get_count = 0;
12192 force_set_set_count = 0;
12193 pass_on_get = false;
12194
12195 v8::HandleScope scope;
12196 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12197 v8::Handle<v8::String> access_property = v8::String::New("a");
12198 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
12199 LocalContext context(NULL, templ);
12200 v8::Handle<v8::Object> global = context->Global();
12201
12202 // Ordinary properties
12203 v8::Handle<v8::String> simple_property = v8::String::New("p");
12204 global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
12205 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
12206 // This should fail because the property is read-only
12207 global->Set(simple_property, v8::Int32::New(5));
12208 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
12209 // This should succeed even though the property is read-only
12210 global->ForceSet(simple_property, v8::Int32::New(6));
12211 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
12212
12213 // Accessors
12214 CHECK_EQ(0, force_set_set_count);
12215 CHECK_EQ(0, force_set_get_count);
12216 CHECK_EQ(3, global->Get(access_property)->Int32Value());
12217 // CHECK_EQ the property shouldn't override it, just call the setter
12218 // which in this case does nothing.
12219 global->Set(access_property, v8::Int32::New(7));
12220 CHECK_EQ(3, global->Get(access_property)->Int32Value());
12221 CHECK_EQ(1, force_set_set_count);
12222 CHECK_EQ(2, force_set_get_count);
12223 // Forcing the property to be set should override the accessor without
12224 // calling it
12225 global->ForceSet(access_property, v8::Int32::New(8));
12226 CHECK_EQ(8, global->Get(access_property)->Int32Value());
12227 CHECK_EQ(1, force_set_set_count);
12228 CHECK_EQ(2, force_set_get_count);
12229}
12230
12231TEST(ForceSetWithInterceptor) {
12232 force_set_get_count = 0;
12233 force_set_set_count = 0;
12234 pass_on_get = false;
12235
12236 v8::HandleScope scope;
12237 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12238 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
12239 LocalContext context(NULL, templ);
12240 v8::Handle<v8::Object> global = context->Global();
12241
12242 v8::Handle<v8::String> some_property = v8::String::New("a");
12243 CHECK_EQ(0, force_set_set_count);
12244 CHECK_EQ(0, force_set_get_count);
12245 CHECK_EQ(3, global->Get(some_property)->Int32Value());
12246 // Setting the property shouldn't override it, just call the setter
12247 // which in this case does nothing.
12248 global->Set(some_property, v8::Int32::New(7));
12249 CHECK_EQ(3, global->Get(some_property)->Int32Value());
12250 CHECK_EQ(1, force_set_set_count);
12251 CHECK_EQ(2, force_set_get_count);
12252 // Getting the property when the interceptor returns an empty handle
12253 // should yield undefined, since the property isn't present on the
12254 // object itself yet.
12255 pass_on_get = true;
12256 CHECK(global->Get(some_property)->IsUndefined());
12257 CHECK_EQ(1, force_set_set_count);
12258 CHECK_EQ(3, force_set_get_count);
12259 // Forcing the property to be set should cause the value to be
12260 // set locally without calling the interceptor.
12261 global->ForceSet(some_property, v8::Int32::New(8));
12262 CHECK_EQ(8, global->Get(some_property)->Int32Value());
12263 CHECK_EQ(1, force_set_set_count);
12264 CHECK_EQ(4, force_set_get_count);
12265 // Reenabling the interceptor should cause it to take precedence over
12266 // the property
12267 pass_on_get = false;
12268 CHECK_EQ(3, global->Get(some_property)->Int32Value());
12269 CHECK_EQ(1, force_set_set_count);
12270 CHECK_EQ(5, force_set_get_count);
12271 // The interceptor should also work for other properties
12272 CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
12273 CHECK_EQ(1, force_set_set_count);
12274 CHECK_EQ(6, force_set_get_count);
12275}
12276
12277
12278THREADED_TEST(ForceDelete) {
12279 v8::HandleScope scope;
12280 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12281 LocalContext context(NULL, templ);
12282 v8::Handle<v8::Object> global = context->Global();
12283
12284 // Ordinary properties
12285 v8::Handle<v8::String> simple_property = v8::String::New("p");
12286 global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
12287 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
12288 // This should fail because the property is dont-delete.
12289 CHECK(!global->Delete(simple_property));
12290 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
12291 // This should succeed even though the property is dont-delete.
12292 CHECK(global->ForceDelete(simple_property));
12293 CHECK(global->Get(simple_property)->IsUndefined());
12294}
12295
12296
12297static int force_delete_interceptor_count = 0;
12298static bool pass_on_delete = false;
12299
12300
12301static v8::Handle<v8::Boolean> ForceDeleteDeleter(
12302 v8::Local<v8::String> name,
12303 const v8::AccessorInfo& info) {
12304 force_delete_interceptor_count++;
12305 if (pass_on_delete) {
12306 return v8::Handle<v8::Boolean>();
12307 } else {
12308 return v8::True();
12309 }
12310}
12311
12312
12313THREADED_TEST(ForceDeleteWithInterceptor) {
12314 force_delete_interceptor_count = 0;
12315 pass_on_delete = false;
12316
12317 v8::HandleScope scope;
12318 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12319 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
12320 LocalContext context(NULL, templ);
12321 v8::Handle<v8::Object> global = context->Global();
12322
12323 v8::Handle<v8::String> some_property = v8::String::New("a");
12324 global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
12325
12326 // Deleting a property should get intercepted and nothing should
12327 // happen.
12328 CHECK_EQ(0, force_delete_interceptor_count);
12329 CHECK(global->Delete(some_property));
12330 CHECK_EQ(1, force_delete_interceptor_count);
12331 CHECK_EQ(42, global->Get(some_property)->Int32Value());
12332 // Deleting the property when the interceptor returns an empty
12333 // handle should not delete the property since it is DontDelete.
12334 pass_on_delete = true;
12335 CHECK(!global->Delete(some_property));
12336 CHECK_EQ(2, force_delete_interceptor_count);
12337 CHECK_EQ(42, global->Get(some_property)->Int32Value());
12338 // Forcing the property to be deleted should delete the value
12339 // without calling the interceptor.
12340 CHECK(global->ForceDelete(some_property));
12341 CHECK(global->Get(some_property)->IsUndefined());
12342 CHECK_EQ(2, force_delete_interceptor_count);
12343}
12344
12345
12346// Make sure that forcing a delete invalidates any IC stubs, so we
12347// don't read the hole value.
12348THREADED_TEST(ForceDeleteIC) {
12349 v8::HandleScope scope;
12350 LocalContext context;
12351 // Create a DontDelete variable on the global object.
12352 CompileRun("this.__proto__ = { foo: 'horse' };"
12353 "var foo = 'fish';"
12354 "function f() { return foo.length; }");
12355 // Initialize the IC for foo in f.
12356 CompileRun("for (var i = 0; i < 4; i++) f();");
12357 // Make sure the value of foo is correct before the deletion.
12358 CHECK_EQ(4, CompileRun("f()")->Int32Value());
12359 // Force the deletion of foo.
12360 CHECK(context->Global()->ForceDelete(v8_str("foo")));
12361 // Make sure the value for foo is read from the prototype, and that
12362 // we don't get in trouble with reading the deleted cell value
12363 // sentinel.
12364 CHECK_EQ(5, CompileRun("f()")->Int32Value());
12365}
12366
12367
12368v8::Persistent<Context> calling_context0;
12369v8::Persistent<Context> calling_context1;
12370v8::Persistent<Context> calling_context2;
12371
12372
12373// Check that the call to the callback is initiated in
12374// calling_context2, the directly calling context is calling_context1
12375// and the callback itself is in calling_context0.
12376static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
12377 ApiTestFuzzer::Fuzz();
12378 CHECK(Context::GetCurrent() == calling_context0);
12379 CHECK(Context::GetCalling() == calling_context1);
12380 CHECK(Context::GetEntered() == calling_context2);
12381 return v8::Integer::New(42);
12382}
12383
12384
12385THREADED_TEST(GetCallingContext) {
12386 v8::HandleScope scope;
12387
12388 calling_context0 = Context::New();
12389 calling_context1 = Context::New();
12390 calling_context2 = Context::New();
12391
12392 // Allow cross-domain access.
12393 Local<String> token = v8_str("<security token>");
12394 calling_context0->SetSecurityToken(token);
12395 calling_context1->SetSecurityToken(token);
12396 calling_context2->SetSecurityToken(token);
12397
12398 // Create an object with a C++ callback in context0.
12399 calling_context0->Enter();
12400 Local<v8::FunctionTemplate> callback_templ =
12401 v8::FunctionTemplate::New(GetCallingContextCallback);
12402 calling_context0->Global()->Set(v8_str("callback"),
12403 callback_templ->GetFunction());
12404 calling_context0->Exit();
12405
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012406 // Expose context0 in context1 and set up a function that calls the
Steve Blocka7e24c12009-10-30 11:49:00 +000012407 // callback function.
12408 calling_context1->Enter();
12409 calling_context1->Global()->Set(v8_str("context0"),
12410 calling_context0->Global());
12411 CompileRun("function f() { context0.callback() }");
12412 calling_context1->Exit();
12413
12414 // Expose context1 in context2 and call the callback function in
12415 // context0 indirectly through f in context1.
12416 calling_context2->Enter();
12417 calling_context2->Global()->Set(v8_str("context1"),
12418 calling_context1->Global());
12419 CompileRun("context1.f()");
12420 calling_context2->Exit();
12421
12422 // Dispose the contexts to allow them to be garbage collected.
12423 calling_context0.Dispose();
12424 calling_context1.Dispose();
12425 calling_context2.Dispose();
12426 calling_context0.Clear();
12427 calling_context1.Clear();
12428 calling_context2.Clear();
12429}
12430
12431
12432// Check that a variable declaration with no explicit initialization
12433// value does not shadow an existing property in the prototype chain.
12434//
12435// This is consistent with Firefox and Safari.
12436//
12437// See http://crbug.com/12548.
12438THREADED_TEST(InitGlobalVarInProtoChain) {
12439 v8::HandleScope scope;
12440 LocalContext context;
12441 // Introduce a variable in the prototype chain.
12442 CompileRun("__proto__.x = 42");
12443 v8::Handle<v8::Value> result = CompileRun("var x; x");
12444 CHECK(!result->IsUndefined());
12445 CHECK_EQ(42, result->Int32Value());
12446}
12447
12448
12449// Regression test for issue 398.
12450// If a function is added to an object, creating a constant function
12451// field, and the result is cloned, replacing the constant function on the
12452// original should not affect the clone.
12453// See http://code.google.com/p/v8/issues/detail?id=398
12454THREADED_TEST(ReplaceConstantFunction) {
12455 v8::HandleScope scope;
12456 LocalContext context;
12457 v8::Handle<v8::Object> obj = v8::Object::New();
12458 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
12459 v8::Handle<v8::String> foo_string = v8::String::New("foo");
12460 obj->Set(foo_string, func_templ->GetFunction());
12461 v8::Handle<v8::Object> obj_clone = obj->Clone();
12462 obj_clone->Set(foo_string, v8::String::New("Hello"));
12463 CHECK(!obj->Get(foo_string)->IsUndefined());
12464}
12465
12466
12467// Regression test for http://crbug.com/16276.
12468THREADED_TEST(Regress16276) {
12469 v8::HandleScope scope;
12470 LocalContext context;
12471 // Force the IC in f to be a dictionary load IC.
12472 CompileRun("function f(obj) { return obj.x; }\n"
12473 "var obj = { x: { foo: 42 }, y: 87 };\n"
12474 "var x = obj.x;\n"
12475 "delete obj.y;\n"
12476 "for (var i = 0; i < 5; i++) f(obj);");
12477 // Detach the global object to make 'this' refer directly to the
12478 // global object (not the proxy), and make sure that the dictionary
12479 // load IC doesn't mess up loading directly from the global object.
12480 context->DetachGlobal();
12481 CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
12482}
12483
12484
12485THREADED_TEST(PixelArray) {
12486 v8::HandleScope scope;
12487 LocalContext context;
Steve Blockd0582a62009-12-15 09:54:21 +000012488 const int kElementCount = 260;
Steve Blocka7e24c12009-10-30 11:49:00 +000012489 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
Steve Block44f0eee2011-05-26 01:26:41 +010012490 i::Handle<i::ExternalPixelArray> pixels =
12491 i::Handle<i::ExternalPixelArray>::cast(
12492 FACTORY->NewExternalArray(kElementCount,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012493 v8::kExternalPixelArray,
12494 pixel_data));
12495 // Force GC to trigger verification.
12496 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +000012497 for (int i = 0; i < kElementCount; i++) {
Steve Blockd0582a62009-12-15 09:54:21 +000012498 pixels->set(i, i % 256);
Steve Blocka7e24c12009-10-30 11:49:00 +000012499 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012500 // Force GC to trigger verification.
12501 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +000012502 for (int i = 0; i < kElementCount; i++) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012503 CHECK_EQ(i % 256, pixels->get_scalar(i));
Steve Blockd0582a62009-12-15 09:54:21 +000012504 CHECK_EQ(i % 256, pixel_data[i]);
Steve Blocka7e24c12009-10-30 11:49:00 +000012505 }
12506
12507 v8::Handle<v8::Object> obj = v8::Object::New();
12508 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
12509 // Set the elements to be the pixels.
12510 // jsobj->set_elements(*pixels);
12511 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
John Reck59135872010-11-02 12:39:01 -070012512 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000012513 obj->Set(v8_str("field"), v8::Int32::New(1503));
12514 context->Global()->Set(v8_str("pixels"), obj);
12515 v8::Handle<v8::Value> result = CompileRun("pixels.field");
12516 CHECK_EQ(1503, result->Int32Value());
12517 result = CompileRun("pixels[1]");
12518 CHECK_EQ(1, result->Int32Value());
12519
12520 result = CompileRun("var sum = 0;"
12521 "for (var i = 0; i < 8; i++) {"
12522 " sum += pixels[i] = pixels[i] = -i;"
12523 "}"
12524 "sum;");
12525 CHECK_EQ(-28, result->Int32Value());
12526
12527 result = CompileRun("var sum = 0;"
12528 "for (var i = 0; i < 8; i++) {"
12529 " sum += pixels[i] = pixels[i] = 0;"
12530 "}"
12531 "sum;");
12532 CHECK_EQ(0, result->Int32Value());
12533
12534 result = CompileRun("var sum = 0;"
12535 "for (var i = 0; i < 8; i++) {"
12536 " sum += pixels[i] = pixels[i] = 255;"
12537 "}"
12538 "sum;");
12539 CHECK_EQ(8 * 255, result->Int32Value());
12540
12541 result = CompileRun("var sum = 0;"
12542 "for (var i = 0; i < 8; i++) {"
12543 " sum += pixels[i] = pixels[i] = 256 + i;"
12544 "}"
12545 "sum;");
12546 CHECK_EQ(2076, result->Int32Value());
12547
12548 result = CompileRun("var sum = 0;"
12549 "for (var i = 0; i < 8; i++) {"
12550 " sum += pixels[i] = pixels[i] = i;"
12551 "}"
12552 "sum;");
12553 CHECK_EQ(28, result->Int32Value());
12554
12555 result = CompileRun("var sum = 0;"
12556 "for (var i = 0; i < 8; i++) {"
12557 " sum += pixels[i];"
12558 "}"
12559 "sum;");
12560 CHECK_EQ(28, result->Int32Value());
12561
12562 i::Handle<i::Smi> value(i::Smi::FromInt(2));
Ben Murdoch589d6972011-11-30 16:04:58 +000012563 i::Handle<i::Object> no_failure;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012564 no_failure =
12565 i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
Ben Murdoch589d6972011-11-30 16:04:58 +000012566 ASSERT(!no_failure.is_null());
12567 i::USE(no_failure);
John Reck59135872010-11-02 12:39:01 -070012568 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000012569 *value.location() = i::Smi::FromInt(256);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012570 no_failure =
12571 i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
Ben Murdoch589d6972011-11-30 16:04:58 +000012572 ASSERT(!no_failure.is_null());
12573 i::USE(no_failure);
John Reck59135872010-11-02 12:39:01 -070012574 CHECK_EQ(255,
12575 i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000012576 *value.location() = i::Smi::FromInt(-1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012577 no_failure =
12578 i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
Ben Murdoch589d6972011-11-30 16:04:58 +000012579 ASSERT(!no_failure.is_null());
12580 i::USE(no_failure);
John Reck59135872010-11-02 12:39:01 -070012581 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000012582
12583 result = CompileRun("for (var i = 0; i < 8; i++) {"
12584 " pixels[i] = (i * 65) - 109;"
12585 "}"
12586 "pixels[1] + pixels[6];");
12587 CHECK_EQ(255, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070012588 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
12589 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
12590 CHECK_EQ(21,
12591 i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
12592 CHECK_EQ(86,
12593 i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
12594 CHECK_EQ(151,
12595 i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
12596 CHECK_EQ(216,
12597 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
12598 CHECK_EQ(255,
12599 i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
12600 CHECK_EQ(255,
12601 i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000012602 result = CompileRun("var sum = 0;"
12603 "for (var i = 0; i < 8; i++) {"
12604 " sum += pixels[i];"
12605 "}"
12606 "sum;");
12607 CHECK_EQ(984, result->Int32Value());
12608
12609 result = CompileRun("for (var i = 0; i < 8; i++) {"
12610 " pixels[i] = (i * 1.1);"
12611 "}"
12612 "pixels[1] + pixels[6];");
12613 CHECK_EQ(8, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070012614 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
12615 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
12616 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
12617 CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
12618 CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
12619 CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
12620 CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
12621 CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000012622
12623 result = CompileRun("for (var i = 0; i < 8; i++) {"
12624 " pixels[7] = undefined;"
12625 "}"
12626 "pixels[7];");
12627 CHECK_EQ(0, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070012628 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000012629
12630 result = CompileRun("for (var i = 0; i < 8; i++) {"
12631 " pixels[6] = '2.3';"
12632 "}"
12633 "pixels[6];");
12634 CHECK_EQ(2, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070012635 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000012636
12637 result = CompileRun("for (var i = 0; i < 8; i++) {"
12638 " pixels[5] = NaN;"
12639 "}"
12640 "pixels[5];");
12641 CHECK_EQ(0, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070012642 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000012643
12644 result = CompileRun("for (var i = 0; i < 8; i++) {"
12645 " pixels[8] = Infinity;"
12646 "}"
12647 "pixels[8];");
12648 CHECK_EQ(255, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070012649 CHECK_EQ(255,
12650 i::Smi::cast(jsobj->GetElement(8)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000012651
12652 result = CompileRun("for (var i = 0; i < 8; i++) {"
12653 " pixels[9] = -Infinity;"
12654 "}"
12655 "pixels[9];");
12656 CHECK_EQ(0, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070012657 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000012658
12659 result = CompileRun("pixels[3] = 33;"
12660 "delete pixels[3];"
12661 "pixels[3];");
12662 CHECK_EQ(33, result->Int32Value());
12663
12664 result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
12665 "pixels[2] = 12; pixels[3] = 13;"
12666 "pixels.__defineGetter__('2',"
12667 "function() { return 120; });"
12668 "pixels[2];");
12669 CHECK_EQ(12, result->Int32Value());
12670
12671 result = CompileRun("var js_array = new Array(40);"
12672 "js_array[0] = 77;"
12673 "js_array;");
12674 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
12675
12676 result = CompileRun("pixels[1] = 23;"
12677 "pixels.__proto__ = [];"
12678 "js_array.__proto__ = pixels;"
12679 "js_array.concat(pixels);");
12680 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
12681 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
12682
12683 result = CompileRun("pixels[1] = 23;");
12684 CHECK_EQ(23, result->Int32Value());
12685
Steve Blockd0582a62009-12-15 09:54:21 +000012686 // Test for index greater than 255. Regression test for:
12687 // http://code.google.com/p/chromium/issues/detail?id=26337.
12688 result = CompileRun("pixels[256] = 255;");
12689 CHECK_EQ(255, result->Int32Value());
12690 result = CompileRun("var i = 0;"
12691 "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
12692 "i");
12693 CHECK_EQ(255, result->Int32Value());
12694
Steve Block1e0659c2011-05-24 12:43:12 +010012695 // Make sure that pixel array ICs recognize when a non-pixel array
12696 // is passed to it.
12697 result = CompileRun("function pa_load(p) {"
12698 " var sum = 0;"
12699 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
12700 " return sum;"
12701 "}"
12702 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12703 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
12704 "just_ints = new Object();"
12705 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12706 "for (var i = 0; i < 10; ++i) {"
12707 " result = pa_load(just_ints);"
12708 "}"
12709 "result");
12710 CHECK_EQ(32640, result->Int32Value());
12711
12712 // Make sure that pixel array ICs recognize out-of-bound accesses.
12713 result = CompileRun("function pa_load(p, start) {"
12714 " var sum = 0;"
12715 " for (var j = start; j < 256; j++) { sum += p[j]; }"
12716 " return sum;"
12717 "}"
12718 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12719 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
12720 "for (var i = 0; i < 10; ++i) {"
12721 " result = pa_load(pixels,-10);"
12722 "}"
12723 "result");
12724 CHECK_EQ(0, result->Int32Value());
12725
12726 // Make sure that generic ICs properly handles a pixel array.
12727 result = CompileRun("function pa_load(p) {"
12728 " var sum = 0;"
12729 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
12730 " return sum;"
12731 "}"
12732 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12733 "just_ints = new Object();"
12734 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12735 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
12736 "for (var i = 0; i < 10; ++i) {"
12737 " result = pa_load(pixels);"
12738 "}"
12739 "result");
12740 CHECK_EQ(32640, result->Int32Value());
12741
12742 // Make sure that generic load ICs recognize out-of-bound accesses in
12743 // pixel arrays.
12744 result = CompileRun("function pa_load(p, start) {"
12745 " var sum = 0;"
12746 " for (var j = start; j < 256; j++) { sum += p[j]; }"
12747 " return sum;"
12748 "}"
12749 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12750 "just_ints = new Object();"
12751 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12752 "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
12753 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
12754 "for (var i = 0; i < 10; ++i) {"
12755 " result = pa_load(pixels,-10);"
12756 "}"
12757 "result");
12758 CHECK_EQ(0, result->Int32Value());
12759
12760 // Make sure that generic ICs properly handles other types than pixel
12761 // arrays (that the inlined fast pixel array test leaves the right information
12762 // in the right registers).
12763 result = CompileRun("function pa_load(p) {"
12764 " var sum = 0;"
12765 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
12766 " return sum;"
12767 "}"
12768 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12769 "just_ints = new Object();"
12770 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12771 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
12772 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
12773 "sparse_array = new Object();"
12774 "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
12775 "sparse_array[1000000] = 3;"
12776 "for (var i = 0; i < 10; ++i) {"
12777 " result = pa_load(sparse_array);"
12778 "}"
12779 "result");
12780 CHECK_EQ(32640, result->Int32Value());
12781
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012782 // Make sure that pixel array store ICs clamp values correctly.
12783 result = CompileRun("function pa_store(p) {"
12784 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
12785 "}"
12786 "pa_store(pixels);"
12787 "var sum = 0;"
12788 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
12789 "sum");
12790 CHECK_EQ(48896, result->Int32Value());
12791
12792 // Make sure that pixel array stores correctly handle accesses outside
12793 // of the pixel array..
12794 result = CompileRun("function pa_store(p,start) {"
12795 " for (var j = 0; j < 256; j++) {"
12796 " p[j+start] = j * 2;"
12797 " }"
12798 "}"
12799 "pa_store(pixels,0);"
12800 "pa_store(pixels,-128);"
12801 "var sum = 0;"
12802 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
12803 "sum");
12804 CHECK_EQ(65280, result->Int32Value());
12805
12806 // Make sure that the generic store stub correctly handle accesses outside
12807 // of the pixel array..
12808 result = CompileRun("function pa_store(p,start) {"
12809 " for (var j = 0; j < 256; j++) {"
12810 " p[j+start] = j * 2;"
12811 " }"
12812 "}"
12813 "pa_store(pixels,0);"
12814 "just_ints = new Object();"
12815 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12816 "pa_store(just_ints, 0);"
12817 "pa_store(pixels,-128);"
12818 "var sum = 0;"
12819 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
12820 "sum");
12821 CHECK_EQ(65280, result->Int32Value());
12822
12823 // Make sure that the generic keyed store stub clamps pixel array values
12824 // correctly.
12825 result = CompileRun("function pa_store(p) {"
12826 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
12827 "}"
12828 "pa_store(pixels);"
12829 "just_ints = new Object();"
12830 "pa_store(just_ints);"
12831 "pa_store(pixels);"
12832 "var sum = 0;"
12833 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
12834 "sum");
12835 CHECK_EQ(48896, result->Int32Value());
12836
12837 // Make sure that pixel array loads are optimized by crankshaft.
Steve Block1e0659c2011-05-24 12:43:12 +010012838 result = CompileRun("function pa_load(p) {"
12839 " var sum = 0;"
12840 " for (var i=0; i<256; ++i) {"
12841 " sum += p[i];"
12842 " }"
12843 " return sum; "
12844 "}"
12845 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
Steve Block44f0eee2011-05-26 01:26:41 +010012846 "for (var i = 0; i < 5000; ++i) {"
Steve Block1e0659c2011-05-24 12:43:12 +010012847 " result = pa_load(pixels);"
12848 "}"
12849 "result");
12850 CHECK_EQ(32640, result->Int32Value());
12851
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012852 // Make sure that pixel array stores are optimized by crankshaft.
12853 result = CompileRun("function pa_init(p) {"
12854 "for (var i = 0; i < 256; ++i) { p[i] = i; }"
12855 "}"
12856 "function pa_load(p) {"
12857 " var sum = 0;"
12858 " for (var i=0; i<256; ++i) {"
12859 " sum += p[i];"
12860 " }"
12861 " return sum; "
12862 "}"
Steve Block44f0eee2011-05-26 01:26:41 +010012863 "for (var i = 0; i < 5000; ++i) {"
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012864 " pa_init(pixels);"
12865 "}"
12866 "result = pa_load(pixels);"
12867 "result");
12868 CHECK_EQ(32640, result->Int32Value());
12869
Steve Blocka7e24c12009-10-30 11:49:00 +000012870 free(pixel_data);
12871}
12872
12873
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010012874THREADED_TEST(PixelArrayInfo) {
12875 v8::HandleScope scope;
12876 LocalContext context;
12877 for (int size = 0; size < 100; size += 10) {
12878 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
12879 v8::Handle<v8::Object> obj = v8::Object::New();
12880 obj->SetIndexedPropertiesToPixelData(pixel_data, size);
12881 CHECK(obj->HasIndexedPropertiesInPixelData());
12882 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
12883 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
12884 free(pixel_data);
12885 }
12886}
12887
12888
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012889static v8::Handle<Value> NotHandledIndexedPropertyGetter(
12890 uint32_t index,
12891 const AccessorInfo& info) {
12892 ApiTestFuzzer::Fuzz();
12893 return v8::Handle<Value>();
12894}
12895
12896
12897static v8::Handle<Value> NotHandledIndexedPropertySetter(
12898 uint32_t index,
12899 Local<Value> value,
12900 const AccessorInfo& info) {
12901 ApiTestFuzzer::Fuzz();
12902 return v8::Handle<Value>();
12903}
12904
12905
12906THREADED_TEST(PixelArrayWithInterceptor) {
12907 v8::HandleScope scope;
12908 LocalContext context;
12909 const int kElementCount = 260;
12910 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
Steve Block44f0eee2011-05-26 01:26:41 +010012911 i::Handle<i::ExternalPixelArray> pixels =
12912 i::Handle<i::ExternalPixelArray>::cast(
12913 FACTORY->NewExternalArray(kElementCount,
12914 v8::kExternalPixelArray,
12915 pixel_data));
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012916 for (int i = 0; i < kElementCount; i++) {
12917 pixels->set(i, i % 256);
12918 }
12919 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12920 templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
12921 NotHandledIndexedPropertySetter);
12922 v8::Handle<v8::Object> obj = templ->NewInstance();
12923 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
12924 context->Global()->Set(v8_str("pixels"), obj);
12925 v8::Handle<v8::Value> result = CompileRun("pixels[1]");
12926 CHECK_EQ(1, result->Int32Value());
12927 result = CompileRun("var sum = 0;"
12928 "for (var i = 0; i < 8; i++) {"
12929 " sum += pixels[i] = pixels[i] = -i;"
12930 "}"
12931 "sum;");
12932 CHECK_EQ(-28, result->Int32Value());
12933 result = CompileRun("pixels.hasOwnProperty('1')");
12934 CHECK(result->BooleanValue());
12935 free(pixel_data);
12936}
12937
12938
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010012939static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
12940 switch (array_type) {
12941 case v8::kExternalByteArray:
12942 case v8::kExternalUnsignedByteArray:
Steve Block44f0eee2011-05-26 01:26:41 +010012943 case v8::kExternalPixelArray:
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010012944 return 1;
12945 break;
12946 case v8::kExternalShortArray:
12947 case v8::kExternalUnsignedShortArray:
12948 return 2;
12949 break;
12950 case v8::kExternalIntArray:
12951 case v8::kExternalUnsignedIntArray:
12952 case v8::kExternalFloatArray:
12953 return 4;
12954 break;
Ben Murdoch257744e2011-11-30 15:57:28 +000012955 case v8::kExternalDoubleArray:
12956 return 8;
12957 break;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010012958 default:
12959 UNREACHABLE();
12960 return -1;
12961 }
12962 UNREACHABLE();
12963 return -1;
12964}
12965
12966
Steve Block3ce2e202009-11-05 08:53:23 +000012967template <class ExternalArrayClass, class ElementType>
12968static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
12969 int64_t low,
12970 int64_t high) {
12971 v8::HandleScope scope;
12972 LocalContext context;
12973 const int kElementCount = 40;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010012974 int element_size = ExternalArrayElementSize(array_type);
Steve Block3ce2e202009-11-05 08:53:23 +000012975 ElementType* array_data =
12976 static_cast<ElementType*>(malloc(kElementCount * element_size));
12977 i::Handle<ExternalArrayClass> array =
12978 i::Handle<ExternalArrayClass>::cast(
Steve Block44f0eee2011-05-26 01:26:41 +010012979 FACTORY->NewExternalArray(kElementCount, array_type, array_data));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012980 // Force GC to trigger verification.
12981 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Block3ce2e202009-11-05 08:53:23 +000012982 for (int i = 0; i < kElementCount; i++) {
12983 array->set(i, static_cast<ElementType>(i));
12984 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012985 // Force GC to trigger verification.
12986 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Block3ce2e202009-11-05 08:53:23 +000012987 for (int i = 0; i < kElementCount; i++) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012988 CHECK_EQ(static_cast<int64_t>(i),
12989 static_cast<int64_t>(array->get_scalar(i)));
Steve Block3ce2e202009-11-05 08:53:23 +000012990 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
12991 }
12992
12993 v8::Handle<v8::Object> obj = v8::Object::New();
12994 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
12995 // Set the elements to be the external array.
12996 obj->SetIndexedPropertiesToExternalArrayData(array_data,
12997 array_type,
12998 kElementCount);
John Reck59135872010-11-02 12:39:01 -070012999 CHECK_EQ(
13000 1, static_cast<int>(jsobj->GetElement(1)->ToObjectChecked()->Number()));
Steve Block3ce2e202009-11-05 08:53:23 +000013001 obj->Set(v8_str("field"), v8::Int32::New(1503));
13002 context->Global()->Set(v8_str("ext_array"), obj);
13003 v8::Handle<v8::Value> result = CompileRun("ext_array.field");
13004 CHECK_EQ(1503, result->Int32Value());
13005 result = CompileRun("ext_array[1]");
13006 CHECK_EQ(1, result->Int32Value());
13007
13008 // Check pass through of assigned smis
13009 result = CompileRun("var sum = 0;"
13010 "for (var i = 0; i < 8; i++) {"
13011 " sum += ext_array[i] = ext_array[i] = -i;"
13012 "}"
13013 "sum;");
13014 CHECK_EQ(-28, result->Int32Value());
13015
13016 // Check assigned smis
13017 result = CompileRun("for (var i = 0; i < 8; i++) {"
13018 " ext_array[i] = i;"
13019 "}"
13020 "var sum = 0;"
13021 "for (var i = 0; i < 8; i++) {"
13022 " sum += ext_array[i];"
13023 "}"
13024 "sum;");
13025 CHECK_EQ(28, result->Int32Value());
13026
13027 // Check assigned smis in reverse order
13028 result = CompileRun("for (var i = 8; --i >= 0; ) {"
13029 " ext_array[i] = i;"
13030 "}"
13031 "var sum = 0;"
13032 "for (var i = 0; i < 8; i++) {"
13033 " sum += ext_array[i];"
13034 "}"
13035 "sum;");
13036 CHECK_EQ(28, result->Int32Value());
13037
13038 // Check pass through of assigned HeapNumbers
13039 result = CompileRun("var sum = 0;"
13040 "for (var i = 0; i < 16; i+=2) {"
13041 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
13042 "}"
13043 "sum;");
13044 CHECK_EQ(-28, result->Int32Value());
13045
13046 // Check assigned HeapNumbers
13047 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
13048 " ext_array[i] = (i * 0.5);"
13049 "}"
13050 "var sum = 0;"
13051 "for (var i = 0; i < 16; i+=2) {"
13052 " sum += ext_array[i];"
13053 "}"
13054 "sum;");
13055 CHECK_EQ(28, result->Int32Value());
13056
13057 // Check assigned HeapNumbers in reverse order
13058 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
13059 " ext_array[i] = (i * 0.5);"
13060 "}"
13061 "var sum = 0;"
13062 "for (var i = 0; i < 16; i+=2) {"
13063 " sum += ext_array[i];"
13064 "}"
13065 "sum;");
13066 CHECK_EQ(28, result->Int32Value());
13067
13068 i::ScopedVector<char> test_buf(1024);
13069
13070 // Check legal boundary conditions.
13071 // The repeated loads and stores ensure the ICs are exercised.
13072 const char* boundary_program =
13073 "var res = 0;"
13074 "for (var i = 0; i < 16; i++) {"
13075 " ext_array[i] = %lld;"
13076 " if (i > 8) {"
13077 " res = ext_array[i];"
13078 " }"
13079 "}"
13080 "res;";
13081 i::OS::SNPrintF(test_buf,
13082 boundary_program,
13083 low);
13084 result = CompileRun(test_buf.start());
13085 CHECK_EQ(low, result->IntegerValue());
13086
13087 i::OS::SNPrintF(test_buf,
13088 boundary_program,
13089 high);
13090 result = CompileRun(test_buf.start());
13091 CHECK_EQ(high, result->IntegerValue());
13092
13093 // Check misprediction of type in IC.
13094 result = CompileRun("var tmp_array = ext_array;"
13095 "var sum = 0;"
13096 "for (var i = 0; i < 8; i++) {"
13097 " tmp_array[i] = i;"
13098 " sum += tmp_array[i];"
13099 " if (i == 4) {"
13100 " tmp_array = {};"
13101 " }"
13102 "}"
13103 "sum;");
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013104 // Force GC to trigger verification.
13105 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Block3ce2e202009-11-05 08:53:23 +000013106 CHECK_EQ(28, result->Int32Value());
13107
13108 // Make sure out-of-range loads do not throw.
13109 i::OS::SNPrintF(test_buf,
13110 "var caught_exception = false;"
13111 "try {"
13112 " ext_array[%d];"
13113 "} catch (e) {"
13114 " caught_exception = true;"
13115 "}"
13116 "caught_exception;",
13117 kElementCount);
13118 result = CompileRun(test_buf.start());
13119 CHECK_EQ(false, result->BooleanValue());
13120
13121 // Make sure out-of-range stores do not throw.
13122 i::OS::SNPrintF(test_buf,
13123 "var caught_exception = false;"
13124 "try {"
13125 " ext_array[%d] = 1;"
13126 "} catch (e) {"
13127 " caught_exception = true;"
13128 "}"
13129 "caught_exception;",
13130 kElementCount);
13131 result = CompileRun(test_buf.start());
13132 CHECK_EQ(false, result->BooleanValue());
13133
13134 // Check other boundary conditions, values and operations.
13135 result = CompileRun("for (var i = 0; i < 8; i++) {"
13136 " ext_array[7] = undefined;"
13137 "}"
13138 "ext_array[7];");
13139 CHECK_EQ(0, result->Int32Value());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013140 if (array_type == v8::kExternalDoubleArray ||
13141 array_type == v8::kExternalFloatArray) {
13142 CHECK_EQ(
13143 static_cast<int>(i::OS::nan_value()),
13144 static_cast<int>(jsobj->GetElement(7)->ToObjectChecked()->Number()));
13145 } else {
13146 CHECK_EQ(0, static_cast<int>(
13147 jsobj->GetElement(7)->ToObjectChecked()->Number()));
13148 }
Steve Block3ce2e202009-11-05 08:53:23 +000013149
13150 result = CompileRun("for (var i = 0; i < 8; i++) {"
13151 " ext_array[6] = '2.3';"
13152 "}"
13153 "ext_array[6];");
13154 CHECK_EQ(2, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070013155 CHECK_EQ(
13156 2, static_cast<int>(jsobj->GetElement(6)->ToObjectChecked()->Number()));
Steve Block3ce2e202009-11-05 08:53:23 +000013157
Ben Murdoch257744e2011-11-30 15:57:28 +000013158 if (array_type != v8::kExternalFloatArray &&
13159 array_type != v8::kExternalDoubleArray) {
Steve Block3ce2e202009-11-05 08:53:23 +000013160 // Though the specification doesn't state it, be explicit about
13161 // converting NaNs and +/-Infinity to zero.
13162 result = CompileRun("for (var i = 0; i < 8; i++) {"
13163 " ext_array[i] = 5;"
13164 "}"
13165 "for (var i = 0; i < 8; i++) {"
13166 " ext_array[i] = NaN;"
13167 "}"
13168 "ext_array[5];");
13169 CHECK_EQ(0, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070013170 CHECK_EQ(0,
13171 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
Steve Block3ce2e202009-11-05 08:53:23 +000013172
13173 result = CompileRun("for (var i = 0; i < 8; i++) {"
13174 " ext_array[i] = 5;"
13175 "}"
13176 "for (var i = 0; i < 8; i++) {"
13177 " ext_array[i] = Infinity;"
13178 "}"
13179 "ext_array[5];");
Steve Block44f0eee2011-05-26 01:26:41 +010013180 int expected_value =
13181 (array_type == v8::kExternalPixelArray) ? 255 : 0;
13182 CHECK_EQ(expected_value, result->Int32Value());
13183 CHECK_EQ(expected_value,
John Reck59135872010-11-02 12:39:01 -070013184 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
Steve Block3ce2e202009-11-05 08:53:23 +000013185
13186 result = CompileRun("for (var i = 0; i < 8; i++) {"
13187 " ext_array[i] = 5;"
13188 "}"
13189 "for (var i = 0; i < 8; i++) {"
13190 " ext_array[i] = -Infinity;"
13191 "}"
13192 "ext_array[5];");
13193 CHECK_EQ(0, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070013194 CHECK_EQ(0,
13195 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
Steve Block1e0659c2011-05-24 12:43:12 +010013196
13197 // Check truncation behavior of integral arrays.
13198 const char* unsigned_data =
13199 "var source_data = [0.6, 10.6];"
13200 "var expected_results = [0, 10];";
13201 const char* signed_data =
13202 "var source_data = [0.6, 10.6, -0.6, -10.6];"
13203 "var expected_results = [0, 10, 0, -10];";
Steve Block44f0eee2011-05-26 01:26:41 +010013204 const char* pixel_data =
13205 "var source_data = [0.6, 10.6];"
13206 "var expected_results = [1, 11];";
Steve Block1e0659c2011-05-24 12:43:12 +010013207 bool is_unsigned =
13208 (array_type == v8::kExternalUnsignedByteArray ||
13209 array_type == v8::kExternalUnsignedShortArray ||
13210 array_type == v8::kExternalUnsignedIntArray);
Steve Block44f0eee2011-05-26 01:26:41 +010013211 bool is_pixel_data = array_type == v8::kExternalPixelArray;
Steve Block1e0659c2011-05-24 12:43:12 +010013212
13213 i::OS::SNPrintF(test_buf,
13214 "%s"
13215 "var all_passed = true;"
13216 "for (var i = 0; i < source_data.length; i++) {"
13217 " for (var j = 0; j < 8; j++) {"
13218 " ext_array[j] = source_data[i];"
13219 " }"
13220 " all_passed = all_passed &&"
13221 " (ext_array[5] == expected_results[i]);"
13222 "}"
13223 "all_passed;",
Steve Block44f0eee2011-05-26 01:26:41 +010013224 (is_unsigned ?
13225 unsigned_data :
13226 (is_pixel_data ? pixel_data : signed_data)));
Steve Block1e0659c2011-05-24 12:43:12 +010013227 result = CompileRun(test_buf.start());
13228 CHECK_EQ(true, result->BooleanValue());
Steve Block3ce2e202009-11-05 08:53:23 +000013229 }
13230
Ben Murdoch8b112d22011-06-08 16:22:53 +010013231 for (int i = 0; i < kElementCount; i++) {
13232 array->set(i, static_cast<ElementType>(i));
13233 }
13234 // Test complex assignments
13235 result = CompileRun("function ee_op_test_complex_func(sum) {"
13236 " for (var i = 0; i < 40; ++i) {"
13237 " sum += (ext_array[i] += 1);"
13238 " sum += (ext_array[i] -= 1);"
13239 " } "
13240 " return sum;"
13241 "}"
13242 "sum=0;"
13243 "for (var i=0;i<10000;++i) {"
13244 " sum=ee_op_test_complex_func(sum);"
13245 "}"
13246 "sum;");
13247 CHECK_EQ(16000000, result->Int32Value());
13248
13249 // Test count operations
13250 result = CompileRun("function ee_op_test_count_func(sum) {"
13251 " for (var i = 0; i < 40; ++i) {"
13252 " sum += (++ext_array[i]);"
13253 " sum += (--ext_array[i]);"
13254 " } "
13255 " return sum;"
13256 "}"
13257 "sum=0;"
13258 "for (var i=0;i<10000;++i) {"
13259 " sum=ee_op_test_count_func(sum);"
13260 "}"
13261 "sum;");
13262 CHECK_EQ(16000000, result->Int32Value());
13263
Steve Block3ce2e202009-11-05 08:53:23 +000013264 result = CompileRun("ext_array[3] = 33;"
13265 "delete ext_array[3];"
13266 "ext_array[3];");
13267 CHECK_EQ(33, result->Int32Value());
13268
13269 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
13270 "ext_array[2] = 12; ext_array[3] = 13;"
13271 "ext_array.__defineGetter__('2',"
13272 "function() { return 120; });"
13273 "ext_array[2];");
13274 CHECK_EQ(12, result->Int32Value());
13275
13276 result = CompileRun("var js_array = new Array(40);"
13277 "js_array[0] = 77;"
13278 "js_array;");
13279 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
13280
13281 result = CompileRun("ext_array[1] = 23;"
13282 "ext_array.__proto__ = [];"
13283 "js_array.__proto__ = ext_array;"
13284 "js_array.concat(ext_array);");
13285 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
13286 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
13287
13288 result = CompileRun("ext_array[1] = 23;");
13289 CHECK_EQ(23, result->Int32Value());
13290
Steve Blockd0582a62009-12-15 09:54:21 +000013291 // Test more complex manipulations which cause eax to contain values
13292 // that won't be completely overwritten by loads from the arrays.
13293 // This catches bugs in the instructions used for the KeyedLoadIC
13294 // for byte and word types.
13295 {
13296 const int kXSize = 300;
13297 const int kYSize = 300;
13298 const int kLargeElementCount = kXSize * kYSize * 4;
13299 ElementType* large_array_data =
13300 static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
Steve Blockd0582a62009-12-15 09:54:21 +000013301 v8::Handle<v8::Object> large_obj = v8::Object::New();
13302 // Set the elements to be the external array.
13303 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
13304 array_type,
13305 kLargeElementCount);
13306 context->Global()->Set(v8_str("large_array"), large_obj);
13307 // Initialize contents of a few rows.
13308 for (int x = 0; x < 300; x++) {
13309 int row = 0;
13310 int offset = row * 300 * 4;
13311 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
13312 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
13313 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
13314 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
13315 row = 150;
13316 offset = row * 300 * 4;
13317 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
13318 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
13319 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
13320 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
13321 row = 298;
13322 offset = row * 300 * 4;
13323 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
13324 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
13325 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
13326 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
13327 }
13328 // The goal of the code below is to make "offset" large enough
13329 // that the computation of the index (which goes into eax) has
13330 // high bits set which will not be overwritten by a byte or short
13331 // load.
13332 result = CompileRun("var failed = false;"
13333 "var offset = 0;"
13334 "for (var i = 0; i < 300; i++) {"
13335 " if (large_array[4 * i] != 127 ||"
13336 " large_array[4 * i + 1] != 0 ||"
13337 " large_array[4 * i + 2] != 0 ||"
13338 " large_array[4 * i + 3] != 127) {"
13339 " failed = true;"
13340 " }"
13341 "}"
13342 "offset = 150 * 300 * 4;"
13343 "for (var i = 0; i < 300; i++) {"
13344 " if (large_array[offset + 4 * i] != 127 ||"
13345 " large_array[offset + 4 * i + 1] != 0 ||"
13346 " large_array[offset + 4 * i + 2] != 0 ||"
13347 " large_array[offset + 4 * i + 3] != 127) {"
13348 " failed = true;"
13349 " }"
13350 "}"
13351 "offset = 298 * 300 * 4;"
13352 "for (var i = 0; i < 300; i++) {"
13353 " if (large_array[offset + 4 * i] != 127 ||"
13354 " large_array[offset + 4 * i + 1] != 0 ||"
13355 " large_array[offset + 4 * i + 2] != 0 ||"
13356 " large_array[offset + 4 * i + 3] != 127) {"
13357 " failed = true;"
13358 " }"
13359 "}"
13360 "!failed;");
13361 CHECK_EQ(true, result->BooleanValue());
13362 free(large_array_data);
13363 }
13364
Steve Block44f0eee2011-05-26 01:26:41 +010013365 // The "" property descriptor is overloaded to store information about
13366 // the external array. Ensure that setting and accessing the "" property
13367 // works (it should overwrite the information cached about the external
13368 // array in the DescriptorArray) in various situations.
13369 result = CompileRun("ext_array[''] = 23; ext_array['']");
13370 CHECK_EQ(23, result->Int32Value());
13371
13372 // Property "" set after the external array is associated with the object.
13373 {
13374 v8::Handle<v8::Object> obj2 = v8::Object::New();
13375 obj2->Set(v8_str("ee_test_field"), v8::Int32::New(256));
13376 obj2->Set(v8_str(""), v8::Int32::New(1503));
13377 // Set the elements to be the external array.
13378 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
13379 array_type,
13380 kElementCount);
13381 context->Global()->Set(v8_str("ext_array"), obj2);
13382 result = CompileRun("ext_array['']");
13383 CHECK_EQ(1503, result->Int32Value());
13384 }
13385
13386 // Property "" set after the external array is associated with the object.
13387 {
13388 v8::Handle<v8::Object> obj2 = v8::Object::New();
13389 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
13390 // Set the elements to be the external array.
13391 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
13392 array_type,
13393 kElementCount);
13394 obj2->Set(v8_str(""), v8::Int32::New(1503));
13395 context->Global()->Set(v8_str("ext_array"), obj2);
13396 result = CompileRun("ext_array['']");
13397 CHECK_EQ(1503, result->Int32Value());
13398 }
13399
13400 // Should reuse the map from previous test.
13401 {
13402 v8::Handle<v8::Object> obj2 = v8::Object::New();
13403 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
13404 // Set the elements to be the external array. Should re-use the map
13405 // from previous test.
13406 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
13407 array_type,
13408 kElementCount);
13409 context->Global()->Set(v8_str("ext_array"), obj2);
13410 result = CompileRun("ext_array['']");
13411 }
13412
13413 // Property "" is a constant function that shouldn't not be interfered with
13414 // when an external array is set.
13415 {
13416 v8::Handle<v8::Object> obj2 = v8::Object::New();
13417 // Start
13418 obj2->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
13419
13420 // Add a constant function to an object.
13421 context->Global()->Set(v8_str("ext_array"), obj2);
13422 result = CompileRun("ext_array[''] = function() {return 1503;};"
13423 "ext_array['']();");
13424
13425 // Add an external array transition to the same map that
13426 // has the constant transition.
13427 v8::Handle<v8::Object> obj3 = v8::Object::New();
13428 obj3->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
13429 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
13430 array_type,
13431 kElementCount);
13432 context->Global()->Set(v8_str("ext_array"), obj3);
13433 }
13434
13435 // If a external array transition is in the map, it should get clobbered
13436 // by a constant function.
13437 {
13438 // Add an external array transition.
13439 v8::Handle<v8::Object> obj3 = v8::Object::New();
13440 obj3->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
13441 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
13442 array_type,
13443 kElementCount);
13444
13445 // Add a constant function to the same map that just got an external array
13446 // transition.
13447 v8::Handle<v8::Object> obj2 = v8::Object::New();
13448 obj2->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
13449 context->Global()->Set(v8_str("ext_array"), obj2);
13450 result = CompileRun("ext_array[''] = function() {return 1503;};"
13451 "ext_array['']();");
13452 }
13453
Steve Block3ce2e202009-11-05 08:53:23 +000013454 free(array_data);
13455}
13456
13457
13458THREADED_TEST(ExternalByteArray) {
Steve Block8defd9f2010-07-08 12:39:36 +010013459 ExternalArrayTestHelper<i::ExternalByteArray, int8_t>(
Steve Block3ce2e202009-11-05 08:53:23 +000013460 v8::kExternalByteArray,
13461 -128,
13462 127);
13463}
13464
13465
13466THREADED_TEST(ExternalUnsignedByteArray) {
Steve Block8defd9f2010-07-08 12:39:36 +010013467 ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>(
Steve Block3ce2e202009-11-05 08:53:23 +000013468 v8::kExternalUnsignedByteArray,
13469 0,
13470 255);
13471}
13472
13473
Steve Block44f0eee2011-05-26 01:26:41 +010013474THREADED_TEST(ExternalPixelArray) {
13475 ExternalArrayTestHelper<i::ExternalPixelArray, uint8_t>(
13476 v8::kExternalPixelArray,
13477 0,
13478 255);
13479}
13480
13481
Steve Block3ce2e202009-11-05 08:53:23 +000013482THREADED_TEST(ExternalShortArray) {
Steve Block8defd9f2010-07-08 12:39:36 +010013483 ExternalArrayTestHelper<i::ExternalShortArray, int16_t>(
Steve Block3ce2e202009-11-05 08:53:23 +000013484 v8::kExternalShortArray,
13485 -32768,
13486 32767);
13487}
13488
13489
13490THREADED_TEST(ExternalUnsignedShortArray) {
Steve Block8defd9f2010-07-08 12:39:36 +010013491 ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>(
Steve Block3ce2e202009-11-05 08:53:23 +000013492 v8::kExternalUnsignedShortArray,
13493 0,
13494 65535);
13495}
13496
13497
13498THREADED_TEST(ExternalIntArray) {
Steve Block8defd9f2010-07-08 12:39:36 +010013499 ExternalArrayTestHelper<i::ExternalIntArray, int32_t>(
Steve Block3ce2e202009-11-05 08:53:23 +000013500 v8::kExternalIntArray,
13501 INT_MIN, // -2147483648
13502 INT_MAX); // 2147483647
13503}
13504
13505
13506THREADED_TEST(ExternalUnsignedIntArray) {
Steve Block8defd9f2010-07-08 12:39:36 +010013507 ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>(
Steve Block3ce2e202009-11-05 08:53:23 +000013508 v8::kExternalUnsignedIntArray,
13509 0,
13510 UINT_MAX); // 4294967295
13511}
13512
13513
13514THREADED_TEST(ExternalFloatArray) {
Steve Block8defd9f2010-07-08 12:39:36 +010013515 ExternalArrayTestHelper<i::ExternalFloatArray, float>(
Steve Block3ce2e202009-11-05 08:53:23 +000013516 v8::kExternalFloatArray,
13517 -500,
13518 500);
13519}
13520
13521
Ben Murdoch257744e2011-11-30 15:57:28 +000013522THREADED_TEST(ExternalDoubleArray) {
13523 ExternalArrayTestHelper<i::ExternalDoubleArray, double>(
13524 v8::kExternalDoubleArray,
13525 -500,
13526 500);
13527}
13528
13529
Steve Block3ce2e202009-11-05 08:53:23 +000013530THREADED_TEST(ExternalArrays) {
13531 TestExternalByteArray();
13532 TestExternalUnsignedByteArray();
13533 TestExternalShortArray();
13534 TestExternalUnsignedShortArray();
13535 TestExternalIntArray();
13536 TestExternalUnsignedIntArray();
13537 TestExternalFloatArray();
13538}
13539
13540
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010013541void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
13542 v8::HandleScope scope;
13543 LocalContext context;
13544 for (int size = 0; size < 100; size += 10) {
13545 int element_size = ExternalArrayElementSize(array_type);
13546 void* external_data = malloc(size * element_size);
13547 v8::Handle<v8::Object> obj = v8::Object::New();
13548 obj->SetIndexedPropertiesToExternalArrayData(
13549 external_data, array_type, size);
13550 CHECK(obj->HasIndexedPropertiesInExternalArrayData());
13551 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
13552 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
13553 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
13554 free(external_data);
13555 }
13556}
13557
13558
13559THREADED_TEST(ExternalArrayInfo) {
13560 ExternalArrayInfoTestHelper(v8::kExternalByteArray);
13561 ExternalArrayInfoTestHelper(v8::kExternalUnsignedByteArray);
13562 ExternalArrayInfoTestHelper(v8::kExternalShortArray);
13563 ExternalArrayInfoTestHelper(v8::kExternalUnsignedShortArray);
13564 ExternalArrayInfoTestHelper(v8::kExternalIntArray);
13565 ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray);
13566 ExternalArrayInfoTestHelper(v8::kExternalFloatArray);
Ben Murdoch257744e2011-11-30 15:57:28 +000013567 ExternalArrayInfoTestHelper(v8::kExternalDoubleArray);
Steve Block44f0eee2011-05-26 01:26:41 +010013568 ExternalArrayInfoTestHelper(v8::kExternalPixelArray);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010013569}
13570
13571
Steve Blocka7e24c12009-10-30 11:49:00 +000013572THREADED_TEST(ScriptContextDependence) {
13573 v8::HandleScope scope;
13574 LocalContext c1;
13575 const char *source = "foo";
13576 v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
13577 v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
13578 c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
13579 CHECK_EQ(dep->Run()->Int32Value(), 100);
13580 CHECK_EQ(indep->Run()->Int32Value(), 100);
13581 LocalContext c2;
13582 c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
13583 CHECK_EQ(dep->Run()->Int32Value(), 100);
13584 CHECK_EQ(indep->Run()->Int32Value(), 101);
13585}
13586
13587
13588THREADED_TEST(StackTrace) {
13589 v8::HandleScope scope;
13590 LocalContext context;
13591 v8::TryCatch try_catch;
13592 const char *source = "function foo() { FAIL.FAIL; }; foo();";
13593 v8::Handle<v8::String> src = v8::String::New(source);
13594 v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
13595 v8::Script::New(src, origin)->Run();
13596 CHECK(try_catch.HasCaught());
13597 v8::String::Utf8Value stack(try_catch.StackTrace());
13598 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
13599}
13600
13601
Kristian Monsen25f61362010-05-21 11:50:48 +010013602// Checks that a StackFrame has certain expected values.
13603void checkStackFrame(const char* expected_script_name,
13604 const char* expected_func_name, int expected_line_number,
13605 int expected_column, bool is_eval, bool is_constructor,
13606 v8::Handle<v8::StackFrame> frame) {
13607 v8::HandleScope scope;
13608 v8::String::Utf8Value func_name(frame->GetFunctionName());
13609 v8::String::Utf8Value script_name(frame->GetScriptName());
13610 if (*script_name == NULL) {
13611 // The situation where there is no associated script, like for evals.
13612 CHECK(expected_script_name == NULL);
13613 } else {
13614 CHECK(strstr(*script_name, expected_script_name) != NULL);
13615 }
13616 CHECK(strstr(*func_name, expected_func_name) != NULL);
13617 CHECK_EQ(expected_line_number, frame->GetLineNumber());
13618 CHECK_EQ(expected_column, frame->GetColumn());
13619 CHECK_EQ(is_eval, frame->IsEval());
13620 CHECK_EQ(is_constructor, frame->IsConstructor());
13621}
13622
13623
13624v8::Handle<Value> AnalyzeStackInNativeCode(const v8::Arguments& args) {
13625 v8::HandleScope scope;
13626 const char* origin = "capture-stack-trace-test";
13627 const int kOverviewTest = 1;
13628 const int kDetailedTest = 2;
13629
13630 ASSERT(args.Length() == 1);
13631
13632 int testGroup = args[0]->Int32Value();
13633 if (testGroup == kOverviewTest) {
13634 v8::Handle<v8::StackTrace> stackTrace =
13635 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
13636 CHECK_EQ(4, stackTrace->GetFrameCount());
13637 checkStackFrame(origin, "bar", 2, 10, false, false,
13638 stackTrace->GetFrame(0));
13639 checkStackFrame(origin, "foo", 6, 3, false, false,
13640 stackTrace->GetFrame(1));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013641 // This is the source string inside the eval which has the call to foo.
13642 checkStackFrame(NULL, "", 1, 5, false, false,
Kristian Monsen25f61362010-05-21 11:50:48 +010013643 stackTrace->GetFrame(2));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013644 // The last frame is an anonymous function which has the initial eval call.
Kristian Monsen25f61362010-05-21 11:50:48 +010013645 checkStackFrame(origin, "", 8, 7, false, false,
13646 stackTrace->GetFrame(3));
13647
13648 CHECK(stackTrace->AsArray()->IsArray());
13649 } else if (testGroup == kDetailedTest) {
13650 v8::Handle<v8::StackTrace> stackTrace =
13651 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
13652 CHECK_EQ(4, stackTrace->GetFrameCount());
13653 checkStackFrame(origin, "bat", 4, 22, false, false,
13654 stackTrace->GetFrame(0));
13655 checkStackFrame(origin, "baz", 8, 3, false, true,
13656 stackTrace->GetFrame(1));
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010013657#ifdef ENABLE_DEBUGGER_SUPPORT
13658 bool is_eval = true;
13659#else // ENABLE_DEBUGGER_SUPPORT
13660 bool is_eval = false;
13661#endif // ENABLE_DEBUGGER_SUPPORT
13662
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013663 // This is the source string inside the eval which has the call to baz.
13664 checkStackFrame(NULL, "", 1, 5, is_eval, false,
Kristian Monsen25f61362010-05-21 11:50:48 +010013665 stackTrace->GetFrame(2));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013666 // The last frame is an anonymous function which has the initial eval call.
Kristian Monsen25f61362010-05-21 11:50:48 +010013667 checkStackFrame(origin, "", 10, 1, false, false,
13668 stackTrace->GetFrame(3));
13669
13670 CHECK(stackTrace->AsArray()->IsArray());
13671 }
13672 return v8::Undefined();
13673}
13674
13675
13676// Tests the C++ StackTrace API.
Ben Murdochb0fe1622011-05-05 13:52:32 +010013677// TODO(3074796): Reenable this as a THREADED_TEST once it passes.
13678// THREADED_TEST(CaptureStackTrace) {
13679TEST(CaptureStackTrace) {
Kristian Monsen25f61362010-05-21 11:50:48 +010013680 v8::HandleScope scope;
13681 v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
13682 Local<ObjectTemplate> templ = ObjectTemplate::New();
13683 templ->Set(v8_str("AnalyzeStackInNativeCode"),
13684 v8::FunctionTemplate::New(AnalyzeStackInNativeCode));
13685 LocalContext context(0, templ);
13686
13687 // Test getting OVERVIEW information. Should ignore information that is not
13688 // script name, function name, line number, and column offset.
13689 const char *overview_source =
13690 "function bar() {\n"
13691 " var y; AnalyzeStackInNativeCode(1);\n"
13692 "}\n"
13693 "function foo() {\n"
13694 "\n"
13695 " bar();\n"
13696 "}\n"
13697 "var x;eval('new foo();');";
13698 v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013699 v8::Handle<Value> overview_result(
13700 v8::Script::New(overview_src, origin)->Run());
13701 CHECK(!overview_result.IsEmpty());
13702 CHECK(overview_result->IsObject());
Kristian Monsen25f61362010-05-21 11:50:48 +010013703
13704 // Test getting DETAILED information.
13705 const char *detailed_source =
13706 "function bat() {AnalyzeStackInNativeCode(2);\n"
13707 "}\n"
13708 "\n"
13709 "function baz() {\n"
13710 " bat();\n"
13711 "}\n"
13712 "eval('new baz();');";
13713 v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
13714 // Make the script using a non-zero line and column offset.
13715 v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
13716 v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
13717 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
13718 v8::Handle<v8::Script> detailed_script(
13719 v8::Script::New(detailed_src, &detailed_origin));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013720 v8::Handle<Value> detailed_result(detailed_script->Run());
13721 CHECK(!detailed_result.IsEmpty());
13722 CHECK(detailed_result->IsObject());
Kristian Monsen25f61362010-05-21 11:50:48 +010013723}
13724
13725
Ben Murdoch3bec4d22010-07-22 14:51:16 +010013726static void StackTraceForUncaughtExceptionListener(
13727 v8::Handle<v8::Message> message,
13728 v8::Handle<Value>) {
13729 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
13730 CHECK_EQ(2, stack_trace->GetFrameCount());
13731 checkStackFrame("origin", "foo", 2, 3, false, false,
13732 stack_trace->GetFrame(0));
13733 checkStackFrame("origin", "bar", 5, 3, false, false,
13734 stack_trace->GetFrame(1));
13735}
13736
13737TEST(CaptureStackTraceForUncaughtException) {
13738 report_count = 0;
13739 v8::HandleScope scope;
13740 LocalContext env;
13741 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
13742 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
13743
13744 Script::Compile(v8_str("function foo() {\n"
13745 " throw 1;\n"
13746 "};\n"
13747 "function bar() {\n"
13748 " foo();\n"
13749 "};"),
13750 v8_str("origin"))->Run();
13751 v8::Local<v8::Object> global = env->Global();
13752 Local<Value> trouble = global->Get(v8_str("bar"));
13753 CHECK(trouble->IsFunction());
13754 Function::Cast(*trouble)->Call(global, 0, NULL);
13755 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
13756 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
13757}
13758
13759
Steve Block1e0659c2011-05-24 12:43:12 +010013760TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
13761 v8::HandleScope scope;
13762 LocalContext env;
13763 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
13764 1024,
13765 v8::StackTrace::kDetailed);
13766
13767 CompileRun(
13768 "var setters = ['column', 'lineNumber', 'scriptName',\n"
13769 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
13770 " 'isConstructor'];\n"
13771 "for (var i = 0; i < setters.length; i++) {\n"
13772 " var prop = setters[i];\n"
13773 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
13774 "}\n");
13775 CompileRun("throw 'exception';");
13776 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
13777}
13778
13779
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013780static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
13781 v8::Handle<v8::Value> data) {
13782 // Use the frame where JavaScript is called from.
13783 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
13784 CHECK(!stack_trace.IsEmpty());
13785 int frame_count = stack_trace->GetFrameCount();
13786 CHECK_EQ(3, frame_count);
13787 int line_number[] = {1, 2, 5};
13788 for (int i = 0; i < frame_count; i++) {
13789 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
13790 }
13791}
13792
13793
13794// Test that we only return the stack trace at the site where the exception
13795// is first thrown (not where it is rethrown).
13796TEST(RethrowStackTrace) {
13797 v8::HandleScope scope;
13798 LocalContext env;
13799 // We make sure that
13800 // - the stack trace of the ReferenceError in g() is reported.
13801 // - the stack trace is not overwritten when e1 is rethrown by t().
13802 // - the stack trace of e2 does not overwrite that of e1.
13803 const char* source =
13804 "function g() { error; } \n"
13805 "function f() { g(); } \n"
13806 "function t(e) { throw e; } \n"
13807 "try { \n"
13808 " f(); \n"
13809 "} catch (e1) { \n"
13810 " try { \n"
13811 " error; \n"
13812 " } catch (e2) { \n"
13813 " t(e1); \n"
13814 " } \n"
13815 "} \n";
13816 v8::V8::AddMessageListener(RethrowStackTraceHandler);
13817 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
13818 CompileRun(source);
13819 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
13820 v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
13821}
13822
13823
13824static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,
13825 v8::Handle<v8::Value> data) {
13826 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
13827 CHECK(!stack_trace.IsEmpty());
13828 int frame_count = stack_trace->GetFrameCount();
13829 CHECK_EQ(2, frame_count);
13830 int line_number[] = {3, 7};
13831 for (int i = 0; i < frame_count; i++) {
13832 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
13833 }
13834}
13835
13836
13837// Test that we do not recognize identity for primitive exceptions.
13838TEST(RethrowPrimitiveStackTrace) {
13839 v8::HandleScope scope;
13840 LocalContext env;
13841 // We do not capture stack trace for non Error objects on creation time.
13842 // Instead, we capture the stack trace on last throw.
13843 const char* source =
13844 "function g() { throw 404; } \n"
13845 "function f() { g(); } \n"
13846 "function t(e) { throw e; } \n"
13847 "try { \n"
13848 " f(); \n"
13849 "} catch (e1) { \n"
13850 " t(e1) \n"
13851 "} \n";
13852 v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
13853 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
13854 CompileRun(source);
13855 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
13856 v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
13857}
13858
13859
13860static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message,
13861 v8::Handle<v8::Value> data) {
13862 // Use the frame where JavaScript is called from.
13863 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
13864 CHECK(!stack_trace.IsEmpty());
13865 CHECK_EQ(1, stack_trace->GetFrameCount());
13866 CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
13867}
13868
13869
13870// Test that the stack trace is captured when the error object is created and
13871// not where it is thrown.
13872TEST(RethrowExistingStackTrace) {
13873 v8::HandleScope scope;
13874 LocalContext env;
13875 const char* source =
13876 "var e = new Error(); \n"
13877 "throw e; \n";
13878 v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
13879 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
13880 CompileRun(source);
13881 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
13882 v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
13883}
13884
13885
13886static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,
13887 v8::Handle<v8::Value> data) {
13888 // Use the frame where JavaScript is called from.
13889 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
13890 CHECK(!stack_trace.IsEmpty());
13891 CHECK_EQ(1, stack_trace->GetFrameCount());
13892 CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
13893}
13894
13895
13896// Test that the stack trace is captured where the bogus Error object is thrown.
13897TEST(RethrowBogusErrorStackTrace) {
13898 v8::HandleScope scope;
13899 LocalContext env;
13900 const char* source =
13901 "var e = {__proto__: new Error()} \n"
13902 "throw e; \n";
13903 v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
13904 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
13905 CompileRun(source);
13906 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
13907 v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
13908}
13909
13910
Ben Murdochf87a2032010-10-22 12:50:53 +010013911v8::Handle<Value> AnalyzeStackOfEvalWithSourceURL(const v8::Arguments& args) {
13912 v8::HandleScope scope;
13913 v8::Handle<v8::StackTrace> stackTrace =
13914 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
13915 CHECK_EQ(5, stackTrace->GetFrameCount());
13916 v8::Handle<v8::String> url = v8_str("eval_url");
13917 for (int i = 0; i < 3; i++) {
13918 v8::Handle<v8::String> name =
13919 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
13920 CHECK(!name.IsEmpty());
13921 CHECK_EQ(url, name);
13922 }
13923 return v8::Undefined();
13924}
13925
13926
13927TEST(SourceURLInStackTrace) {
13928 v8::HandleScope scope;
13929 Local<ObjectTemplate> templ = ObjectTemplate::New();
13930 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
13931 v8::FunctionTemplate::New(AnalyzeStackOfEvalWithSourceURL));
13932 LocalContext context(0, templ);
13933
13934 const char *source =
13935 "function outer() {\n"
13936 "function bar() {\n"
13937 " AnalyzeStackOfEvalWithSourceURL();\n"
13938 "}\n"
13939 "function foo() {\n"
13940 "\n"
13941 " bar();\n"
13942 "}\n"
13943 "foo();\n"
13944 "}\n"
13945 "eval('(' + outer +')()//@ sourceURL=eval_url');";
13946 CHECK(CompileRun(source)->IsUndefined());
13947}
13948
13949
Steve Block3ce2e202009-11-05 08:53:23 +000013950// Test that idle notification can be handled and eventually returns true.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013951// This just checks the contract of the IdleNotification() function,
13952// and does not verify that it does reasonable work.
Steve Blocka7e24c12009-10-30 11:49:00 +000013953THREADED_TEST(IdleNotification) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013954 v8::HandleScope scope;
13955 LocalContext env;
13956 {
13957 // Create garbage in old-space to generate work for idle notification.
13958 i::AlwaysAllocateScope always_allocate;
13959 for (int i = 0; i < 100; i++) {
13960 FACTORY->NewFixedArray(1000, i::TENURED);
13961 }
Steve Block3ce2e202009-11-05 08:53:23 +000013962 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013963 bool finshed_idle_work = false;
13964 for (int i = 0; i < 100 && !finshed_idle_work; i++) {
13965 finshed_idle_work = v8::V8::IdleNotification();
13966 }
13967 CHECK(finshed_idle_work);
13968}
13969
13970// Test that idle notification can be handled and eventually returns true.
13971// This just checks the contract of the IdleNotification() function,
13972// and does not verify that it does reasonable work.
13973TEST(IdleNotificationWithSmallHint) {
13974 v8::HandleScope scope;
13975 LocalContext env;
13976 {
13977 // Create garbage in old-space to generate work for idle notification.
13978 i::AlwaysAllocateScope always_allocate;
13979 for (int i = 0; i < 100; i++) {
13980 FACTORY->NewFixedArray(1000, i::TENURED);
13981 }
13982 }
13983 intptr_t old_size = HEAP->SizeOfObjects();
13984 bool finshed_idle_work = false;
13985 bool no_idle_work = v8::V8::IdleNotification(10);
13986 for (int i = 0; i < 200 && !finshed_idle_work; i++) {
13987 finshed_idle_work = v8::V8::IdleNotification(10);
13988 }
13989 intptr_t new_size = HEAP->SizeOfObjects();
13990 CHECK(finshed_idle_work);
13991 CHECK(no_idle_work || new_size < old_size);
13992}
13993
13994
13995// This just checks the contract of the IdleNotification() function,
13996// and does not verify that it does reasonable work.
13997TEST(IdleNotificationWithLargeHint) {
13998 v8::HandleScope scope;
13999 LocalContext env;
14000 {
14001 // Create garbage in old-space to generate work for idle notification.
14002 i::AlwaysAllocateScope always_allocate;
14003 for (int i = 0; i < 100; i++) {
14004 FACTORY->NewFixedArray(1000, i::TENURED);
14005 }
14006 }
14007 intptr_t old_size = HEAP->SizeOfObjects();
14008 bool finshed_idle_work = false;
14009 bool no_idle_work = v8::V8::IdleNotification(900);
14010 for (int i = 0; i < 200 && !finshed_idle_work; i++) {
14011 finshed_idle_work = v8::V8::IdleNotification(900);
14012 }
14013 intptr_t new_size = HEAP->SizeOfObjects();
14014 CHECK(finshed_idle_work);
14015 CHECK(no_idle_work || new_size < old_size);
Ben Murdochc7cc0282012-03-05 14:35:55 +000014016}
14017
Steve Blocka7e24c12009-10-30 11:49:00 +000014018
14019static uint32_t* stack_limit;
14020
14021static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
Steve Block44f0eee2011-05-26 01:26:41 +010014022 stack_limit = reinterpret_cast<uint32_t*>(
14023 i::Isolate::Current()->stack_guard()->real_climit());
Steve Blocka7e24c12009-10-30 11:49:00 +000014024 return v8::Undefined();
14025}
14026
14027
14028// Uses the address of a local variable to determine the stack top now.
14029// Given a size, returns an address that is that far from the current
14030// top of stack.
14031static uint32_t* ComputeStackLimit(uint32_t size) {
14032 uint32_t* answer = &size - (size / sizeof(size));
14033 // If the size is very large and the stack is very near the bottom of
14034 // memory then the calculation above may wrap around and give an address
14035 // that is above the (downwards-growing) stack. In that case we return
14036 // a very low address.
14037 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
14038 return answer;
14039}
14040
14041
14042TEST(SetResourceConstraints) {
14043 static const int K = 1024;
14044 uint32_t* set_limit = ComputeStackLimit(128 * K);
14045
14046 // Set stack limit.
14047 v8::ResourceConstraints constraints;
14048 constraints.set_stack_limit(set_limit);
14049 CHECK(v8::SetResourceConstraints(&constraints));
14050
14051 // Execute a script.
14052 v8::HandleScope scope;
14053 LocalContext env;
14054 Local<v8::FunctionTemplate> fun_templ =
14055 v8::FunctionTemplate::New(GetStackLimitCallback);
14056 Local<Function> fun = fun_templ->GetFunction();
14057 env->Global()->Set(v8_str("get_stack_limit"), fun);
14058 CompileRun("get_stack_limit();");
14059
14060 CHECK(stack_limit == set_limit);
14061}
14062
14063
14064TEST(SetResourceConstraintsInThread) {
14065 uint32_t* set_limit;
14066 {
14067 v8::Locker locker;
14068 static const int K = 1024;
14069 set_limit = ComputeStackLimit(128 * K);
14070
14071 // Set stack limit.
14072 v8::ResourceConstraints constraints;
14073 constraints.set_stack_limit(set_limit);
14074 CHECK(v8::SetResourceConstraints(&constraints));
14075
14076 // Execute a script.
14077 v8::HandleScope scope;
14078 LocalContext env;
14079 Local<v8::FunctionTemplate> fun_templ =
14080 v8::FunctionTemplate::New(GetStackLimitCallback);
14081 Local<Function> fun = fun_templ->GetFunction();
14082 env->Global()->Set(v8_str("get_stack_limit"), fun);
14083 CompileRun("get_stack_limit();");
14084
14085 CHECK(stack_limit == set_limit);
14086 }
14087 {
14088 v8::Locker locker;
14089 CHECK(stack_limit == set_limit);
14090 }
14091}
Steve Block3ce2e202009-11-05 08:53:23 +000014092
14093
14094THREADED_TEST(GetHeapStatistics) {
14095 v8::HandleScope scope;
14096 LocalContext c1;
14097 v8::HeapStatistics heap_statistics;
Steve Blockd0582a62009-12-15 09:54:21 +000014098 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
14099 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
Steve Block3ce2e202009-11-05 08:53:23 +000014100 v8::V8::GetHeapStatistics(&heap_statistics);
Steve Blockd0582a62009-12-15 09:54:21 +000014101 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
14102 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
14103}
14104
14105
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014106class VisitorImpl : public v8::ExternalResourceVisitor {
14107 public:
14108 VisitorImpl(TestResource* r1, TestResource* r2)
14109 : resource1_(r1),
14110 resource2_(r2),
14111 found_resource1_(false),
14112 found_resource2_(false) {}
14113 virtual ~VisitorImpl() {}
14114 virtual void VisitExternalString(v8::Handle<v8::String> string) {
14115 if (!string->IsExternal()) {
14116 CHECK(string->IsExternalAscii());
14117 return;
14118 }
14119 v8::String::ExternalStringResource* resource =
14120 string->GetExternalStringResource();
14121 CHECK(resource);
14122 if (resource1_ == resource) {
14123 CHECK(!found_resource1_);
14124 found_resource1_ = true;
14125 }
14126 if (resource2_ == resource) {
14127 CHECK(!found_resource2_);
14128 found_resource2_ = true;
14129 }
14130 }
14131 void CheckVisitedResources() {
14132 CHECK(found_resource1_);
14133 CHECK(found_resource2_);
14134 }
14135
14136 private:
14137 v8::String::ExternalStringResource* resource1_;
14138 v8::String::ExternalStringResource* resource2_;
14139 bool found_resource1_;
14140 bool found_resource2_;
14141};
14142
14143TEST(VisitExternalStrings) {
14144 v8::HandleScope scope;
14145 LocalContext env;
14146 const char* string = "Some string";
14147 uint16_t* two_byte_string = AsciiToTwoByteString(string);
14148 TestResource* resource1 = new TestResource(two_byte_string);
14149 v8::Local<v8::String> string1 = v8::String::NewExternal(resource1);
14150 TestResource* resource2 = new TestResource(two_byte_string);
14151 v8::Local<v8::String> string2 = v8::String::NewExternal(resource2);
14152
14153 // We need to add usages for string1 and string2 to avoid warnings in GCC 4.7
14154 CHECK(string1->IsExternal());
14155 CHECK(string2->IsExternal());
14156
14157 VisitorImpl visitor(resource1, resource2);
14158 v8::V8::VisitExternalResources(&visitor);
14159 visitor.CheckVisitedResources();
14160}
14161
14162
Steve Blockd0582a62009-12-15 09:54:21 +000014163static double DoubleFromBits(uint64_t value) {
14164 double target;
Steve Blockd0582a62009-12-15 09:54:21 +000014165 memcpy(&target, &value, sizeof(target));
Steve Blockd0582a62009-12-15 09:54:21 +000014166 return target;
14167}
14168
14169
14170static uint64_t DoubleToBits(double value) {
14171 uint64_t target;
Steve Blockd0582a62009-12-15 09:54:21 +000014172 memcpy(&target, &value, sizeof(target));
Steve Blockd0582a62009-12-15 09:54:21 +000014173 return target;
14174}
14175
14176
14177static double DoubleToDateTime(double input) {
14178 double date_limit = 864e13;
14179 if (IsNaN(input) || input < -date_limit || input > date_limit) {
14180 return i::OS::nan_value();
14181 }
14182 return (input < 0) ? -(floor(-input)) : floor(input);
14183}
14184
14185// We don't have a consistent way to write 64-bit constants syntactically, so we
14186// split them into two 32-bit constants and combine them programmatically.
14187static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
14188 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
14189}
14190
14191
14192THREADED_TEST(QuietSignalingNaNs) {
14193 v8::HandleScope scope;
14194 LocalContext context;
14195 v8::TryCatch try_catch;
14196
14197 // Special double values.
14198 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
14199 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
14200 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
14201 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
14202 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
14203 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
14204 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
14205
14206 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
14207 // on either side of the epoch.
14208 double date_limit = 864e13;
14209
14210 double test_values[] = {
14211 snan,
14212 qnan,
14213 infinity,
14214 max_normal,
14215 date_limit + 1,
14216 date_limit,
14217 min_normal,
14218 max_denormal,
14219 min_denormal,
14220 0,
14221 -0,
14222 -min_denormal,
14223 -max_denormal,
14224 -min_normal,
14225 -date_limit,
14226 -date_limit - 1,
14227 -max_normal,
14228 -infinity,
14229 -qnan,
14230 -snan
14231 };
14232 int num_test_values = 20;
14233
14234 for (int i = 0; i < num_test_values; i++) {
14235 double test_value = test_values[i];
14236
14237 // Check that Number::New preserves non-NaNs and quiets SNaNs.
14238 v8::Handle<v8::Value> number = v8::Number::New(test_value);
14239 double stored_number = number->NumberValue();
14240 if (!IsNaN(test_value)) {
14241 CHECK_EQ(test_value, stored_number);
14242 } else {
14243 uint64_t stored_bits = DoubleToBits(stored_number);
14244 // Check if quiet nan (bits 51..62 all set).
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014245#if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
14246 // Most significant fraction bit for quiet nan is set to 0
14247 // on MIPS architecture. Allowed by IEEE-754.
14248 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
14249#else
Steve Blockd0582a62009-12-15 09:54:21 +000014250 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014251#endif
Steve Blockd0582a62009-12-15 09:54:21 +000014252 }
14253
14254 // Check that Date::New preserves non-NaNs in the date range and
14255 // quiets SNaNs.
14256 v8::Handle<v8::Value> date = v8::Date::New(test_value);
14257 double expected_stored_date = DoubleToDateTime(test_value);
14258 double stored_date = date->NumberValue();
14259 if (!IsNaN(expected_stored_date)) {
14260 CHECK_EQ(expected_stored_date, stored_date);
14261 } else {
14262 uint64_t stored_bits = DoubleToBits(stored_date);
14263 // Check if quiet nan (bits 51..62 all set).
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014264#if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
14265 // Most significant fraction bit for quiet nan is set to 0
14266 // on MIPS architecture. Allowed by IEEE-754.
14267 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
14268#else
Steve Blockd0582a62009-12-15 09:54:21 +000014269 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014270#endif
Steve Blockd0582a62009-12-15 09:54:21 +000014271 }
14272 }
14273}
14274
14275
14276static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
14277 v8::HandleScope scope;
14278 v8::TryCatch tc;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014279 v8::Handle<v8::String> str(args[0]->ToString());
14280 USE(str);
Steve Blockd0582a62009-12-15 09:54:21 +000014281 if (tc.HasCaught())
14282 return tc.ReThrow();
14283 return v8::Undefined();
14284}
14285
14286
14287// Test that an exception can be propagated down through a spaghetti
14288// stack using ReThrow.
14289THREADED_TEST(SpaghettiStackReThrow) {
14290 v8::HandleScope scope;
14291 LocalContext context;
14292 context->Global()->Set(
14293 v8::String::New("s"),
14294 v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
14295 v8::TryCatch try_catch;
14296 CompileRun(
14297 "var i = 0;"
14298 "var o = {"
14299 " toString: function () {"
14300 " if (i == 10) {"
14301 " throw 'Hey!';"
14302 " } else {"
14303 " i++;"
14304 " return s(o);"
14305 " }"
14306 " }"
14307 "};"
14308 "s(o);");
14309 CHECK(try_catch.HasCaught());
14310 v8::String::Utf8Value value(try_catch.Exception());
14311 CHECK_EQ(0, strcmp(*value, "Hey!"));
14312}
14313
14314
Steve Blockd0582a62009-12-15 09:54:21 +000014315TEST(Regress528) {
14316 v8::V8::Initialize();
14317
14318 v8::HandleScope scope;
14319 v8::Persistent<Context> context;
14320 v8::Persistent<Context> other_context;
14321 int gc_count;
14322
14323 // Create a context used to keep the code from aging in the compilation
14324 // cache.
14325 other_context = Context::New();
14326
14327 // Context-dependent context data creates reference from the compilation
14328 // cache to the global object.
14329 const char* source_simple = "1";
14330 context = Context::New();
14331 {
14332 v8::HandleScope scope;
14333
14334 context->Enter();
14335 Local<v8::String> obj = v8::String::New("");
14336 context->SetData(obj);
14337 CompileRun(source_simple);
14338 context->Exit();
14339 }
14340 context.Dispose();
14341 for (gc_count = 1; gc_count < 10; gc_count++) {
14342 other_context->Enter();
14343 CompileRun(source_simple);
14344 other_context->Exit();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014345 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blockd0582a62009-12-15 09:54:21 +000014346 if (GetGlobalObjectsCount() == 1) break;
14347 }
14348 CHECK_GE(2, gc_count);
14349 CHECK_EQ(1, GetGlobalObjectsCount());
14350
14351 // Eval in a function creates reference from the compilation cache to the
14352 // global object.
14353 const char* source_eval = "function f(){eval('1')}; f()";
14354 context = Context::New();
14355 {
14356 v8::HandleScope scope;
14357
14358 context->Enter();
14359 CompileRun(source_eval);
14360 context->Exit();
14361 }
14362 context.Dispose();
14363 for (gc_count = 1; gc_count < 10; gc_count++) {
14364 other_context->Enter();
14365 CompileRun(source_eval);
14366 other_context->Exit();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014367 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blockd0582a62009-12-15 09:54:21 +000014368 if (GetGlobalObjectsCount() == 1) break;
14369 }
14370 CHECK_GE(2, gc_count);
14371 CHECK_EQ(1, GetGlobalObjectsCount());
14372
14373 // Looking up the line number for an exception creates reference from the
14374 // compilation cache to the global object.
14375 const char* source_exception = "function f(){throw 1;} f()";
14376 context = Context::New();
14377 {
14378 v8::HandleScope scope;
14379
14380 context->Enter();
14381 v8::TryCatch try_catch;
14382 CompileRun(source_exception);
14383 CHECK(try_catch.HasCaught());
14384 v8::Handle<v8::Message> message = try_catch.Message();
14385 CHECK(!message.IsEmpty());
14386 CHECK_EQ(1, message->GetLineNumber());
14387 context->Exit();
14388 }
14389 context.Dispose();
14390 for (gc_count = 1; gc_count < 10; gc_count++) {
14391 other_context->Enter();
14392 CompileRun(source_exception);
14393 other_context->Exit();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014394 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blockd0582a62009-12-15 09:54:21 +000014395 if (GetGlobalObjectsCount() == 1) break;
14396 }
14397 CHECK_GE(2, gc_count);
14398 CHECK_EQ(1, GetGlobalObjectsCount());
14399
14400 other_context.Dispose();
Steve Block3ce2e202009-11-05 08:53:23 +000014401}
Andrei Popescu402d9372010-02-26 13:31:12 +000014402
14403
14404THREADED_TEST(ScriptOrigin) {
14405 v8::HandleScope scope;
14406 LocalContext env;
14407 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
14408 v8::Handle<v8::String> script = v8::String::New(
14409 "function f() {}\n\nfunction g() {}");
14410 v8::Script::Compile(script, &origin)->Run();
14411 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
14412 env->Global()->Get(v8::String::New("f")));
14413 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
14414 env->Global()->Get(v8::String::New("g")));
14415
14416 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
14417 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
14418 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
14419
14420 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
14421 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
14422 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
14423}
14424
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014425THREADED_TEST(FunctionGetInferredName) {
14426 v8::HandleScope scope;
14427 LocalContext env;
14428 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
14429 v8::Handle<v8::String> script = v8::String::New(
14430 "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
14431 v8::Script::Compile(script, &origin)->Run();
14432 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
14433 env->Global()->Get(v8::String::New("f")));
14434 CHECK_EQ("foo.bar.baz", *v8::String::AsciiValue(f->GetInferredName()));
14435}
Andrei Popescu402d9372010-02-26 13:31:12 +000014436
14437THREADED_TEST(ScriptLineNumber) {
14438 v8::HandleScope scope;
14439 LocalContext env;
14440 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
14441 v8::Handle<v8::String> script = v8::String::New(
14442 "function f() {}\n\nfunction g() {}");
14443 v8::Script::Compile(script, &origin)->Run();
14444 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
14445 env->Global()->Get(v8::String::New("f")));
14446 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
14447 env->Global()->Get(v8::String::New("g")));
14448 CHECK_EQ(0, f->GetScriptLineNumber());
14449 CHECK_EQ(2, g->GetScriptLineNumber());
14450}
14451
14452
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014453THREADED_TEST(ScriptColumnNumber) {
14454 v8::HandleScope scope;
14455 LocalContext env;
14456 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"),
14457 v8::Integer::New(3), v8::Integer::New(2));
14458 v8::Handle<v8::String> script = v8::String::New(
14459 "function foo() {}\n\n function bar() {}");
14460 v8::Script::Compile(script, &origin)->Run();
14461 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
14462 env->Global()->Get(v8::String::New("foo")));
14463 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
14464 env->Global()->Get(v8::String::New("bar")));
14465 CHECK_EQ(14, foo->GetScriptColumnNumber());
14466 CHECK_EQ(17, bar->GetScriptColumnNumber());
14467}
14468
14469
14470THREADED_TEST(FunctionGetScriptId) {
14471 v8::HandleScope scope;
14472 LocalContext env;
14473 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"),
14474 v8::Integer::New(3), v8::Integer::New(2));
14475 v8::Handle<v8::String> scriptSource = v8::String::New(
14476 "function foo() {}\n\n function bar() {}");
14477 v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
14478 script->Run();
14479 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
14480 env->Global()->Get(v8::String::New("foo")));
14481 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
14482 env->Global()->Get(v8::String::New("bar")));
14483 CHECK_EQ(script->Id(), foo->GetScriptId());
14484 CHECK_EQ(script->Id(), bar->GetScriptId());
14485}
14486
14487
Andrei Popescu402d9372010-02-26 13:31:12 +000014488static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
14489 const AccessorInfo& info) {
14490 return v8_num(42);
14491}
14492
14493
14494static void SetterWhichSetsYOnThisTo23(Local<String> name,
14495 Local<Value> value,
14496 const AccessorInfo& info) {
14497 info.This()->Set(v8_str("y"), v8_num(23));
14498}
14499
14500
Steve Block6ded16b2010-05-10 14:33:55 +010014501TEST(SetterOnConstructorPrototype) {
Andrei Popescu402d9372010-02-26 13:31:12 +000014502 v8::HandleScope scope;
14503 Local<ObjectTemplate> templ = ObjectTemplate::New();
14504 templ->SetAccessor(v8_str("x"),
14505 GetterWhichReturns42,
14506 SetterWhichSetsYOnThisTo23);
14507 LocalContext context;
14508 context->Global()->Set(v8_str("P"), templ->NewInstance());
14509 CompileRun("function C1() {"
14510 " this.x = 23;"
14511 "};"
14512 "C1.prototype = P;"
14513 "function C2() {"
14514 " this.x = 23"
14515 "};"
14516 "C2.prototype = { };"
14517 "C2.prototype.__proto__ = P;");
14518
14519 v8::Local<v8::Script> script;
14520 script = v8::Script::Compile(v8_str("new C1();"));
14521 for (int i = 0; i < 10; i++) {
14522 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
14523 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
14524 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
14525 }
14526
14527 script = v8::Script::Compile(v8_str("new C2();"));
14528 for (int i = 0; i < 10; i++) {
14529 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
14530 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
14531 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
14532 }
14533}
14534
14535
14536static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
14537 Local<String> name, const AccessorInfo& info) {
14538 return v8_num(42);
14539}
14540
14541
14542static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
14543 Local<String> name, Local<Value> value, const AccessorInfo& info) {
14544 if (name->Equals(v8_str("x"))) {
14545 info.This()->Set(v8_str("y"), v8_num(23));
14546 }
14547 return v8::Handle<Value>();
14548}
14549
14550
14551THREADED_TEST(InterceptorOnConstructorPrototype) {
14552 v8::HandleScope scope;
14553 Local<ObjectTemplate> templ = ObjectTemplate::New();
14554 templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
14555 NamedPropertySetterWhichSetsYOnThisTo23);
14556 LocalContext context;
14557 context->Global()->Set(v8_str("P"), templ->NewInstance());
14558 CompileRun("function C1() {"
14559 " this.x = 23;"
14560 "};"
14561 "C1.prototype = P;"
14562 "function C2() {"
14563 " this.x = 23"
14564 "};"
14565 "C2.prototype = { };"
14566 "C2.prototype.__proto__ = P;");
14567
14568 v8::Local<v8::Script> script;
14569 script = v8::Script::Compile(v8_str("new C1();"));
14570 for (int i = 0; i < 10; i++) {
14571 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
14572 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
14573 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
14574 }
14575
14576 script = v8::Script::Compile(v8_str("new C2();"));
14577 for (int i = 0; i < 10; i++) {
14578 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
14579 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
14580 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
14581 }
14582}
Steve Block6ded16b2010-05-10 14:33:55 +010014583
14584
14585TEST(Bug618) {
14586 const char* source = "function C1() {"
14587 " this.x = 23;"
14588 "};"
14589 "C1.prototype = P;";
14590
14591 v8::HandleScope scope;
14592 LocalContext context;
14593 v8::Local<v8::Script> script;
14594
14595 // Use a simple object as prototype.
14596 v8::Local<v8::Object> prototype = v8::Object::New();
14597 prototype->Set(v8_str("y"), v8_num(42));
14598 context->Global()->Set(v8_str("P"), prototype);
14599
14600 // This compile will add the code to the compilation cache.
14601 CompileRun(source);
14602
14603 script = v8::Script::Compile(v8_str("new C1();"));
Kristian Monsen0d5e1162010-09-30 15:31:59 +010014604 // Allow enough iterations for the inobject slack tracking logic
14605 // to finalize instance size and install the fast construct stub.
14606 for (int i = 0; i < 256; i++) {
Steve Block6ded16b2010-05-10 14:33:55 +010014607 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
14608 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
14609 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
14610 }
14611
14612 // Use an API object with accessors as prototype.
14613 Local<ObjectTemplate> templ = ObjectTemplate::New();
14614 templ->SetAccessor(v8_str("x"),
14615 GetterWhichReturns42,
14616 SetterWhichSetsYOnThisTo23);
14617 context->Global()->Set(v8_str("P"), templ->NewInstance());
14618
14619 // This compile will get the code from the compilation cache.
14620 CompileRun(source);
14621
14622 script = v8::Script::Compile(v8_str("new C1();"));
14623 for (int i = 0; i < 10; i++) {
14624 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
14625 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
14626 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
14627 }
14628}
14629
14630int prologue_call_count = 0;
14631int epilogue_call_count = 0;
14632int prologue_call_count_second = 0;
14633int epilogue_call_count_second = 0;
14634
14635void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
14636 ++prologue_call_count;
14637}
14638
14639void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
14640 ++epilogue_call_count;
14641}
14642
14643void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
14644 ++prologue_call_count_second;
14645}
14646
14647void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
14648 ++epilogue_call_count_second;
14649}
14650
14651TEST(GCCallbacks) {
14652 LocalContext context;
14653
14654 v8::V8::AddGCPrologueCallback(PrologueCallback);
14655 v8::V8::AddGCEpilogueCallback(EpilogueCallback);
14656 CHECK_EQ(0, prologue_call_count);
14657 CHECK_EQ(0, epilogue_call_count);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014658 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Block6ded16b2010-05-10 14:33:55 +010014659 CHECK_EQ(1, prologue_call_count);
14660 CHECK_EQ(1, epilogue_call_count);
14661 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
14662 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014663 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Block6ded16b2010-05-10 14:33:55 +010014664 CHECK_EQ(2, prologue_call_count);
14665 CHECK_EQ(2, epilogue_call_count);
14666 CHECK_EQ(1, prologue_call_count_second);
14667 CHECK_EQ(1, epilogue_call_count_second);
14668 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
14669 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014670 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Block6ded16b2010-05-10 14:33:55 +010014671 CHECK_EQ(2, prologue_call_count);
14672 CHECK_EQ(2, epilogue_call_count);
14673 CHECK_EQ(2, prologue_call_count_second);
14674 CHECK_EQ(2, epilogue_call_count_second);
14675 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
14676 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014677 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Block6ded16b2010-05-10 14:33:55 +010014678 CHECK_EQ(2, prologue_call_count);
14679 CHECK_EQ(2, epilogue_call_count);
14680 CHECK_EQ(2, prologue_call_count_second);
14681 CHECK_EQ(2, epilogue_call_count_second);
14682}
Kristian Monsen25f61362010-05-21 11:50:48 +010014683
14684
14685THREADED_TEST(AddToJSFunctionResultCache) {
14686 i::FLAG_allow_natives_syntax = true;
14687 v8::HandleScope scope;
14688
14689 LocalContext context;
14690
14691 const char* code =
14692 "(function() {"
14693 " var key0 = 'a';"
14694 " var key1 = 'b';"
14695 " var r0 = %_GetFromCache(0, key0);"
14696 " var r1 = %_GetFromCache(0, key1);"
14697 " var r0_ = %_GetFromCache(0, key0);"
14698 " if (r0 !== r0_)"
14699 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
14700 " var r1_ = %_GetFromCache(0, key1);"
14701 " if (r1 !== r1_)"
14702 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
14703 " return 'PASSED';"
14704 "})()";
Steve Block44f0eee2011-05-26 01:26:41 +010014705 HEAP->ClearJSFunctionResultCaches();
Kristian Monsen25f61362010-05-21 11:50:48 +010014706 ExpectString(code, "PASSED");
14707}
14708
14709
14710static const int k0CacheSize = 16;
14711
14712THREADED_TEST(FillJSFunctionResultCache) {
14713 i::FLAG_allow_natives_syntax = true;
14714 v8::HandleScope scope;
14715
14716 LocalContext context;
14717
14718 const char* code =
14719 "(function() {"
14720 " var k = 'a';"
14721 " var r = %_GetFromCache(0, k);"
14722 " for (var i = 0; i < 16; i++) {"
14723 " %_GetFromCache(0, 'a' + i);"
14724 " };"
14725 " if (r === %_GetFromCache(0, k))"
14726 " return 'FAILED: k0CacheSize is too small';"
14727 " return 'PASSED';"
14728 "})()";
Steve Block44f0eee2011-05-26 01:26:41 +010014729 HEAP->ClearJSFunctionResultCaches();
Kristian Monsen25f61362010-05-21 11:50:48 +010014730 ExpectString(code, "PASSED");
14731}
14732
14733
14734THREADED_TEST(RoundRobinGetFromCache) {
14735 i::FLAG_allow_natives_syntax = true;
14736 v8::HandleScope scope;
14737
14738 LocalContext context;
14739
14740 const char* code =
14741 "(function() {"
14742 " var keys = [];"
14743 " for (var i = 0; i < 16; i++) keys.push(i);"
14744 " var values = [];"
14745 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
14746 " for (var i = 0; i < 16; i++) {"
14747 " var v = %_GetFromCache(0, keys[i]);"
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014748 " if (v.toString() !== values[i].toString())"
Kristian Monsen25f61362010-05-21 11:50:48 +010014749 " return 'Wrong value for ' + "
14750 " keys[i] + ': ' + v + ' vs. ' + values[i];"
14751 " };"
14752 " return 'PASSED';"
14753 "})()";
Steve Block44f0eee2011-05-26 01:26:41 +010014754 HEAP->ClearJSFunctionResultCaches();
Kristian Monsen25f61362010-05-21 11:50:48 +010014755 ExpectString(code, "PASSED");
14756}
14757
14758
14759THREADED_TEST(ReverseGetFromCache) {
14760 i::FLAG_allow_natives_syntax = true;
14761 v8::HandleScope scope;
14762
14763 LocalContext context;
14764
14765 const char* code =
14766 "(function() {"
14767 " var keys = [];"
14768 " for (var i = 0; i < 16; i++) keys.push(i);"
14769 " var values = [];"
14770 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
14771 " for (var i = 15; i >= 16; i--) {"
14772 " var v = %_GetFromCache(0, keys[i]);"
14773 " if (v !== values[i])"
14774 " return 'Wrong value for ' + "
14775 " keys[i] + ': ' + v + ' vs. ' + values[i];"
14776 " };"
14777 " return 'PASSED';"
14778 "})()";
Steve Block44f0eee2011-05-26 01:26:41 +010014779 HEAP->ClearJSFunctionResultCaches();
Kristian Monsen25f61362010-05-21 11:50:48 +010014780 ExpectString(code, "PASSED");
14781}
14782
14783
14784THREADED_TEST(TestEviction) {
14785 i::FLAG_allow_natives_syntax = true;
14786 v8::HandleScope scope;
14787
14788 LocalContext context;
14789
14790 const char* code =
14791 "(function() {"
14792 " for (var i = 0; i < 2*16; i++) {"
14793 " %_GetFromCache(0, 'a' + i);"
14794 " };"
14795 " return 'PASSED';"
14796 "})()";
Steve Block44f0eee2011-05-26 01:26:41 +010014797 HEAP->ClearJSFunctionResultCaches();
Kristian Monsen25f61362010-05-21 11:50:48 +010014798 ExpectString(code, "PASSED");
14799}
Steve Block8defd9f2010-07-08 12:39:36 +010014800
14801
14802THREADED_TEST(TwoByteStringInAsciiCons) {
14803 // See Chromium issue 47824.
14804 v8::HandleScope scope;
14805
14806 LocalContext context;
14807 const char* init_code =
14808 "var str1 = 'abelspendabel';"
14809 "var str2 = str1 + str1 + str1;"
14810 "str2;";
14811 Local<Value> result = CompileRun(init_code);
14812
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014813 Local<Value> indexof = CompileRun("str2.indexOf('els')");
14814 Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
14815
Steve Block8defd9f2010-07-08 12:39:36 +010014816 CHECK(result->IsString());
14817 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
14818 int length = string->length();
14819 CHECK(string->IsAsciiRepresentation());
14820
14821 FlattenString(string);
14822 i::Handle<i::String> flat_string = FlattenGetString(string);
14823
14824 CHECK(string->IsAsciiRepresentation());
14825 CHECK(flat_string->IsAsciiRepresentation());
14826
14827 // Create external resource.
14828 uint16_t* uc16_buffer = new uint16_t[length + 1];
14829
14830 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
14831 uc16_buffer[length] = 0;
14832
14833 TestResource resource(uc16_buffer);
14834
14835 flat_string->MakeExternal(&resource);
14836
14837 CHECK(flat_string->IsTwoByteRepresentation());
14838
14839 // At this point, we should have a Cons string which is flat and ASCII,
14840 // with a first half that is a two-byte string (although it only contains
14841 // ASCII characters). This is a valid sequence of steps, and it can happen
14842 // in real pages.
14843
14844 CHECK(string->IsAsciiRepresentation());
14845 i::ConsString* cons = i::ConsString::cast(*string);
14846 CHECK_EQ(0, cons->second()->length());
14847 CHECK(cons->first()->IsTwoByteRepresentation());
14848
14849 // Check that some string operations work.
14850
14851 // Atom RegExp.
14852 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
14853 CHECK_EQ(6, reresult->Int32Value());
14854
14855 // Nonatom RegExp.
14856 reresult = CompileRun("str2.match(/abe./g).length;");
14857 CHECK_EQ(6, reresult->Int32Value());
14858
14859 reresult = CompileRun("str2.search(/bel/g);");
14860 CHECK_EQ(1, reresult->Int32Value());
14861
14862 reresult = CompileRun("str2.search(/be./g);");
14863 CHECK_EQ(1, reresult->Int32Value());
14864
14865 ExpectTrue("/bel/g.test(str2);");
14866
14867 ExpectTrue("/be./g.test(str2);");
14868
14869 reresult = CompileRun("/bel/g.exec(str2);");
14870 CHECK(!reresult->IsNull());
14871
14872 reresult = CompileRun("/be./g.exec(str2);");
14873 CHECK(!reresult->IsNull());
14874
14875 ExpectString("str2.substring(2, 10);", "elspenda");
14876
14877 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
14878
14879 ExpectString("str2.charAt(2);", "e");
14880
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014881 ExpectObject("str2.indexOf('els');", indexof);
14882
14883 ExpectObject("str2.lastIndexOf('dab');", lastindexof);
14884
Steve Block8defd9f2010-07-08 12:39:36 +010014885 reresult = CompileRun("str2.charCodeAt(2);");
14886 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
14887}
Iain Merrick75681382010-08-19 15:07:18 +010014888
14889
14890// Failed access check callback that performs a GC on each invocation.
14891void FailedAccessCheckCallbackGC(Local<v8::Object> target,
14892 v8::AccessType type,
14893 Local<v8::Value> data) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014894 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Iain Merrick75681382010-08-19 15:07:18 +010014895}
14896
14897
14898TEST(GCInFailedAccessCheckCallback) {
14899 // Install a failed access check callback that performs a GC on each
14900 // invocation. Then force the callback to be called from va
14901
14902 v8::V8::Initialize();
14903 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
14904
14905 v8::HandleScope scope;
14906
14907 // Create an ObjectTemplate for global objects and install access
14908 // check callbacks that will block access.
14909 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
14910 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
14911 IndexedGetAccessBlocker,
14912 v8::Handle<v8::Value>(),
14913 false);
14914
14915 // Create a context and set an x property on it's global object.
14916 LocalContext context0(NULL, global_template);
14917 context0->Global()->Set(v8_str("x"), v8_num(42));
14918 v8::Handle<v8::Object> global0 = context0->Global();
14919
14920 // Create a context with a different security token so that the
14921 // failed access check callback will be called on each access.
14922 LocalContext context1(NULL, global_template);
14923 context1->Global()->Set(v8_str("other"), global0);
14924
14925 // Get property with failed access check.
14926 ExpectUndefined("other.x");
14927
14928 // Get element with failed access check.
14929 ExpectUndefined("other[0]");
14930
14931 // Set property with failed access check.
14932 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
14933 CHECK(result->IsObject());
14934
14935 // Set element with failed access check.
14936 result = CompileRun("other[0] = new Object()");
14937 CHECK(result->IsObject());
14938
14939 // Get property attribute with failed access check.
14940 ExpectFalse("\'x\' in other");
14941
14942 // Get property attribute for element with failed access check.
14943 ExpectFalse("0 in other");
14944
14945 // Delete property.
14946 ExpectFalse("delete other.x");
14947
14948 // Delete element.
14949 CHECK_EQ(false, global0->Delete(0));
14950
14951 // DefineAccessor.
14952 CHECK_EQ(false,
14953 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
14954
14955 // Define JavaScript accessor.
14956 ExpectUndefined("Object.prototype.__defineGetter__.call("
14957 " other, \'x\', function() { return 42; })");
14958
14959 // LookupAccessor.
14960 ExpectUndefined("Object.prototype.__lookupGetter__.call("
14961 " other, \'x\')");
14962
14963 // HasLocalElement.
14964 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
14965
14966 CHECK_EQ(false, global0->HasRealIndexedProperty(0));
14967 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
14968 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
14969
14970 // Reset the failed access check callback so it does not influence
14971 // the other tests.
14972 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
14973}
Kristian Monsen0d5e1162010-09-30 15:31:59 +010014974
Steve Block44f0eee2011-05-26 01:26:41 +010014975TEST(DefaultIsolateGetCurrent) {
14976 CHECK(v8::Isolate::GetCurrent() != NULL);
14977 v8::Isolate* isolate = v8::Isolate::GetCurrent();
14978 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
14979 printf("*** %s\n", "DefaultIsolateGetCurrent success");
14980}
14981
14982TEST(IsolateNewDispose) {
14983 v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
14984 v8::Isolate* isolate = v8::Isolate::New();
14985 CHECK(isolate != NULL);
14986 CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
14987 CHECK(current_isolate != isolate);
14988 CHECK(current_isolate == v8::Isolate::GetCurrent());
14989
14990 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14991 last_location = last_message = NULL;
14992 isolate->Dispose();
14993 CHECK_EQ(last_location, NULL);
14994 CHECK_EQ(last_message, NULL);
14995}
14996
14997TEST(IsolateEnterExitDefault) {
14998 v8::HandleScope scope;
14999 LocalContext context;
15000 v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
15001 CHECK(current_isolate != NULL); // Default isolate.
15002 ExpectString("'hello'", "hello");
15003 current_isolate->Enter();
15004 ExpectString("'still working'", "still working");
15005 current_isolate->Exit();
15006 ExpectString("'still working 2'", "still working 2");
15007 current_isolate->Exit();
15008 // Default isolate is always, well, 'default current'.
15009 CHECK_EQ(v8::Isolate::GetCurrent(), current_isolate);
15010 // Still working since default isolate is auto-entering any thread
15011 // that has no isolate and attempts to execute V8 APIs.
15012 ExpectString("'still working 3'", "still working 3");
15013}
15014
15015TEST(DisposeDefaultIsolate) {
15016 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
15017
15018 // Run some V8 code to trigger default isolate to become 'current'.
15019 v8::HandleScope scope;
15020 LocalContext context;
15021 ExpectString("'run some V8'", "run some V8");
15022
15023 v8::Isolate* isolate = v8::Isolate::GetCurrent();
15024 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
15025 last_location = last_message = NULL;
15026 isolate->Dispose();
15027 // It is not possible to dispose default isolate via Isolate API.
15028 CHECK_NE(last_location, NULL);
15029 CHECK_NE(last_message, NULL);
15030}
15031
15032TEST(RunDefaultAndAnotherIsolate) {
15033 v8::HandleScope scope;
15034 LocalContext context;
15035
15036 // Enter new isolate.
15037 v8::Isolate* isolate = v8::Isolate::New();
15038 CHECK(isolate);
15039 isolate->Enter();
15040 { // Need this block because subsequent Exit() will deallocate Heap,
15041 // so we need all scope objects to be deconstructed when it happens.
15042 v8::HandleScope scope_new;
15043 LocalContext context_new;
15044
15045 // Run something in new isolate.
15046 CompileRun("var foo = 153;");
15047 ExpectTrue("function f() { return foo == 153; }; f()");
15048 }
15049 isolate->Exit();
15050
15051 // This runs automatically in default isolate.
15052 // Variables in another isolate should be not available.
15053 ExpectTrue("function f() {"
15054 " try {"
15055 " foo;"
15056 " return false;"
15057 " } catch(e) {"
15058 " return true;"
15059 " }"
15060 "};"
15061 "var bar = 371;"
15062 "f()");
15063
15064 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
15065 last_location = last_message = NULL;
15066 isolate->Dispose();
15067 CHECK_EQ(last_location, NULL);
15068 CHECK_EQ(last_message, NULL);
15069
15070 // Check that default isolate still runs.
15071 ExpectTrue("function f() { return bar == 371; }; f()");
15072}
15073
15074TEST(DisposeIsolateWhenInUse) {
15075 v8::Isolate* isolate = v8::Isolate::New();
15076 CHECK(isolate);
15077 isolate->Enter();
15078 v8::HandleScope scope;
15079 LocalContext context;
15080 // Run something in this isolate.
15081 ExpectTrue("true");
15082 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
15083 last_location = last_message = NULL;
15084 // Still entered, should fail.
15085 isolate->Dispose();
15086 CHECK_NE(last_location, NULL);
15087 CHECK_NE(last_message, NULL);
15088}
15089
15090TEST(RunTwoIsolatesOnSingleThread) {
15091 // Run isolate 1.
15092 v8::Isolate* isolate1 = v8::Isolate::New();
15093 isolate1->Enter();
15094 v8::Persistent<v8::Context> context1 = v8::Context::New();
15095
15096 {
15097 v8::Context::Scope cscope(context1);
15098 v8::HandleScope scope;
15099 // Run something in new isolate.
15100 CompileRun("var foo = 'isolate 1';");
15101 ExpectString("function f() { return foo; }; f()", "isolate 1");
15102 }
15103
15104 // Run isolate 2.
15105 v8::Isolate* isolate2 = v8::Isolate::New();
15106 v8::Persistent<v8::Context> context2;
15107
15108 {
15109 v8::Isolate::Scope iscope(isolate2);
15110 context2 = v8::Context::New();
15111 v8::Context::Scope cscope(context2);
15112 v8::HandleScope scope;
15113
15114 // Run something in new isolate.
15115 CompileRun("var foo = 'isolate 2';");
15116 ExpectString("function f() { return foo; }; f()", "isolate 2");
15117 }
15118
15119 {
15120 v8::Context::Scope cscope(context1);
15121 v8::HandleScope scope;
15122 // Now again in isolate 1
15123 ExpectString("function f() { return foo; }; f()", "isolate 1");
15124 }
15125
15126 isolate1->Exit();
15127
15128 // Run some stuff in default isolate.
15129 v8::Persistent<v8::Context> context_default = v8::Context::New();
15130
15131 {
15132 v8::Context::Scope cscope(context_default);
15133 v8::HandleScope scope;
15134 // Variables in other isolates should be not available, verify there
15135 // is an exception.
15136 ExpectTrue("function f() {"
15137 " try {"
15138 " foo;"
15139 " return false;"
15140 " } catch(e) {"
15141 " return true;"
15142 " }"
15143 "};"
15144 "var isDefaultIsolate = true;"
15145 "f()");
15146 }
15147
15148 isolate1->Enter();
15149
15150 {
15151 v8::Isolate::Scope iscope(isolate2);
15152 v8::Context::Scope cscope(context2);
15153 v8::HandleScope scope;
15154 ExpectString("function f() { return foo; }; f()", "isolate 2");
15155 }
15156
15157 {
15158 v8::Context::Scope cscope(context1);
15159 v8::HandleScope scope;
15160 ExpectString("function f() { return foo; }; f()", "isolate 1");
15161 }
15162
15163 {
15164 v8::Isolate::Scope iscope(isolate2);
15165 context2.Dispose();
15166 }
15167
15168 context1.Dispose();
15169 isolate1->Exit();
15170
15171 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
15172 last_location = last_message = NULL;
15173
15174 isolate1->Dispose();
15175 CHECK_EQ(last_location, NULL);
15176 CHECK_EQ(last_message, NULL);
15177
15178 isolate2->Dispose();
15179 CHECK_EQ(last_location, NULL);
15180 CHECK_EQ(last_message, NULL);
15181
15182 // Check that default isolate still runs.
15183 {
15184 v8::Context::Scope cscope(context_default);
15185 v8::HandleScope scope;
15186 ExpectTrue("function f() { return isDefaultIsolate; }; f()");
15187 }
15188}
15189
15190static int CalcFibonacci(v8::Isolate* isolate, int limit) {
15191 v8::Isolate::Scope isolate_scope(isolate);
15192 v8::HandleScope scope;
15193 LocalContext context;
15194 i::ScopedVector<char> code(1024);
15195 i::OS::SNPrintF(code, "function fib(n) {"
15196 " if (n <= 2) return 1;"
15197 " return fib(n-1) + fib(n-2);"
15198 "}"
15199 "fib(%d)", limit);
15200 Local<Value> value = CompileRun(code.start());
15201 CHECK(value->IsNumber());
15202 return static_cast<int>(value->NumberValue());
15203}
15204
15205class IsolateThread : public v8::internal::Thread {
15206 public:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015207 IsolateThread(v8::Isolate* isolate, int fib_limit)
15208 : Thread("IsolateThread"),
Steve Block44f0eee2011-05-26 01:26:41 +010015209 isolate_(isolate),
15210 fib_limit_(fib_limit),
15211 result_(0) { }
15212
15213 void Run() {
15214 result_ = CalcFibonacci(isolate_, fib_limit_);
15215 }
15216
15217 int result() { return result_; }
15218
15219 private:
15220 v8::Isolate* isolate_;
15221 int fib_limit_;
15222 int result_;
15223};
15224
15225TEST(MultipleIsolatesOnIndividualThreads) {
15226 v8::Isolate* isolate1 = v8::Isolate::New();
15227 v8::Isolate* isolate2 = v8::Isolate::New();
15228
15229 IsolateThread thread1(isolate1, 21);
15230 IsolateThread thread2(isolate2, 12);
15231
15232 // Compute some fibonacci numbers on 3 threads in 3 isolates.
15233 thread1.Start();
15234 thread2.Start();
15235
15236 int result1 = CalcFibonacci(v8::Isolate::GetCurrent(), 21);
15237 int result2 = CalcFibonacci(v8::Isolate::GetCurrent(), 12);
15238
15239 thread1.Join();
15240 thread2.Join();
15241
15242 // Compare results. The actual fibonacci numbers for 12 and 21 are taken
15243 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
15244 CHECK_EQ(result1, 10946);
15245 CHECK_EQ(result2, 144);
15246 CHECK_EQ(result1, thread1.result());
15247 CHECK_EQ(result2, thread2.result());
15248
15249 isolate1->Dispose();
15250 isolate2->Dispose();
15251}
15252
Ben Murdoch257744e2011-11-30 15:57:28 +000015253TEST(IsolateDifferentContexts) {
15254 v8::Isolate* isolate = v8::Isolate::New();
15255 Persistent<v8::Context> context;
15256 {
15257 v8::Isolate::Scope isolate_scope(isolate);
15258 v8::HandleScope handle_scope;
15259 context = v8::Context::New();
15260 v8::Context::Scope context_scope(context);
15261 Local<Value> v = CompileRun("2");
15262 CHECK(v->IsNumber());
15263 CHECK_EQ(2, static_cast<int>(v->NumberValue()));
15264 }
15265 {
15266 v8::Isolate::Scope isolate_scope(isolate);
15267 v8::HandleScope handle_scope;
15268 context = v8::Context::New();
15269 v8::Context::Scope context_scope(context);
15270 Local<Value> v = CompileRun("22");
15271 CHECK(v->IsNumber());
15272 CHECK_EQ(22, static_cast<int>(v->NumberValue()));
15273 }
15274}
Steve Block44f0eee2011-05-26 01:26:41 +010015275
15276class InitDefaultIsolateThread : public v8::internal::Thread {
15277 public:
15278 enum TestCase {
15279 IgnoreOOM,
15280 SetResourceConstraints,
15281 SetFatalHandler,
15282 SetCounterFunction,
15283 SetCreateHistogramFunction,
15284 SetAddHistogramSampleFunction
15285 };
15286
15287 explicit InitDefaultIsolateThread(TestCase testCase)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015288 : Thread("InitDefaultIsolateThread"),
Steve Block44f0eee2011-05-26 01:26:41 +010015289 testCase_(testCase),
15290 result_(false) { }
15291
15292 void Run() {
15293 switch (testCase_) {
15294 case IgnoreOOM:
15295 v8::V8::IgnoreOutOfMemoryException();
15296 break;
15297
15298 case SetResourceConstraints: {
15299 static const int K = 1024;
15300 v8::ResourceConstraints constraints;
15301 constraints.set_max_young_space_size(256 * K);
15302 constraints.set_max_old_space_size(4 * K * K);
15303 v8::SetResourceConstraints(&constraints);
15304 break;
15305 }
15306
15307 case SetFatalHandler:
15308 v8::V8::SetFatalErrorHandler(NULL);
15309 break;
15310
15311 case SetCounterFunction:
15312 v8::V8::SetCounterFunction(NULL);
15313 break;
15314
15315 case SetCreateHistogramFunction:
15316 v8::V8::SetCreateHistogramFunction(NULL);
15317 break;
15318
15319 case SetAddHistogramSampleFunction:
15320 v8::V8::SetAddHistogramSampleFunction(NULL);
15321 break;
15322 }
15323 result_ = true;
15324 }
15325
15326 bool result() { return result_; }
15327
15328 private:
15329 TestCase testCase_;
15330 bool result_;
15331};
15332
15333
15334static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
15335 InitDefaultIsolateThread thread(testCase);
15336 thread.Start();
15337 thread.Join();
15338 CHECK_EQ(thread.result(), true);
15339}
15340
15341TEST(InitializeDefaultIsolateOnSecondaryThread1) {
15342 InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM);
15343}
15344
15345TEST(InitializeDefaultIsolateOnSecondaryThread2) {
15346 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
15347}
15348
15349TEST(InitializeDefaultIsolateOnSecondaryThread3) {
15350 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
15351}
15352
15353TEST(InitializeDefaultIsolateOnSecondaryThread4) {
15354 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
15355}
15356
15357TEST(InitializeDefaultIsolateOnSecondaryThread5) {
15358 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
15359}
15360
15361TEST(InitializeDefaultIsolateOnSecondaryThread6) {
15362 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
15363}
15364
Kristian Monsen0d5e1162010-09-30 15:31:59 +010015365
15366TEST(StringCheckMultipleContexts) {
15367 const char* code =
15368 "(function() { return \"a\".charAt(0); })()";
15369
15370 {
15371 // Run the code twice in the first context to initialize the call IC.
15372 v8::HandleScope scope;
15373 LocalContext context1;
15374 ExpectString(code, "a");
15375 ExpectString(code, "a");
15376 }
15377
15378 {
15379 // Change the String.prototype in the second context and check
15380 // that the right function gets called.
15381 v8::HandleScope scope;
15382 LocalContext context2;
15383 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
15384 ExpectString(code, "not a");
15385 }
15386}
15387
15388
15389TEST(NumberCheckMultipleContexts) {
15390 const char* code =
15391 "(function() { return (42).toString(); })()";
15392
15393 {
15394 // Run the code twice in the first context to initialize the call IC.
15395 v8::HandleScope scope;
15396 LocalContext context1;
15397 ExpectString(code, "42");
15398 ExpectString(code, "42");
15399 }
15400
15401 {
15402 // Change the Number.prototype in the second context and check
15403 // that the right function gets called.
15404 v8::HandleScope scope;
15405 LocalContext context2;
15406 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
15407 ExpectString(code, "not 42");
15408 }
15409}
15410
15411
15412TEST(BooleanCheckMultipleContexts) {
15413 const char* code =
15414 "(function() { return true.toString(); })()";
15415
15416 {
15417 // Run the code twice in the first context to initialize the call IC.
15418 v8::HandleScope scope;
15419 LocalContext context1;
15420 ExpectString(code, "true");
15421 ExpectString(code, "true");
15422 }
15423
15424 {
15425 // Change the Boolean.prototype in the second context and check
15426 // that the right function gets called.
15427 v8::HandleScope scope;
15428 LocalContext context2;
15429 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
15430 ExpectString(code, "");
15431 }
15432}
Ben Murdochf87a2032010-10-22 12:50:53 +010015433
15434
15435TEST(DontDeleteCellLoadIC) {
15436 const char* function_code =
15437 "function readCell() { while (true) { return cell; } }";
15438
15439 {
15440 // Run the code twice in the first context to initialize the load
15441 // IC for a don't delete cell.
15442 v8::HandleScope scope;
15443 LocalContext context1;
15444 CompileRun("var cell = \"first\";");
15445 ExpectBoolean("delete cell", false);
15446 CompileRun(function_code);
15447 ExpectString("readCell()", "first");
15448 ExpectString("readCell()", "first");
15449 }
15450
15451 {
15452 // Use a deletable cell in the second context.
15453 v8::HandleScope scope;
15454 LocalContext context2;
15455 CompileRun("cell = \"second\";");
15456 CompileRun(function_code);
15457 ExpectString("readCell()", "second");
15458 ExpectBoolean("delete cell", true);
15459 ExpectString("(function() {"
15460 " try {"
15461 " return readCell();"
15462 " } catch(e) {"
15463 " return e.toString();"
15464 " }"
15465 "})()",
15466 "ReferenceError: cell is not defined");
15467 CompileRun("cell = \"new_second\";");
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015468 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Ben Murdochf87a2032010-10-22 12:50:53 +010015469 ExpectString("readCell()", "new_second");
15470 ExpectString("readCell()", "new_second");
15471 }
15472}
15473
15474
15475TEST(DontDeleteCellLoadICForceDelete) {
15476 const char* function_code =
15477 "function readCell() { while (true) { return cell; } }";
15478
15479 // Run the code twice to initialize the load IC for a don't delete
15480 // cell.
15481 v8::HandleScope scope;
15482 LocalContext context;
15483 CompileRun("var cell = \"value\";");
15484 ExpectBoolean("delete cell", false);
15485 CompileRun(function_code);
15486 ExpectString("readCell()", "value");
15487 ExpectString("readCell()", "value");
15488
15489 // Delete the cell using the API and check the inlined code works
15490 // correctly.
15491 CHECK(context->Global()->ForceDelete(v8_str("cell")));
15492 ExpectString("(function() {"
15493 " try {"
15494 " return readCell();"
15495 " } catch(e) {"
15496 " return e.toString();"
15497 " }"
15498 "})()",
15499 "ReferenceError: cell is not defined");
15500}
15501
15502
15503TEST(DontDeleteCellLoadICAPI) {
15504 const char* function_code =
15505 "function readCell() { while (true) { return cell; } }";
15506
15507 // Run the code twice to initialize the load IC for a don't delete
15508 // cell created using the API.
15509 v8::HandleScope scope;
15510 LocalContext context;
15511 context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
15512 ExpectBoolean("delete cell", false);
15513 CompileRun(function_code);
15514 ExpectString("readCell()", "value");
15515 ExpectString("readCell()", "value");
15516
15517 // Delete the cell using the API and check the inlined code works
15518 // correctly.
15519 CHECK(context->Global()->ForceDelete(v8_str("cell")));
15520 ExpectString("(function() {"
15521 " try {"
15522 " return readCell();"
15523 " } catch(e) {"
15524 " return e.toString();"
15525 " }"
15526 "})()",
15527 "ReferenceError: cell is not defined");
15528}
15529
15530
Ben Murdochf87a2032010-10-22 12:50:53 +010015531TEST(RegExp) {
15532 v8::HandleScope scope;
15533 LocalContext context;
15534
15535 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
15536 CHECK(re->IsRegExp());
15537 CHECK(re->GetSource()->Equals(v8_str("foo")));
Ben Murdoch69a99ed2011-11-30 16:03:39 +000015538 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
Ben Murdochf87a2032010-10-22 12:50:53 +010015539
15540 re = v8::RegExp::New(v8_str("bar"),
15541 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
15542 v8::RegExp::kGlobal));
15543 CHECK(re->IsRegExp());
15544 CHECK(re->GetSource()->Equals(v8_str("bar")));
Ben Murdoch69a99ed2011-11-30 16:03:39 +000015545 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
15546 static_cast<int>(re->GetFlags()));
Ben Murdochf87a2032010-10-22 12:50:53 +010015547
15548 re = v8::RegExp::New(v8_str("baz"),
15549 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
15550 v8::RegExp::kMultiline));
15551 CHECK(re->IsRegExp());
15552 CHECK(re->GetSource()->Equals(v8_str("baz")));
Ben Murdoch69a99ed2011-11-30 16:03:39 +000015553 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
15554 static_cast<int>(re->GetFlags()));
Ben Murdochf87a2032010-10-22 12:50:53 +010015555
15556 re = CompileRun("/quux/").As<v8::RegExp>();
15557 CHECK(re->IsRegExp());
15558 CHECK(re->GetSource()->Equals(v8_str("quux")));
Ben Murdoch69a99ed2011-11-30 16:03:39 +000015559 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
Ben Murdochf87a2032010-10-22 12:50:53 +010015560
15561 re = CompileRun("/quux/gm").As<v8::RegExp>();
15562 CHECK(re->IsRegExp());
15563 CHECK(re->GetSource()->Equals(v8_str("quux")));
Ben Murdoch69a99ed2011-11-30 16:03:39 +000015564 CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
15565 static_cast<int>(re->GetFlags()));
Ben Murdochf87a2032010-10-22 12:50:53 +010015566
15567 // Override the RegExp constructor and check the API constructor
15568 // still works.
15569 CompileRun("RegExp = function() {}");
15570
15571 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
15572 CHECK(re->IsRegExp());
15573 CHECK(re->GetSource()->Equals(v8_str("foobar")));
Ben Murdoch69a99ed2011-11-30 16:03:39 +000015574 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
Ben Murdochf87a2032010-10-22 12:50:53 +010015575
15576 re = v8::RegExp::New(v8_str("foobarbaz"),
15577 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
15578 v8::RegExp::kMultiline));
15579 CHECK(re->IsRegExp());
15580 CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
Ben Murdoch69a99ed2011-11-30 16:03:39 +000015581 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
15582 static_cast<int>(re->GetFlags()));
Ben Murdochf87a2032010-10-22 12:50:53 +010015583
15584 context->Global()->Set(v8_str("re"), re);
15585 ExpectTrue("re.test('FoobarbaZ')");
15586
Ben Murdoch257744e2011-11-30 15:57:28 +000015587 // RegExps are objects on which you can set properties.
15588 re->Set(v8_str("property"), v8::Integer::New(32));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015589 v8::Handle<v8::Value> value(CompileRun("re.property"));
15590 CHECK_EQ(32, value->Int32Value());
Ben Murdoch257744e2011-11-30 15:57:28 +000015591
Ben Murdochf87a2032010-10-22 12:50:53 +010015592 v8::TryCatch try_catch;
15593 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
15594 CHECK(re.IsEmpty());
15595 CHECK(try_catch.HasCaught());
15596 context->Global()->Set(v8_str("ex"), try_catch.Exception());
15597 ExpectTrue("ex instanceof SyntaxError");
15598}
15599
15600
Steve Block1e0659c2011-05-24 12:43:12 +010015601THREADED_TEST(Equals) {
15602 v8::HandleScope handleScope;
15603 LocalContext localContext;
15604
15605 v8::Handle<v8::Object> globalProxy = localContext->Global();
15606 v8::Handle<Value> global = globalProxy->GetPrototype();
15607
15608 CHECK(global->StrictEquals(global));
15609 CHECK(!global->StrictEquals(globalProxy));
15610 CHECK(!globalProxy->StrictEquals(global));
15611 CHECK(globalProxy->StrictEquals(globalProxy));
15612
15613 CHECK(global->Equals(global));
15614 CHECK(!global->Equals(globalProxy));
15615 CHECK(!globalProxy->Equals(global));
15616 CHECK(globalProxy->Equals(globalProxy));
15617}
15618
15619
Ben Murdochf87a2032010-10-22 12:50:53 +010015620static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
15621 const v8::AccessorInfo& info ) {
15622 return v8_str("42!");
15623}
15624
15625
15626static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo& info) {
15627 v8::Handle<v8::Array> result = v8::Array::New();
15628 result->Set(0, v8_str("universalAnswer"));
15629 return result;
15630}
15631
15632
15633TEST(NamedEnumeratorAndForIn) {
15634 v8::HandleScope handle_scope;
15635 LocalContext context;
15636 v8::Context::Scope context_scope(context.local());
15637
15638 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New();
15639 tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
15640 context->Global()->Set(v8_str("o"), tmpl->NewInstance());
15641 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
15642 "var result = []; for (var k in o) result.push(k); result"));
15643 CHECK_EQ(1, result->Length());
15644 CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
15645}
Steve Block1e0659c2011-05-24 12:43:12 +010015646
15647
15648TEST(DefinePropertyPostDetach) {
15649 v8::HandleScope scope;
15650 LocalContext context;
15651 v8::Handle<v8::Object> proxy = context->Global();
15652 v8::Handle<v8::Function> define_property =
15653 CompileRun("(function() {"
15654 " Object.defineProperty("
15655 " this,"
15656 " 1,"
15657 " { configurable: true, enumerable: true, value: 3 });"
15658 "})").As<Function>();
15659 context->DetachGlobal();
15660 define_property->Call(proxy, 0, NULL);
15661}
Ben Murdoch8b112d22011-06-08 16:22:53 +010015662
15663
15664static void InstallContextId(v8::Handle<Context> context, int id) {
15665 Context::Scope scope(context);
15666 CompileRun("Object.prototype").As<Object>()->
15667 Set(v8_str("context_id"), v8::Integer::New(id));
15668}
15669
15670
15671static void CheckContextId(v8::Handle<Object> object, int expected) {
15672 CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
15673}
15674
15675
15676THREADED_TEST(CreationContext) {
15677 HandleScope handle_scope;
15678 Persistent<Context> context1 = Context::New();
15679 InstallContextId(context1, 1);
15680 Persistent<Context> context2 = Context::New();
15681 InstallContextId(context2, 2);
15682 Persistent<Context> context3 = Context::New();
15683 InstallContextId(context3, 3);
15684
15685 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New();
15686
15687 Local<Object> object1;
15688 Local<Function> func1;
15689 {
15690 Context::Scope scope(context1);
15691 object1 = Object::New();
15692 func1 = tmpl->GetFunction();
15693 }
15694
15695 Local<Object> object2;
15696 Local<Function> func2;
15697 {
15698 Context::Scope scope(context2);
15699 object2 = Object::New();
15700 func2 = tmpl->GetFunction();
15701 }
15702
15703 Local<Object> instance1;
15704 Local<Object> instance2;
15705
15706 {
15707 Context::Scope scope(context3);
15708 instance1 = func1->NewInstance();
15709 instance2 = func2->NewInstance();
15710 }
15711
15712 CHECK(object1->CreationContext() == context1);
15713 CheckContextId(object1, 1);
15714 CHECK(func1->CreationContext() == context1);
15715 CheckContextId(func1, 1);
15716 CHECK(instance1->CreationContext() == context1);
15717 CheckContextId(instance1, 1);
15718 CHECK(object2->CreationContext() == context2);
15719 CheckContextId(object2, 2);
15720 CHECK(func2->CreationContext() == context2);
15721 CheckContextId(func2, 2);
15722 CHECK(instance2->CreationContext() == context2);
15723 CheckContextId(instance2, 2);
15724
15725 {
15726 Context::Scope scope(context1);
15727 CHECK(object1->CreationContext() == context1);
15728 CheckContextId(object1, 1);
15729 CHECK(func1->CreationContext() == context1);
15730 CheckContextId(func1, 1);
15731 CHECK(instance1->CreationContext() == context1);
15732 CheckContextId(instance1, 1);
15733 CHECK(object2->CreationContext() == context2);
15734 CheckContextId(object2, 2);
15735 CHECK(func2->CreationContext() == context2);
15736 CheckContextId(func2, 2);
15737 CHECK(instance2->CreationContext() == context2);
15738 CheckContextId(instance2, 2);
15739 }
15740
15741 {
15742 Context::Scope scope(context2);
15743 CHECK(object1->CreationContext() == context1);
15744 CheckContextId(object1, 1);
15745 CHECK(func1->CreationContext() == context1);
15746 CheckContextId(func1, 1);
15747 CHECK(instance1->CreationContext() == context1);
15748 CheckContextId(instance1, 1);
15749 CHECK(object2->CreationContext() == context2);
15750 CheckContextId(object2, 2);
15751 CHECK(func2->CreationContext() == context2);
15752 CheckContextId(func2, 2);
15753 CHECK(instance2->CreationContext() == context2);
15754 CheckContextId(instance2, 2);
15755 }
15756
15757 context1.Dispose();
15758 context2.Dispose();
15759 context3.Dispose();
15760}
Ben Murdoch257744e2011-11-30 15:57:28 +000015761
15762
Ben Murdoch69a99ed2011-11-30 16:03:39 +000015763THREADED_TEST(CreationContextOfJsFunction) {
15764 HandleScope handle_scope;
15765 Persistent<Context> context = Context::New();
15766 InstallContextId(context, 1);
15767
15768 Local<Object> function;
15769 {
15770 Context::Scope scope(context);
15771 function = CompileRun("function foo() {}; foo").As<Object>();
15772 }
15773
15774 CHECK(function->CreationContext() == context);
15775 CheckContextId(function, 1);
15776
15777 context.Dispose();
15778}
15779
15780
Ben Murdoch257744e2011-11-30 15:57:28 +000015781Handle<Value> HasOwnPropertyIndexedPropertyGetter(uint32_t index,
15782 const AccessorInfo& info) {
15783 if (index == 42) return v8_str("yes");
15784 return Handle<v8::Integer>();
15785}
15786
15787
15788Handle<Value> HasOwnPropertyNamedPropertyGetter(Local<String> property,
15789 const AccessorInfo& info) {
15790 if (property->Equals(v8_str("foo"))) return v8_str("yes");
15791 return Handle<Value>();
15792}
15793
15794
15795Handle<v8::Integer> HasOwnPropertyIndexedPropertyQuery(
15796 uint32_t index, const AccessorInfo& info) {
15797 if (index == 42) return v8_num(1).As<v8::Integer>();
15798 return Handle<v8::Integer>();
15799}
15800
15801
15802Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery(
15803 Local<String> property, const AccessorInfo& info) {
15804 if (property->Equals(v8_str("foo"))) return v8_num(1).As<v8::Integer>();
15805 return Handle<v8::Integer>();
15806}
15807
15808
15809Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery2(
15810 Local<String> property, const AccessorInfo& info) {
15811 if (property->Equals(v8_str("bar"))) return v8_num(1).As<v8::Integer>();
15812 return Handle<v8::Integer>();
15813}
15814
15815
15816Handle<Value> HasOwnPropertyAccessorGetter(Local<String> property,
15817 const AccessorInfo& info) {
15818 return v8_str("yes");
15819}
15820
15821
15822TEST(HasOwnProperty) {
15823 v8::HandleScope scope;
15824 LocalContext env;
15825 { // Check normal properties and defined getters.
15826 Handle<Value> value = CompileRun(
15827 "function Foo() {"
15828 " this.foo = 11;"
15829 " this.__defineGetter__('baz', function() { return 1; });"
15830 "};"
15831 "function Bar() { "
15832 " this.bar = 13;"
15833 " this.__defineGetter__('bla', function() { return 2; });"
15834 "};"
15835 "Bar.prototype = new Foo();"
15836 "new Bar();");
15837 CHECK(value->IsObject());
15838 Handle<Object> object = value->ToObject();
15839 CHECK(object->Has(v8_str("foo")));
15840 CHECK(!object->HasOwnProperty(v8_str("foo")));
15841 CHECK(object->HasOwnProperty(v8_str("bar")));
15842 CHECK(object->Has(v8_str("baz")));
15843 CHECK(!object->HasOwnProperty(v8_str("baz")));
15844 CHECK(object->HasOwnProperty(v8_str("bla")));
15845 }
15846 { // Check named getter interceptors.
15847 Handle<ObjectTemplate> templ = ObjectTemplate::New();
15848 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
15849 Handle<Object> instance = templ->NewInstance();
15850 CHECK(!instance->HasOwnProperty(v8_str("42")));
15851 CHECK(instance->HasOwnProperty(v8_str("foo")));
15852 CHECK(!instance->HasOwnProperty(v8_str("bar")));
15853 }
15854 { // Check indexed getter interceptors.
15855 Handle<ObjectTemplate> templ = ObjectTemplate::New();
15856 templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
15857 Handle<Object> instance = templ->NewInstance();
15858 CHECK(instance->HasOwnProperty(v8_str("42")));
15859 CHECK(!instance->HasOwnProperty(v8_str("43")));
15860 CHECK(!instance->HasOwnProperty(v8_str("foo")));
15861 }
15862 { // Check named query interceptors.
15863 Handle<ObjectTemplate> templ = ObjectTemplate::New();
15864 templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
15865 Handle<Object> instance = templ->NewInstance();
15866 CHECK(instance->HasOwnProperty(v8_str("foo")));
15867 CHECK(!instance->HasOwnProperty(v8_str("bar")));
15868 }
15869 { // Check indexed query interceptors.
15870 Handle<ObjectTemplate> templ = ObjectTemplate::New();
15871 templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
15872 Handle<Object> instance = templ->NewInstance();
15873 CHECK(instance->HasOwnProperty(v8_str("42")));
15874 CHECK(!instance->HasOwnProperty(v8_str("41")));
15875 }
15876 { // Check callbacks.
15877 Handle<ObjectTemplate> templ = ObjectTemplate::New();
15878 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
15879 Handle<Object> instance = templ->NewInstance();
15880 CHECK(instance->HasOwnProperty(v8_str("foo")));
15881 CHECK(!instance->HasOwnProperty(v8_str("bar")));
15882 }
15883 { // Check that query wins on disagreement.
15884 Handle<ObjectTemplate> templ = ObjectTemplate::New();
15885 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
15886 0,
15887 HasOwnPropertyNamedPropertyQuery2);
15888 Handle<Object> instance = templ->NewInstance();
15889 CHECK(!instance->HasOwnProperty(v8_str("foo")));
15890 CHECK(instance->HasOwnProperty(v8_str("bar")));
15891 }
15892}
15893
15894
15895void CheckCodeGenerationAllowed() {
15896 Handle<Value> result = CompileRun("eval('42')");
15897 CHECK_EQ(42, result->Int32Value());
15898 result = CompileRun("(function(e) { return e('42'); })(eval)");
15899 CHECK_EQ(42, result->Int32Value());
15900 result = CompileRun("var f = new Function('return 42'); f()");
15901 CHECK_EQ(42, result->Int32Value());
15902}
15903
15904
15905void CheckCodeGenerationDisallowed() {
15906 TryCatch try_catch;
15907
15908 Handle<Value> result = CompileRun("eval('42')");
15909 CHECK(result.IsEmpty());
15910 CHECK(try_catch.HasCaught());
15911 try_catch.Reset();
15912
15913 result = CompileRun("(function(e) { return e('42'); })(eval)");
15914 CHECK(result.IsEmpty());
15915 CHECK(try_catch.HasCaught());
15916 try_catch.Reset();
15917
15918 result = CompileRun("var f = new Function('return 42'); f()");
15919 CHECK(result.IsEmpty());
15920 CHECK(try_catch.HasCaught());
15921}
15922
15923
15924bool CodeGenerationAllowed(Local<Context> context) {
15925 ApiTestFuzzer::Fuzz();
15926 return true;
15927}
15928
15929
15930bool CodeGenerationDisallowed(Local<Context> context) {
15931 ApiTestFuzzer::Fuzz();
15932 return false;
15933}
15934
15935
15936THREADED_TEST(AllowCodeGenFromStrings) {
15937 v8::HandleScope scope;
15938 LocalContext context;
15939
15940 // eval and the Function constructor allowed by default.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015941 CHECK(context->IsCodeGenerationFromStringsAllowed());
Ben Murdoch257744e2011-11-30 15:57:28 +000015942 CheckCodeGenerationAllowed();
15943
15944 // Disallow eval and the Function constructor.
15945 context->AllowCodeGenerationFromStrings(false);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015946 CHECK(!context->IsCodeGenerationFromStringsAllowed());
Ben Murdoch257744e2011-11-30 15:57:28 +000015947 CheckCodeGenerationDisallowed();
15948
15949 // Allow again.
15950 context->AllowCodeGenerationFromStrings(true);
15951 CheckCodeGenerationAllowed();
15952
15953 // Disallow but setting a global callback that will allow the calls.
15954 context->AllowCodeGenerationFromStrings(false);
15955 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015956 CHECK(!context->IsCodeGenerationFromStringsAllowed());
Ben Murdoch257744e2011-11-30 15:57:28 +000015957 CheckCodeGenerationAllowed();
15958
15959 // Set a callback that disallows the code generation.
15960 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015961 CHECK(!context->IsCodeGenerationFromStringsAllowed());
Ben Murdoch257744e2011-11-30 15:57:28 +000015962 CheckCodeGenerationDisallowed();
15963}
15964
15965
15966static v8::Handle<Value> NonObjectThis(const v8::Arguments& args) {
15967 return v8::Undefined();
15968}
15969
15970
15971THREADED_TEST(CallAPIFunctionOnNonObject) {
15972 v8::HandleScope scope;
15973 LocalContext context;
15974 Handle<FunctionTemplate> templ = v8::FunctionTemplate::New(NonObjectThis);
15975 Handle<Function> function = templ->GetFunction();
15976 context->Global()->Set(v8_str("f"), function);
15977 TryCatch try_catch;
15978 CompileRun("f.call(2)");
15979}
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015980
15981
15982// Regression test for issue 1470.
15983THREADED_TEST(ReadOnlyIndexedProperties) {
15984 v8::HandleScope scope;
15985 Local<ObjectTemplate> templ = ObjectTemplate::New();
15986
15987 LocalContext context;
15988 Local<v8::Object> obj = templ->NewInstance();
15989 context->Global()->Set(v8_str("obj"), obj);
15990 obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
15991 obj->Set(v8_str("1"), v8_str("foobar"));
15992 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
15993 obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
15994 obj->Set(v8_num(2), v8_str("foobar"));
15995 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
15996
15997 // Test non-smi case.
15998 obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
15999 obj->Set(v8_str("2000000000"), v8_str("foobar"));
16000 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
16001}
16002
16003
16004THREADED_TEST(Regress1516) {
16005 v8::HandleScope scope;
16006
16007 LocalContext context;
16008 { v8::HandleScope temp_scope;
16009 CompileRun("({'a': 0})");
16010 }
16011
16012 int elements;
16013 { i::MapCache* map_cache =
16014 i::MapCache::cast(i::Isolate::Current()->context()->map_cache());
16015 elements = map_cache->NumberOfElements();
16016 CHECK_LE(1, elements);
16017 }
16018
16019 i::Isolate::Current()->heap()->CollectAllGarbage(true);
16020 { i::Object* raw_map_cache = i::Isolate::Current()->context()->map_cache();
16021 if (raw_map_cache != i::Isolate::Current()->heap()->undefined_value()) {
16022 i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
16023 CHECK_GT(elements, map_cache->NumberOfElements());
16024 }
16025 }
16026}
16027
16028
16029static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
16030 Local<Value> name,
16031 v8::AccessType type,
16032 Local<Value> data) {
16033 // Only block read access to __proto__.
16034 if (type == v8::ACCESS_GET &&
16035 name->IsString() &&
16036 name->ToString()->Length() == 9 &&
16037 name->ToString()->Utf8Length() == 9) {
16038 char buffer[10];
16039 CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
16040 return strncmp(buffer, "__proto__", 9) != 0;
16041 }
16042
16043 return true;
16044}
16045
16046
16047THREADED_TEST(Regress93759) {
16048 HandleScope scope;
16049
16050 // Template for object with security check.
16051 Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New();
16052 // We don't do indexing, so any callback can be used for that.
16053 no_proto_template->SetAccessCheckCallbacks(
16054 BlockProtoNamedSecurityTestCallback,
16055 IndexedSecurityTestCallback);
16056
16057 // Templates for objects with hidden prototypes and possibly security check.
16058 Local<FunctionTemplate> hidden_proto_template = v8::FunctionTemplate::New();
16059 hidden_proto_template->SetHiddenPrototype(true);
16060
16061 Local<FunctionTemplate> protected_hidden_proto_template =
16062 v8::FunctionTemplate::New();
16063 protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
16064 BlockProtoNamedSecurityTestCallback,
16065 IndexedSecurityTestCallback);
16066 protected_hidden_proto_template->SetHiddenPrototype(true);
16067
16068 // Context for "foreign" objects used in test.
16069 Persistent<Context> context = v8::Context::New();
16070 context->Enter();
16071
16072 // Plain object, no security check.
16073 Local<Object> simple_object = Object::New();
16074
16075 // Object with explicit security check.
16076 Local<Object> protected_object =
16077 no_proto_template->NewInstance();
16078
16079 // JSGlobalProxy object, always have security check.
16080 Local<Object> proxy_object =
16081 context->Global();
16082
16083 // Global object, the prototype of proxy_object. No security checks.
16084 Local<Object> global_object =
16085 proxy_object->GetPrototype()->ToObject();
16086
16087 // Hidden prototype without security check.
16088 Local<Object> hidden_prototype =
16089 hidden_proto_template->GetFunction()->NewInstance();
16090 Local<Object> object_with_hidden =
16091 Object::New();
16092 object_with_hidden->SetPrototype(hidden_prototype);
16093
16094 // Hidden prototype with security check on the hidden prototype.
16095 Local<Object> protected_hidden_prototype =
16096 protected_hidden_proto_template->GetFunction()->NewInstance();
16097 Local<Object> object_with_protected_hidden =
16098 Object::New();
16099 object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
16100
16101 context->Exit();
16102
16103 // Template for object for second context. Values to test are put on it as
16104 // properties.
16105 Local<ObjectTemplate> global_template = ObjectTemplate::New();
16106 global_template->Set(v8_str("simple"), simple_object);
16107 global_template->Set(v8_str("protected"), protected_object);
16108 global_template->Set(v8_str("global"), global_object);
16109 global_template->Set(v8_str("proxy"), proxy_object);
16110 global_template->Set(v8_str("hidden"), object_with_hidden);
16111 global_template->Set(v8_str("phidden"), object_with_protected_hidden);
16112
16113 LocalContext context2(NULL, global_template);
16114
16115 Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
16116 CHECK(result1->Equals(simple_object->GetPrototype()));
16117
16118 Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
16119 CHECK(result2->Equals(Undefined()));
16120
16121 Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
16122 CHECK(result3->Equals(global_object->GetPrototype()));
16123
16124 Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
16125 CHECK(result4->Equals(Undefined()));
16126
16127 Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
16128 CHECK(result5->Equals(
16129 object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
16130
16131 Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
16132 CHECK(result6->Equals(Undefined()));
16133
16134 context.Dispose();
16135}
Ben Murdoch69a99ed2011-11-30 16:03:39 +000016136
16137
Ben Murdoch5710cea2012-05-21 14:52:42 +010016138THREADED_TEST(Regress125988) {
16139 v8::HandleScope scope;
16140 Handle<FunctionTemplate> intercept = FunctionTemplate::New();
16141 AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
16142 LocalContext env;
16143 env->Global()->Set(v8_str("Intercept"), intercept->GetFunction());
16144 CompileRun("var a = new Object();"
16145 "var b = new Intercept();"
16146 "var c = new Object();"
16147 "c.__proto__ = b;"
16148 "b.__proto__ = a;"
16149 "a.x = 23;"
16150 "for (var i = 0; i < 3; i++) c.x;");
16151 ExpectBoolean("c.hasOwnProperty('x')", false);
16152 ExpectInt32("c.x", 23);
16153 CompileRun("a.y = 42;"
16154 "for (var i = 0; i < 3; i++) c.x;");
16155 ExpectBoolean("c.hasOwnProperty('x')", false);
16156 ExpectInt32("c.x", 23);
16157 ExpectBoolean("c.hasOwnProperty('y')", false);
16158 ExpectInt32("c.y", 42);
16159}
16160
16161
Ben Murdoch69a99ed2011-11-30 16:03:39 +000016162static void TestReceiver(Local<Value> expected_result,
16163 Local<Value> expected_receiver,
16164 const char* code) {
16165 Local<Value> result = CompileRun(code);
16166 CHECK(result->IsObject());
16167 CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
16168 CHECK(expected_result->Equals(result->ToObject()->Get(0)));
16169}
16170
16171
16172THREADED_TEST(ForeignFunctionReceiver) {
16173 HandleScope scope;
16174
16175 // Create two contexts with different "id" properties ('i' and 'o').
16176 // Call a function both from its own context and from a the foreign
16177 // context, and see what "this" is bound to (returning both "this"
16178 // and "this.id" for comparison).
16179
16180 Persistent<Context> foreign_context = v8::Context::New();
16181 foreign_context->Enter();
16182 Local<Value> foreign_function =
16183 CompileRun("function func() { return { 0: this.id, "
16184 " 1: this, "
16185 " toString: function() { "
16186 " return this[0];"
16187 " }"
16188 " };"
16189 "}"
16190 "var id = 'i';"
16191 "func;");
16192 CHECK(foreign_function->IsFunction());
16193 foreign_context->Exit();
16194
16195 LocalContext context;
16196
16197 Local<String> password = v8_str("Password");
16198 // Don't get hit by security checks when accessing foreign_context's
16199 // global receiver (aka. global proxy).
16200 context->SetSecurityToken(password);
16201 foreign_context->SetSecurityToken(password);
16202
16203 Local<String> i = v8_str("i");
16204 Local<String> o = v8_str("o");
16205 Local<String> id = v8_str("id");
16206
16207 CompileRun("function ownfunc() { return { 0: this.id, "
16208 " 1: this, "
16209 " toString: function() { "
16210 " return this[0];"
16211 " }"
16212 " };"
16213 "}"
16214 "var id = 'o';"
16215 "ownfunc");
16216 context->Global()->Set(v8_str("func"), foreign_function);
16217
16218 // Sanity check the contexts.
16219 CHECK(i->Equals(foreign_context->Global()->Get(id)));
16220 CHECK(o->Equals(context->Global()->Get(id)));
16221
16222 // Checking local function's receiver.
16223 // Calling function using its call/apply methods.
16224 TestReceiver(o, context->Global(), "ownfunc.call()");
16225 TestReceiver(o, context->Global(), "ownfunc.apply()");
16226 // Making calls through built-in functions.
16227 TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
16228 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
16229 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
16230 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
16231 // Calling with environment record as base.
16232 TestReceiver(o, context->Global(), "ownfunc()");
16233 // Calling with no base.
16234 TestReceiver(o, context->Global(), "(1,ownfunc)()");
16235
16236 // Checking foreign function return value.
16237 // Calling function using its call/apply methods.
16238 TestReceiver(i, foreign_context->Global(), "func.call()");
16239 TestReceiver(i, foreign_context->Global(), "func.apply()");
16240 // Calling function using another context's call/apply methods.
16241 TestReceiver(i, foreign_context->Global(),
16242 "Function.prototype.call.call(func)");
16243 TestReceiver(i, foreign_context->Global(),
16244 "Function.prototype.call.apply(func)");
16245 TestReceiver(i, foreign_context->Global(),
16246 "Function.prototype.apply.call(func)");
16247 TestReceiver(i, foreign_context->Global(),
16248 "Function.prototype.apply.apply(func)");
16249 // Making calls through built-in functions.
16250 TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
16251 // ToString(func()) is func()[0], i.e., the returned this.id.
16252 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
16253 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
16254 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
16255
16256 // TODO(1547): Make the following also return "i".
16257 // Calling with environment record as base.
16258 TestReceiver(o, context->Global(), "func()");
16259 // Calling with no base.
16260 TestReceiver(o, context->Global(), "(1,func)()");
16261
16262 foreign_context.Dispose();
16263}
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016264
16265
16266uint8_t callback_fired = 0;
16267
16268
16269void CallCompletedCallback1() {
16270 i::OS::Print("Firing callback 1.\n");
16271 callback_fired ^= 1; // Toggle first bit.
16272}
16273
16274
16275void CallCompletedCallback2() {
16276 i::OS::Print("Firing callback 2.\n");
16277 callback_fired ^= 2; // Toggle second bit.
16278}
16279
16280
16281Handle<Value> RecursiveCall(const Arguments& args) {
16282 int32_t level = args[0]->Int32Value();
16283 if (level < 3) {
16284 level++;
16285 i::OS::Print("Entering recursion level %d.\n", level);
16286 char script[64];
16287 i::Vector<char> script_vector(script, sizeof(script));
16288 i::OS::SNPrintF(script_vector, "recursion(%d)", level);
16289 CompileRun(script_vector.start());
16290 i::OS::Print("Leaving recursion level %d.\n", level);
16291 CHECK_EQ(0, callback_fired);
16292 } else {
16293 i::OS::Print("Recursion ends.\n");
16294 CHECK_EQ(0, callback_fired);
16295 }
16296 return Undefined();
16297}
16298
16299
16300TEST(CallCompletedCallback) {
16301 v8::HandleScope scope;
16302 LocalContext env;
16303 v8::Handle<v8::FunctionTemplate> recursive_runtime =
16304 v8::FunctionTemplate::New(RecursiveCall);
16305 env->Global()->Set(v8_str("recursion"),
16306 recursive_runtime->GetFunction());
16307 // Adding the same callback a second time has no effect.
16308 v8::V8::AddCallCompletedCallback(CallCompletedCallback1);
16309 v8::V8::AddCallCompletedCallback(CallCompletedCallback1);
16310 v8::V8::AddCallCompletedCallback(CallCompletedCallback2);
16311 i::OS::Print("--- Script (1) ---\n");
16312 Local<Script> script =
16313 v8::Script::Compile(v8::String::New("recursion(0)"));
16314 script->Run();
16315 CHECK_EQ(3, callback_fired);
16316
16317 i::OS::Print("\n--- Script (2) ---\n");
16318 callback_fired = 0;
16319 v8::V8::RemoveCallCompletedCallback(CallCompletedCallback1);
16320 script->Run();
16321 CHECK_EQ(2, callback_fired);
16322
16323 i::OS::Print("\n--- Function ---\n");
16324 callback_fired = 0;
16325 Local<Function> recursive_function =
16326 Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
16327 v8::Handle<Value> args[] = { v8_num(0) };
16328 recursive_function->Call(env->Global(), 1, args);
16329 CHECK_EQ(2, callback_fired);
16330}
16331
16332
16333void CallCompletedCallbackNoException() {
16334 v8::HandleScope scope;
16335 CompileRun("1+1;");
16336}
16337
16338
16339void CallCompletedCallbackException() {
16340 v8::HandleScope scope;
16341 CompileRun("throw 'second exception';");
16342}
16343
16344
16345TEST(CallCompletedCallbackOneException) {
16346 v8::HandleScope scope;
16347 LocalContext env;
16348 v8::V8::AddCallCompletedCallback(CallCompletedCallbackNoException);
16349 CompileRun("throw 'exception';");
16350}
16351
16352
16353TEST(CallCompletedCallbackTwoExceptions) {
16354 v8::HandleScope scope;
16355 LocalContext env;
16356 v8::V8::AddCallCompletedCallback(CallCompletedCallbackException);
16357 CompileRun("throw 'first exception';");
16358}
16359
16360
16361static int probes_counter = 0;
16362static int misses_counter = 0;
16363static int updates_counter = 0;
16364
16365
16366static int* LookupCounter(const char* name) {
16367 if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
16368 return &probes_counter;
16369 } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
16370 return &misses_counter;
16371 } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
16372 return &updates_counter;
16373 }
16374 return NULL;
16375}
16376
16377
16378static const char* kMegamorphicTestProgram =
16379 "function ClassA() { };"
16380 "function ClassB() { };"
16381 "ClassA.prototype.foo = function() { };"
16382 "ClassB.prototype.foo = function() { };"
16383 "function fooify(obj) { obj.foo(); };"
16384 "var a = new ClassA();"
16385 "var b = new ClassB();"
16386 "for (var i = 0; i < 10000; i++) {"
16387 " fooify(a);"
16388 " fooify(b);"
16389 "}";
16390
16391
16392static void StubCacheHelper(bool primary) {
16393 V8::SetCounterFunction(LookupCounter);
16394 USE(kMegamorphicTestProgram);
16395#ifdef DEBUG
16396 i::FLAG_native_code_counters = true;
16397 if (primary) {
16398 i::FLAG_test_primary_stub_cache = true;
16399 } else {
16400 i::FLAG_test_secondary_stub_cache = true;
16401 }
16402 i::FLAG_crankshaft = false;
16403 v8::HandleScope scope;
16404 LocalContext env;
16405 int initial_probes = probes_counter;
16406 int initial_misses = misses_counter;
16407 int initial_updates = updates_counter;
16408 CompileRun(kMegamorphicTestProgram);
16409 int probes = probes_counter - initial_probes;
16410 int misses = misses_counter - initial_misses;
16411 int updates = updates_counter - initial_updates;
16412 CHECK_LT(updates, 10);
16413 CHECK_LT(misses, 10);
16414 CHECK_GE(probes, 10000);
16415#endif
16416}
16417
16418
16419TEST(SecondaryStubCache) {
16420 StubCacheHelper(true);
16421}
16422
16423
16424TEST(PrimaryStubCache) {
16425 StubCacheHelper(false);
16426}
16427