blob: 59d6d19462f357d96b27f9fb1515161d17d6bd57 [file] [log] [blame]
Ben Murdochc7cc0282012-03-05 14:35:55 +00001// 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 Murdoch592a9fc2012-03-05 11:04:45 +000083static 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 Murdoch592a9fc2012-03-05 11:04:45 +0000401 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 Murdoch592a9fc2012-03-05 11:04:45 +0000405 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 Murdoch592a9fc2012-03-05 11:04:45 +0000423 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 Murdoch592a9fc2012-03-05 11:04:45 +0000427 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 Murdoch592a9fc2012-03-05 11:04:45 +0000449 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 Murdoch592a9fc2012-03-05 11:04:45 +0000453 // TODO(1608): This should use kAbortIncrementalMarking.
454 HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000455 CHECK_EQ(1, dispose_count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000456}
457
458
459THREADED_TEST(ScriptMakingExternalAsciiString) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000460 int dispose_count = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +0000461 const char* c_source = "1 + 2 * 3";
462 {
463 v8::HandleScope scope;
464 LocalContext env;
465 Local<String> source = v8_str(c_source);
Andrei Popescu402d9372010-02-26 13:31:12 +0000466 // Trigger GCs so that the newly allocated string moves to old gen.
Steve Block44f0eee2011-05-26 01:26:41 +0100467 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
468 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
Steve Blocka7e24c12009-10-30 11:49:00 +0000469 bool success = source->MakeExternal(
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000470 new TestAsciiResource(i::StrDup(c_source), &dispose_count));
Steve Blocka7e24c12009-10-30 11:49:00 +0000471 CHECK(success);
472 Local<Script> script = Script::Compile(source);
473 Local<Value> value = script->Run();
474 CHECK(value->IsNumber());
475 CHECK_EQ(7, value->Int32Value());
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000476 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000477 CHECK_EQ(0, dispose_count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000478 }
Steve Block44f0eee2011-05-26 01:26:41 +0100479 i::Isolate::Current()->compilation_cache()->Clear();
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000480 // TODO(1608): This should use kAbortIncrementalMarking.
481 HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000482 CHECK_EQ(1, dispose_count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000483}
484
485
Andrei Popescu402d9372010-02-26 13:31:12 +0000486TEST(MakingExternalStringConditions) {
487 v8::HandleScope scope;
488 LocalContext env;
489
490 // Free some space in the new space so that we can check freshness.
Steve Block44f0eee2011-05-26 01:26:41 +0100491 HEAP->CollectGarbage(i::NEW_SPACE);
492 HEAP->CollectGarbage(i::NEW_SPACE);
Andrei Popescu402d9372010-02-26 13:31:12 +0000493
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000494 uint16_t* two_byte_string = AsciiToTwoByteString("s1");
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100495 Local<String> small_string = String::New(two_byte_string);
496 i::DeleteArray(two_byte_string);
497
Andrei Popescu402d9372010-02-26 13:31:12 +0000498 // We should refuse to externalize newly created small string.
499 CHECK(!small_string->CanMakeExternal());
500 // Trigger GCs so that the newly allocated string moves to old gen.
Steve Block44f0eee2011-05-26 01:26:41 +0100501 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
502 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
Andrei Popescu402d9372010-02-26 13:31:12 +0000503 // Old space strings should be accepted.
504 CHECK(small_string->CanMakeExternal());
505
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000506 two_byte_string = AsciiToTwoByteString("small string 2");
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100507 small_string = String::New(two_byte_string);
508 i::DeleteArray(two_byte_string);
509
Andrei Popescu402d9372010-02-26 13:31:12 +0000510 // We should refuse externalizing newly created small string.
511 CHECK(!small_string->CanMakeExternal());
512 for (int i = 0; i < 100; i++) {
513 String::Value value(small_string);
514 }
515 // Frequently used strings should be accepted.
516 CHECK(small_string->CanMakeExternal());
517
518 const int buf_size = 10 * 1024;
519 char* buf = i::NewArray<char>(buf_size);
520 memset(buf, 'a', buf_size);
521 buf[buf_size - 1] = '\0';
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100522
523 two_byte_string = AsciiToTwoByteString(buf);
524 Local<String> large_string = String::New(two_byte_string);
Andrei Popescu402d9372010-02-26 13:31:12 +0000525 i::DeleteArray(buf);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100526 i::DeleteArray(two_byte_string);
Andrei Popescu402d9372010-02-26 13:31:12 +0000527 // Large strings should be immediately accepted.
528 CHECK(large_string->CanMakeExternal());
529}
530
531
532TEST(MakingExternalAsciiStringConditions) {
533 v8::HandleScope scope;
534 LocalContext env;
535
536 // Free some space in the new space so that we can check freshness.
Steve Block44f0eee2011-05-26 01:26:41 +0100537 HEAP->CollectGarbage(i::NEW_SPACE);
538 HEAP->CollectGarbage(i::NEW_SPACE);
Andrei Popescu402d9372010-02-26 13:31:12 +0000539
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000540 Local<String> small_string = String::New("s1");
Andrei Popescu402d9372010-02-26 13:31:12 +0000541 // We should refuse to externalize newly created small string.
542 CHECK(!small_string->CanMakeExternal());
543 // Trigger GCs so that the newly allocated string moves to old gen.
Steve Block44f0eee2011-05-26 01:26:41 +0100544 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
545 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
Andrei Popescu402d9372010-02-26 13:31:12 +0000546 // Old space strings should be accepted.
547 CHECK(small_string->CanMakeExternal());
548
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000549 small_string = String::New("small string 2");
Andrei Popescu402d9372010-02-26 13:31:12 +0000550 // We should refuse externalizing newly created small string.
551 CHECK(!small_string->CanMakeExternal());
552 for (int i = 0; i < 100; i++) {
553 String::Value value(small_string);
554 }
555 // Frequently used strings should be accepted.
556 CHECK(small_string->CanMakeExternal());
557
558 const int buf_size = 10 * 1024;
559 char* buf = i::NewArray<char>(buf_size);
560 memset(buf, 'a', buf_size);
561 buf[buf_size - 1] = '\0';
562 Local<String> large_string = String::New(buf);
563 i::DeleteArray(buf);
564 // Large strings should be immediately accepted.
565 CHECK(large_string->CanMakeExternal());
566}
567
568
Steve Blocka7e24c12009-10-30 11:49:00 +0000569THREADED_TEST(UsingExternalString) {
570 {
571 v8::HandleScope scope;
572 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
573 Local<String> string =
574 String::NewExternal(new TestResource(two_byte_string));
575 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
576 // Trigger GCs so that the newly allocated string moves to old gen.
Steve Block44f0eee2011-05-26 01:26:41 +0100577 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
578 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
579 i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
Steve Blocka7e24c12009-10-30 11:49:00 +0000580 CHECK(isymbol->IsSymbol());
581 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000582 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
583 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000584}
585
586
587THREADED_TEST(UsingExternalAsciiString) {
588 {
589 v8::HandleScope scope;
590 const char* one_byte_string = "test string";
591 Local<String> string = String::NewExternal(
592 new TestAsciiResource(i::StrDup(one_byte_string)));
593 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
594 // Trigger GCs so that the newly allocated string moves to old gen.
Steve Block44f0eee2011-05-26 01:26:41 +0100595 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
596 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
597 i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
Steve Blocka7e24c12009-10-30 11:49:00 +0000598 CHECK(isymbol->IsSymbol());
599 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000600 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
601 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000602}
603
604
Leon Clarkee46be812010-01-19 14:06:41 +0000605THREADED_TEST(ScavengeExternalString) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000606 int dispose_count = 0;
Steve Block6ded16b2010-05-10 14:33:55 +0100607 bool in_new_space = false;
Leon Clarkee46be812010-01-19 14:06:41 +0000608 {
609 v8::HandleScope scope;
610 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
611 Local<String> string =
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000612 String::NewExternal(new TestResource(two_byte_string,
613 &dispose_count));
Leon Clarkee46be812010-01-19 14:06:41 +0000614 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
Steve Block44f0eee2011-05-26 01:26:41 +0100615 HEAP->CollectGarbage(i::NEW_SPACE);
616 in_new_space = HEAP->InNewSpace(*istring);
617 CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000618 CHECK_EQ(0, dispose_count);
Leon Clarkee46be812010-01-19 14:06:41 +0000619 }
Steve Block44f0eee2011-05-26 01:26:41 +0100620 HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000621 CHECK_EQ(1, dispose_count);
Leon Clarkee46be812010-01-19 14:06:41 +0000622}
623
624
625THREADED_TEST(ScavengeExternalAsciiString) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000626 int dispose_count = 0;
Steve Block6ded16b2010-05-10 14:33:55 +0100627 bool in_new_space = false;
Leon Clarkee46be812010-01-19 14:06:41 +0000628 {
629 v8::HandleScope scope;
630 const char* one_byte_string = "test string";
631 Local<String> string = String::NewExternal(
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000632 new TestAsciiResource(i::StrDup(one_byte_string), &dispose_count));
Leon Clarkee46be812010-01-19 14:06:41 +0000633 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
Steve Block44f0eee2011-05-26 01:26:41 +0100634 HEAP->CollectGarbage(i::NEW_SPACE);
635 in_new_space = HEAP->InNewSpace(*istring);
636 CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000637 CHECK_EQ(0, dispose_count);
Leon Clarkee46be812010-01-19 14:06:41 +0000638 }
Steve Block44f0eee2011-05-26 01:26:41 +0100639 HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000640 CHECK_EQ(1, dispose_count);
Leon Clarkee46be812010-01-19 14:06:41 +0000641}
642
643
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100644class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
645 public:
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000646 // Only used by non-threaded tests, so it can use static fields.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100647 static int dispose_calls;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000648 static int dispose_count;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100649
650 TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000651 : TestAsciiResource(data, &dispose_count),
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100652 dispose_(dispose) { }
653
654 void Dispose() {
655 ++dispose_calls;
656 if (dispose_) delete this;
657 }
658 private:
659 bool dispose_;
660};
661
662
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000663int TestAsciiResourceWithDisposeControl::dispose_count = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100664int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
665
666
667TEST(ExternalStringWithDisposeHandling) {
668 const char* c_source = "1 + 2 * 3";
669
670 // Use a stack allocated external string resource allocated object.
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000671 TestAsciiResourceWithDisposeControl::dispose_count = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100672 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
673 TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
674 {
675 v8::HandleScope scope;
676 LocalContext env;
677 Local<String> source = String::NewExternal(&res_stack);
678 Local<Script> script = Script::Compile(source);
679 Local<Value> value = script->Run();
680 CHECK(value->IsNumber());
681 CHECK_EQ(7, value->Int32Value());
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000682 HEAP->CollectAllAvailableGarbage();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000683 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100684 }
Steve Block44f0eee2011-05-26 01:26:41 +0100685 i::Isolate::Current()->compilation_cache()->Clear();
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000686 HEAP->CollectAllAvailableGarbage();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100687 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000688 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100689
690 // Use a heap allocated external string resource allocated object.
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000691 TestAsciiResourceWithDisposeControl::dispose_count = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100692 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
693 TestAsciiResource* res_heap =
694 new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
695 {
696 v8::HandleScope scope;
697 LocalContext env;
698 Local<String> source = String::NewExternal(res_heap);
699 Local<Script> script = Script::Compile(source);
700 Local<Value> value = script->Run();
701 CHECK(value->IsNumber());
702 CHECK_EQ(7, value->Int32Value());
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000703 HEAP->CollectAllAvailableGarbage();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000704 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100705 }
Steve Block44f0eee2011-05-26 01:26:41 +0100706 i::Isolate::Current()->compilation_cache()->Clear();
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000707 HEAP->CollectAllAvailableGarbage();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100708 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000709 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100710}
711
712
Steve Block3ce2e202009-11-05 08:53:23 +0000713THREADED_TEST(StringConcat) {
714 {
715 v8::HandleScope scope;
716 LocalContext env;
717 const char* one_byte_string_1 = "function a_times_t";
718 const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
719 const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
720 const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
721 const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
722 const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
723 const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
724 Local<String> left = v8_str(one_byte_string_1);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100725
726 uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
727 Local<String> right = String::New(two_byte_source);
728 i::DeleteArray(two_byte_source);
729
Steve Block3ce2e202009-11-05 08:53:23 +0000730 Local<String> source = String::Concat(left, right);
731 right = String::NewExternal(
732 new TestAsciiResource(i::StrDup(one_byte_extern_1)));
733 source = String::Concat(source, right);
734 right = String::NewExternal(
735 new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
736 source = String::Concat(source, right);
737 right = v8_str(one_byte_string_2);
738 source = String::Concat(source, right);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100739
740 two_byte_source = AsciiToTwoByteString(two_byte_string_2);
741 right = String::New(two_byte_source);
742 i::DeleteArray(two_byte_source);
743
Steve Block3ce2e202009-11-05 08:53:23 +0000744 source = String::Concat(source, right);
745 right = String::NewExternal(
746 new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
747 source = String::Concat(source, right);
748 Local<Script> script = Script::Compile(source);
749 Local<Value> value = script->Run();
750 CHECK(value->IsNumber());
751 CHECK_EQ(68, value->Int32Value());
752 }
Steve Block44f0eee2011-05-26 01:26:41 +0100753 i::Isolate::Current()->compilation_cache()->Clear();
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000754 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
755 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Block3ce2e202009-11-05 08:53:23 +0000756}
757
758
Steve Blocka7e24c12009-10-30 11:49:00 +0000759THREADED_TEST(GlobalProperties) {
760 v8::HandleScope scope;
761 LocalContext env;
762 v8::Handle<v8::Object> global = env->Global();
763 global->Set(v8_str("pi"), v8_num(3.1415926));
764 Local<Value> pi = global->Get(v8_str("pi"));
765 CHECK_EQ(3.1415926, pi->NumberValue());
766}
767
768
769static v8::Handle<Value> handle_call(const v8::Arguments& args) {
770 ApiTestFuzzer::Fuzz();
771 return v8_num(102);
772}
773
774
775static v8::Handle<Value> construct_call(const v8::Arguments& args) {
776 ApiTestFuzzer::Fuzz();
777 args.This()->Set(v8_str("x"), v8_num(1));
778 args.This()->Set(v8_str("y"), v8_num(2));
779 return args.This();
780}
781
Ben Murdochf87a2032010-10-22 12:50:53 +0100782static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
783 ApiTestFuzzer::Fuzz();
784 return v8_num(239);
785}
786
787
Steve Blocka7e24c12009-10-30 11:49:00 +0000788THREADED_TEST(FunctionTemplate) {
789 v8::HandleScope scope;
790 LocalContext env;
791 {
792 Local<v8::FunctionTemplate> fun_templ =
793 v8::FunctionTemplate::New(handle_call);
794 Local<Function> fun = fun_templ->GetFunction();
795 env->Global()->Set(v8_str("obj"), fun);
796 Local<Script> script = v8_compile("obj()");
797 CHECK_EQ(102, script->Run()->Int32Value());
798 }
799 // Use SetCallHandler to initialize a function template, should work like the
800 // previous one.
801 {
802 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
803 fun_templ->SetCallHandler(handle_call);
804 Local<Function> fun = fun_templ->GetFunction();
805 env->Global()->Set(v8_str("obj"), fun);
806 Local<Script> script = v8_compile("obj()");
807 CHECK_EQ(102, script->Run()->Int32Value());
808 }
809 // Test constructor calls.
810 {
811 Local<v8::FunctionTemplate> fun_templ =
812 v8::FunctionTemplate::New(construct_call);
813 fun_templ->SetClassName(v8_str("funky"));
Ben Murdochf87a2032010-10-22 12:50:53 +0100814 fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), Return239);
Steve Blocka7e24c12009-10-30 11:49:00 +0000815 Local<Function> fun = fun_templ->GetFunction();
816 env->Global()->Set(v8_str("obj"), fun);
817 Local<Script> script = v8_compile("var s = new obj(); s.x");
818 CHECK_EQ(1, script->Run()->Int32Value());
819
820 Local<Value> result = v8_compile("(new obj()).toString()")->Run();
821 CHECK_EQ(v8_str("[object funky]"), result);
Ben Murdochf87a2032010-10-22 12:50:53 +0100822
823 result = v8_compile("(new obj()).m")->Run();
824 CHECK_EQ(239, result->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +0000825 }
826}
827
828
Ben Murdochb8e0da22011-05-16 14:20:40 +0100829static void* expected_ptr;
830static v8::Handle<v8::Value> callback(const v8::Arguments& args) {
831 void* ptr = v8::External::Unwrap(args.Data());
832 CHECK_EQ(expected_ptr, ptr);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000833 return v8::True();
Ben Murdochb8e0da22011-05-16 14:20:40 +0100834}
835
836
837static void TestExternalPointerWrapping() {
838 v8::HandleScope scope;
839 LocalContext env;
840
841 v8::Handle<v8::Value> data = v8::External::Wrap(expected_ptr);
842
843 v8::Handle<v8::Object> obj = v8::Object::New();
844 obj->Set(v8_str("func"),
845 v8::FunctionTemplate::New(callback, data)->GetFunction());
846 env->Global()->Set(v8_str("obj"), obj);
847
848 CHECK(CompileRun(
849 "function foo() {\n"
850 " for (var i = 0; i < 13; i++) obj.func();\n"
851 "}\n"
852 "foo(), true")->BooleanValue());
853}
854
855
856THREADED_TEST(ExternalWrap) {
857 // Check heap allocated object.
858 int* ptr = new int;
859 expected_ptr = ptr;
860 TestExternalPointerWrapping();
861 delete ptr;
862
863 // Check stack allocated object.
864 int foo;
865 expected_ptr = &foo;
866 TestExternalPointerWrapping();
867
868 // Check not aligned addresses.
869 const int n = 100;
870 char* s = new char[n];
871 for (int i = 0; i < n; i++) {
872 expected_ptr = s + i;
873 TestExternalPointerWrapping();
874 }
875
876 delete[] s;
877
878 // Check several invalid addresses.
879 expected_ptr = reinterpret_cast<void*>(1);
880 TestExternalPointerWrapping();
881
882 expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
883 TestExternalPointerWrapping();
884
885 expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
886 TestExternalPointerWrapping();
887
888#if defined(V8_HOST_ARCH_X64)
Steve Block1e0659c2011-05-24 12:43:12 +0100889 // Check a value with a leading 1 bit in x64 Smi encoding.
890 expected_ptr = reinterpret_cast<void*>(0x400000000);
891 TestExternalPointerWrapping();
892
Ben Murdochb8e0da22011-05-16 14:20:40 +0100893 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
894 TestExternalPointerWrapping();
895
896 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
897 TestExternalPointerWrapping();
898#endif
899}
900
901
Steve Blocka7e24c12009-10-30 11:49:00 +0000902THREADED_TEST(FindInstanceInPrototypeChain) {
903 v8::HandleScope scope;
904 LocalContext env;
905
906 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
907 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
908 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
909 derived->Inherit(base);
910
911 Local<v8::Function> base_function = base->GetFunction();
912 Local<v8::Function> derived_function = derived->GetFunction();
913 Local<v8::Function> other_function = other->GetFunction();
914
915 Local<v8::Object> base_instance = base_function->NewInstance();
916 Local<v8::Object> derived_instance = derived_function->NewInstance();
917 Local<v8::Object> derived_instance2 = derived_function->NewInstance();
918 Local<v8::Object> other_instance = other_function->NewInstance();
919 derived_instance2->Set(v8_str("__proto__"), derived_instance);
920 other_instance->Set(v8_str("__proto__"), derived_instance2);
921
922 // base_instance is only an instance of base.
923 CHECK_EQ(base_instance,
924 base_instance->FindInstanceInPrototypeChain(base));
925 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
926 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
927
928 // derived_instance is an instance of base and derived.
929 CHECK_EQ(derived_instance,
930 derived_instance->FindInstanceInPrototypeChain(base));
931 CHECK_EQ(derived_instance,
932 derived_instance->FindInstanceInPrototypeChain(derived));
933 CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
934
935 // other_instance is an instance of other and its immediate
936 // prototype derived_instance2 is an instance of base and derived.
937 // Note, derived_instance is an instance of base and derived too,
938 // but it comes after derived_instance2 in the prototype chain of
939 // other_instance.
940 CHECK_EQ(derived_instance2,
941 other_instance->FindInstanceInPrototypeChain(base));
942 CHECK_EQ(derived_instance2,
943 other_instance->FindInstanceInPrototypeChain(derived));
944 CHECK_EQ(other_instance,
945 other_instance->FindInstanceInPrototypeChain(other));
946}
947
948
Steve Block3ce2e202009-11-05 08:53:23 +0000949THREADED_TEST(TinyInteger) {
950 v8::HandleScope scope;
951 LocalContext env;
952 int32_t value = 239;
953 Local<v8::Integer> value_obj = v8::Integer::New(value);
954 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
955}
956
957
958THREADED_TEST(BigSmiInteger) {
959 v8::HandleScope scope;
960 LocalContext env;
961 int32_t value = i::Smi::kMaxValue;
962 // We cannot add one to a Smi::kMaxValue without wrapping.
963 if (i::kSmiValueSize < 32) {
964 CHECK(i::Smi::IsValid(value));
965 CHECK(!i::Smi::IsValid(value + 1));
966 Local<v8::Integer> value_obj = v8::Integer::New(value);
967 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
968 }
969}
970
971
972THREADED_TEST(BigInteger) {
973 v8::HandleScope scope;
974 LocalContext env;
975 // We cannot add one to a Smi::kMaxValue without wrapping.
976 if (i::kSmiValueSize < 32) {
977 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
978 // The code will not be run in that case, due to the "if" guard.
979 int32_t value =
980 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
981 CHECK(value > i::Smi::kMaxValue);
982 CHECK(!i::Smi::IsValid(value));
983 Local<v8::Integer> value_obj = v8::Integer::New(value);
984 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
985 }
986}
987
988
989THREADED_TEST(TinyUnsignedInteger) {
990 v8::HandleScope scope;
991 LocalContext env;
992 uint32_t value = 239;
993 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
994 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
995}
996
997
998THREADED_TEST(BigUnsignedSmiInteger) {
999 v8::HandleScope scope;
1000 LocalContext env;
1001 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1002 CHECK(i::Smi::IsValid(value));
1003 CHECK(!i::Smi::IsValid(value + 1));
1004 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1005 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1006}
1007
1008
1009THREADED_TEST(BigUnsignedInteger) {
1010 v8::HandleScope scope;
1011 LocalContext env;
1012 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1013 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1014 CHECK(!i::Smi::IsValid(value));
1015 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1016 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1017}
1018
1019
1020THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1021 v8::HandleScope scope;
1022 LocalContext env;
1023 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1024 uint32_t value = INT32_MAX_AS_UINT + 1;
1025 CHECK(value > INT32_MAX_AS_UINT); // No overflow.
1026 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1027 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1028}
1029
1030
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001031THREADED_TEST(IsNativeError) {
1032 v8::HandleScope scope;
1033 LocalContext env;
1034 v8::Handle<Value> syntax_error = CompileRun(
1035 "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1036 CHECK(syntax_error->IsNativeError());
1037 v8::Handle<Value> not_error = CompileRun("{a:42}");
1038 CHECK(!not_error->IsNativeError());
1039 v8::Handle<Value> not_object = CompileRun("42");
1040 CHECK(!not_object->IsNativeError());
1041}
1042
1043
1044THREADED_TEST(StringObject) {
1045 v8::HandleScope scope;
1046 LocalContext env;
1047 v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1048 CHECK(boxed_string->IsStringObject());
1049 v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1050 CHECK(!unboxed_string->IsStringObject());
1051 v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1052 CHECK(!boxed_not_string->IsStringObject());
1053 v8::Handle<Value> not_object = CompileRun("0");
1054 CHECK(!not_object->IsStringObject());
1055 v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1056 CHECK(!as_boxed.IsEmpty());
1057 Local<v8::String> the_string = as_boxed->StringValue();
1058 CHECK(!the_string.IsEmpty());
1059 ExpectObject("\"test\"", the_string);
1060 v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1061 CHECK(new_boxed_string->IsStringObject());
1062 as_boxed = new_boxed_string.As<v8::StringObject>();
1063 the_string = as_boxed->StringValue();
1064 CHECK(!the_string.IsEmpty());
1065 ExpectObject("\"test\"", the_string);
1066}
1067
1068
1069THREADED_TEST(NumberObject) {
1070 v8::HandleScope scope;
1071 LocalContext env;
1072 v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1073 CHECK(boxed_number->IsNumberObject());
1074 v8::Handle<Value> unboxed_number = CompileRun("42");
1075 CHECK(!unboxed_number->IsNumberObject());
1076 v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1077 CHECK(!boxed_not_number->IsNumberObject());
1078 v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1079 CHECK(!as_boxed.IsEmpty());
1080 double the_number = as_boxed->NumberValue();
1081 CHECK_EQ(42.0, the_number);
1082 v8::Handle<v8::Value> new_boxed_number = v8::NumberObject::New(43);
1083 CHECK(new_boxed_number->IsNumberObject());
1084 as_boxed = new_boxed_number.As<v8::NumberObject>();
1085 the_number = as_boxed->NumberValue();
1086 CHECK_EQ(43.0, the_number);
1087}
1088
1089
1090THREADED_TEST(BooleanObject) {
1091 v8::HandleScope scope;
1092 LocalContext env;
1093 v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1094 CHECK(boxed_boolean->IsBooleanObject());
1095 v8::Handle<Value> unboxed_boolean = CompileRun("true");
1096 CHECK(!unboxed_boolean->IsBooleanObject());
1097 v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1098 CHECK(!boxed_not_boolean->IsBooleanObject());
1099 v8::Handle<v8::BooleanObject> as_boxed =
1100 boxed_boolean.As<v8::BooleanObject>();
1101 CHECK(!as_boxed.IsEmpty());
1102 bool the_boolean = as_boxed->BooleanValue();
1103 CHECK_EQ(true, the_boolean);
1104 v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1105 v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1106 CHECK(boxed_true->IsBooleanObject());
1107 CHECK(boxed_false->IsBooleanObject());
1108 as_boxed = boxed_true.As<v8::BooleanObject>();
1109 CHECK_EQ(true, as_boxed->BooleanValue());
1110 as_boxed = boxed_false.As<v8::BooleanObject>();
1111 CHECK_EQ(false, as_boxed->BooleanValue());
1112}
1113
1114
Steve Blocka7e24c12009-10-30 11:49:00 +00001115THREADED_TEST(Number) {
1116 v8::HandleScope scope;
1117 LocalContext env;
1118 double PI = 3.1415926;
1119 Local<v8::Number> pi_obj = v8::Number::New(PI);
1120 CHECK_EQ(PI, pi_obj->NumberValue());
1121}
1122
1123
1124THREADED_TEST(ToNumber) {
1125 v8::HandleScope scope;
1126 LocalContext env;
1127 Local<String> str = v8_str("3.1415926");
1128 CHECK_EQ(3.1415926, str->NumberValue());
1129 v8::Handle<v8::Boolean> t = v8::True();
1130 CHECK_EQ(1.0, t->NumberValue());
1131 v8::Handle<v8::Boolean> f = v8::False();
1132 CHECK_EQ(0.0, f->NumberValue());
1133}
1134
1135
1136THREADED_TEST(Date) {
1137 v8::HandleScope scope;
1138 LocalContext env;
1139 double PI = 3.1415926;
Ben Murdoch257744e2011-11-30 15:57:28 +00001140 Local<Value> date = v8::Date::New(PI);
1141 CHECK_EQ(3.0, date->NumberValue());
1142 date.As<v8::Date>()->Set(v8_str("property"), v8::Integer::New(42));
1143 CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00001144}
1145
1146
1147THREADED_TEST(Boolean) {
1148 v8::HandleScope scope;
1149 LocalContext env;
1150 v8::Handle<v8::Boolean> t = v8::True();
1151 CHECK(t->Value());
1152 v8::Handle<v8::Boolean> f = v8::False();
1153 CHECK(!f->Value());
1154 v8::Handle<v8::Primitive> u = v8::Undefined();
1155 CHECK(!u->BooleanValue());
1156 v8::Handle<v8::Primitive> n = v8::Null();
1157 CHECK(!n->BooleanValue());
1158 v8::Handle<String> str1 = v8_str("");
1159 CHECK(!str1->BooleanValue());
1160 v8::Handle<String> str2 = v8_str("x");
1161 CHECK(str2->BooleanValue());
1162 CHECK(!v8::Number::New(0)->BooleanValue());
1163 CHECK(v8::Number::New(-1)->BooleanValue());
1164 CHECK(v8::Number::New(1)->BooleanValue());
1165 CHECK(v8::Number::New(42)->BooleanValue());
1166 CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1167}
1168
1169
1170static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
1171 ApiTestFuzzer::Fuzz();
1172 return v8_num(13.4);
1173}
1174
1175
1176static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
1177 ApiTestFuzzer::Fuzz();
1178 return v8_num(876);
1179}
1180
1181
1182THREADED_TEST(GlobalPrototype) {
1183 v8::HandleScope scope;
1184 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
1185 func_templ->PrototypeTemplate()->Set(
1186 "dummy",
1187 v8::FunctionTemplate::New(DummyCallHandler));
1188 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1189 templ->Set("x", v8_num(200));
1190 templ->SetAccessor(v8_str("m"), GetM);
1191 LocalContext env(0, templ);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001192 v8::Handle<Script> script(v8_compile("dummy()"));
1193 v8::Handle<Value> result(script->Run());
Steve Blocka7e24c12009-10-30 11:49:00 +00001194 CHECK_EQ(13.4, result->NumberValue());
1195 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1196 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1197}
1198
1199
Steve Blocka7e24c12009-10-30 11:49:00 +00001200THREADED_TEST(ObjectTemplate) {
1201 v8::HandleScope scope;
1202 Local<ObjectTemplate> templ1 = ObjectTemplate::New();
1203 templ1->Set("x", v8_num(10));
1204 templ1->Set("y", v8_num(13));
1205 LocalContext env;
1206 Local<v8::Object> instance1 = templ1->NewInstance();
1207 env->Global()->Set(v8_str("p"), instance1);
1208 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1209 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1210 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
1211 fun->PrototypeTemplate()->Set("nirk", v8_num(123));
1212 Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1213 templ2->Set("a", v8_num(12));
1214 templ2->Set("b", templ1);
1215 Local<v8::Object> instance2 = templ2->NewInstance();
1216 env->Global()->Set(v8_str("q"), instance2);
1217 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1218 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1219 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1220 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1221}
1222
1223
1224static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
1225 ApiTestFuzzer::Fuzz();
1226 return v8_num(17.2);
1227}
1228
1229
1230static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
1231 ApiTestFuzzer::Fuzz();
1232 return v8_num(15.2);
1233}
1234
1235
1236THREADED_TEST(DescriptorInheritance) {
1237 v8::HandleScope scope;
1238 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
1239 super->PrototypeTemplate()->Set("flabby",
1240 v8::FunctionTemplate::New(GetFlabby));
1241 super->PrototypeTemplate()->Set("PI", v8_num(3.14));
1242
1243 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1244
1245 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
1246 base1->Inherit(super);
1247 base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
1248
1249 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
1250 base2->Inherit(super);
1251 base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
1252
1253 LocalContext env;
1254
1255 env->Global()->Set(v8_str("s"), super->GetFunction());
1256 env->Global()->Set(v8_str("base1"), base1->GetFunction());
1257 env->Global()->Set(v8_str("base2"), base2->GetFunction());
1258
1259 // Checks right __proto__ chain.
1260 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1261 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1262
1263 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1264
1265 // Instance accessor should not be visible on function object or its prototype
1266 CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1267 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1268 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1269
1270 env->Global()->Set(v8_str("obj"),
1271 base1->GetFunction()->NewInstance());
1272 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1273 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1274 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1275 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1276 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1277
1278 env->Global()->Set(v8_str("obj2"),
1279 base2->GetFunction()->NewInstance());
1280 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1281 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1282 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1283 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1284 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1285
1286 // base1 and base2 cannot cross reference to each's prototype
1287 CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1288 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1289}
1290
1291
1292int echo_named_call_count;
1293
1294
1295static v8::Handle<Value> EchoNamedProperty(Local<String> name,
1296 const AccessorInfo& info) {
1297 ApiTestFuzzer::Fuzz();
1298 CHECK_EQ(v8_str("data"), info.Data());
1299 echo_named_call_count++;
1300 return name;
1301}
1302
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001303// Helper functions for Interceptor/Accessor interaction tests
1304
1305Handle<Value> SimpleAccessorGetter(Local<String> name,
1306 const AccessorInfo& info) {
1307 Handle<Object> self = info.This();
1308 return self->Get(String::Concat(v8_str("accessor_"), name));
1309}
1310
1311void SimpleAccessorSetter(Local<String> name, Local<Value> value,
1312 const AccessorInfo& info) {
1313 Handle<Object> self = info.This();
1314 self->Set(String::Concat(v8_str("accessor_"), name), value);
1315}
1316
1317Handle<Value> EmptyInterceptorGetter(Local<String> name,
1318 const AccessorInfo& info) {
1319 return Handle<Value>();
1320}
1321
1322Handle<Value> EmptyInterceptorSetter(Local<String> name,
1323 Local<Value> value,
1324 const AccessorInfo& info) {
1325 return Handle<Value>();
1326}
1327
1328Handle<Value> InterceptorGetter(Local<String> name,
1329 const AccessorInfo& info) {
1330 // Intercept names that start with 'interceptor_'.
1331 String::AsciiValue ascii(name);
1332 char* name_str = *ascii;
1333 char prefix[] = "interceptor_";
1334 int i;
1335 for (i = 0; name_str[i] && prefix[i]; ++i) {
1336 if (name_str[i] != prefix[i]) return Handle<Value>();
1337 }
1338 Handle<Object> self = info.This();
1339 return self->GetHiddenValue(v8_str(name_str + i));
1340}
1341
1342Handle<Value> InterceptorSetter(Local<String> name,
1343 Local<Value> value,
1344 const AccessorInfo& info) {
1345 // Intercept accesses that set certain integer values.
1346 if (value->IsInt32() && value->Int32Value() < 10000) {
1347 Handle<Object> self = info.This();
1348 self->SetHiddenValue(name, value);
1349 return value;
1350 }
1351 return Handle<Value>();
1352}
1353
1354void AddAccessor(Handle<FunctionTemplate> templ,
1355 Handle<String> name,
1356 v8::AccessorGetter getter,
1357 v8::AccessorSetter setter) {
1358 templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
1359}
1360
1361void AddInterceptor(Handle<FunctionTemplate> templ,
1362 v8::NamedPropertyGetter getter,
1363 v8::NamedPropertySetter setter) {
1364 templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
1365}
1366
1367THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
1368 v8::HandleScope scope;
1369 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1370 Handle<FunctionTemplate> child = FunctionTemplate::New();
1371 child->Inherit(parent);
1372 AddAccessor(parent, v8_str("age"),
1373 SimpleAccessorGetter, SimpleAccessorSetter);
1374 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1375 LocalContext env;
1376 env->Global()->Set(v8_str("Child"), child->GetFunction());
1377 CompileRun("var child = new Child;"
1378 "child.age = 10;");
1379 ExpectBoolean("child.hasOwnProperty('age')", false);
1380 ExpectInt32("child.age", 10);
1381 ExpectInt32("child.accessor_age", 10);
1382}
1383
1384THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
1385 v8::HandleScope scope;
1386 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1387 Handle<FunctionTemplate> child = FunctionTemplate::New();
1388 child->Inherit(parent);
1389 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1390 LocalContext env;
1391 env->Global()->Set(v8_str("Child"), child->GetFunction());
1392 CompileRun("var child = new Child;"
1393 "var parent = child.__proto__;"
1394 "Object.defineProperty(parent, 'age', "
1395 " {get: function(){ return this.accessor_age; }, "
1396 " set: function(v){ this.accessor_age = v; }, "
1397 " enumerable: true, configurable: true});"
1398 "child.age = 10;");
1399 ExpectBoolean("child.hasOwnProperty('age')", false);
1400 ExpectInt32("child.age", 10);
1401 ExpectInt32("child.accessor_age", 10);
1402}
1403
1404THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
1405 v8::HandleScope scope;
1406 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1407 Handle<FunctionTemplate> child = FunctionTemplate::New();
1408 child->Inherit(parent);
1409 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1410 LocalContext env;
1411 env->Global()->Set(v8_str("Child"), child->GetFunction());
1412 CompileRun("var child = new Child;"
1413 "var parent = child.__proto__;"
1414 "parent.name = 'Alice';");
1415 ExpectBoolean("child.hasOwnProperty('name')", false);
1416 ExpectString("child.name", "Alice");
1417 CompileRun("child.name = 'Bob';");
1418 ExpectString("child.name", "Bob");
1419 ExpectBoolean("child.hasOwnProperty('name')", true);
1420 ExpectString("parent.name", "Alice");
1421}
1422
1423THREADED_TEST(SwitchFromInterceptorToAccessor) {
1424 v8::HandleScope scope;
Ben Murdochc7cc0282012-03-05 14:35:55 +00001425 Handle<FunctionTemplate> templ = FunctionTemplate::New();
1426 AddAccessor(templ, v8_str("age"),
1427 SimpleAccessorGetter, SimpleAccessorSetter);
1428 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1429 LocalContext env;
1430 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1431 CompileRun("var obj = new Obj;"
1432 "function setAge(i){ obj.age = i; };"
1433 "for(var i = 0; i <= 10000; i++) setAge(i);");
1434 // All i < 10000 go to the interceptor.
1435 ExpectInt32("obj.interceptor_age", 9999);
1436 // The last i goes to the accessor.
1437 ExpectInt32("obj.accessor_age", 10000);
1438}
1439
1440THREADED_TEST(SwitchFromAccessorToInterceptor) {
1441 v8::HandleScope scope;
1442 Handle<FunctionTemplate> templ = FunctionTemplate::New();
1443 AddAccessor(templ, v8_str("age"),
1444 SimpleAccessorGetter, SimpleAccessorSetter);
1445 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1446 LocalContext env;
1447 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1448 CompileRun("var obj = new Obj;"
1449 "function setAge(i){ obj.age = i; };"
1450 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1451 // All i >= 10000 go to the accessor.
1452 ExpectInt32("obj.accessor_age", 10000);
1453 // The last i goes to the interceptor.
1454 ExpectInt32("obj.interceptor_age", 9999);
1455}
1456
1457THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
1458 v8::HandleScope scope;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001459 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1460 Handle<FunctionTemplate> child = FunctionTemplate::New();
1461 child->Inherit(parent);
1462 AddAccessor(parent, v8_str("age"),
1463 SimpleAccessorGetter, SimpleAccessorSetter);
1464 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1465 LocalContext env;
1466 env->Global()->Set(v8_str("Child"), child->GetFunction());
1467 CompileRun("var child = new Child;"
1468 "function setAge(i){ child.age = i; };"
1469 "for(var i = 0; i <= 10000; i++) setAge(i);");
1470 // All i < 10000 go to the interceptor.
1471 ExpectInt32("child.interceptor_age", 9999);
1472 // The last i goes to the accessor.
1473 ExpectInt32("child.accessor_age", 10000);
1474}
1475
Ben Murdochc7cc0282012-03-05 14:35:55 +00001476THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001477 v8::HandleScope scope;
1478 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1479 Handle<FunctionTemplate> child = FunctionTemplate::New();
1480 child->Inherit(parent);
1481 AddAccessor(parent, v8_str("age"),
1482 SimpleAccessorGetter, SimpleAccessorSetter);
1483 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1484 LocalContext env;
1485 env->Global()->Set(v8_str("Child"), child->GetFunction());
1486 CompileRun("var child = new Child;"
1487 "function setAge(i){ child.age = i; };"
1488 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1489 // All i >= 10000 go to the accessor.
1490 ExpectInt32("child.accessor_age", 10000);
1491 // The last i goes to the interceptor.
1492 ExpectInt32("child.interceptor_age", 9999);
1493}
1494
Ben Murdochc7cc0282012-03-05 14:35:55 +00001495THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
1496 v8::HandleScope scope;
1497 Handle<FunctionTemplate> templ = FunctionTemplate::New();
1498 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1499 LocalContext env;
1500 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1501 CompileRun("var obj = new Obj;"
1502 "function setter(i) { this.accessor_age = i; };"
1503 "function getter() { return this.accessor_age; };"
1504 "function setAge(i) { obj.age = i; };"
1505 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
1506 "for(var i = 0; i <= 10000; i++) setAge(i);");
1507 // All i < 10000 go to the interceptor.
1508 ExpectInt32("obj.interceptor_age", 9999);
1509 // The last i goes to the JavaScript accessor.
1510 ExpectInt32("obj.accessor_age", 10000);
1511 // The installed JavaScript getter is still intact.
1512 // This last part is a regression test for issue 1651 and relies on the fact
1513 // that both interceptor and accessor are being installed on the same object.
1514 ExpectInt32("obj.age", 10000);
1515 ExpectBoolean("obj.hasOwnProperty('age')", true);
1516 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
1517}
1518
1519THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
1520 v8::HandleScope scope;
1521 Handle<FunctionTemplate> templ = FunctionTemplate::New();
1522 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1523 LocalContext env;
1524 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1525 CompileRun("var obj = new Obj;"
1526 "function setter(i) { this.accessor_age = i; };"
1527 "function getter() { return this.accessor_age; };"
1528 "function setAge(i) { obj.age = i; };"
1529 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
1530 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1531 // All i >= 10000 go to the accessor.
1532 ExpectInt32("obj.accessor_age", 10000);
1533 // The last i goes to the interceptor.
1534 ExpectInt32("obj.interceptor_age", 9999);
1535 // The installed JavaScript getter is still intact.
1536 // This last part is a regression test for issue 1651 and relies on the fact
1537 // that both interceptor and accessor are being installed on the same object.
1538 ExpectInt32("obj.age", 10000);
1539 ExpectBoolean("obj.hasOwnProperty('age')", true);
1540 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
1541}
1542
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001543THREADED_TEST(SwitchFromInterceptorToProperty) {
1544 v8::HandleScope scope;
1545 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1546 Handle<FunctionTemplate> child = FunctionTemplate::New();
1547 child->Inherit(parent);
1548 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1549 LocalContext env;
1550 env->Global()->Set(v8_str("Child"), child->GetFunction());
1551 CompileRun("var child = new Child;"
1552 "function setAge(i){ child.age = i; };"
1553 "for(var i = 0; i <= 10000; i++) setAge(i);");
1554 // All i < 10000 go to the interceptor.
1555 ExpectInt32("child.interceptor_age", 9999);
1556 // The last i goes to child's own property.
1557 ExpectInt32("child.age", 10000);
1558}
1559
1560THREADED_TEST(SwitchFromPropertyToInterceptor) {
1561 v8::HandleScope scope;
1562 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1563 Handle<FunctionTemplate> child = FunctionTemplate::New();
1564 child->Inherit(parent);
1565 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1566 LocalContext env;
1567 env->Global()->Set(v8_str("Child"), child->GetFunction());
1568 CompileRun("var child = new Child;"
1569 "function setAge(i){ child.age = i; };"
1570 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1571 // All i >= 10000 go to child's own property.
1572 ExpectInt32("child.age", 10000);
1573 // The last i goes to the interceptor.
1574 ExpectInt32("child.interceptor_age", 9999);
1575}
Steve Blocka7e24c12009-10-30 11:49:00 +00001576
1577THREADED_TEST(NamedPropertyHandlerGetter) {
1578 echo_named_call_count = 0;
1579 v8::HandleScope scope;
1580 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1581 templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
1582 0, 0, 0, 0,
1583 v8_str("data"));
1584 LocalContext env;
1585 env->Global()->Set(v8_str("obj"),
1586 templ->GetFunction()->NewInstance());
1587 CHECK_EQ(echo_named_call_count, 0);
1588 v8_compile("obj.x")->Run();
1589 CHECK_EQ(echo_named_call_count, 1);
1590 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
1591 v8::Handle<Value> str = CompileRun(code);
1592 String::AsciiValue value(str);
1593 CHECK_EQ(*value, "oddlepoddle");
1594 // Check default behavior
1595 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
1596 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
1597 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
1598}
1599
1600
1601int echo_indexed_call_count = 0;
1602
1603
1604static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
1605 const AccessorInfo& info) {
1606 ApiTestFuzzer::Fuzz();
1607 CHECK_EQ(v8_num(637), info.Data());
1608 echo_indexed_call_count++;
1609 return v8_num(index);
1610}
1611
1612
1613THREADED_TEST(IndexedPropertyHandlerGetter) {
1614 v8::HandleScope scope;
1615 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1616 templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
1617 0, 0, 0, 0,
1618 v8_num(637));
1619 LocalContext env;
1620 env->Global()->Set(v8_str("obj"),
1621 templ->GetFunction()->NewInstance());
1622 Local<Script> script = v8_compile("obj[900]");
1623 CHECK_EQ(script->Run()->Int32Value(), 900);
1624}
1625
1626
1627v8::Handle<v8::Object> bottom;
1628
1629static v8::Handle<Value> CheckThisIndexedPropertyHandler(
1630 uint32_t index,
1631 const AccessorInfo& info) {
1632 ApiTestFuzzer::Fuzz();
1633 CHECK(info.This()->Equals(bottom));
1634 return v8::Handle<Value>();
1635}
1636
1637static v8::Handle<Value> CheckThisNamedPropertyHandler(
1638 Local<String> name,
1639 const AccessorInfo& info) {
1640 ApiTestFuzzer::Fuzz();
1641 CHECK(info.This()->Equals(bottom));
1642 return v8::Handle<Value>();
1643}
1644
1645
1646v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
1647 Local<Value> value,
1648 const AccessorInfo& info) {
1649 ApiTestFuzzer::Fuzz();
1650 CHECK(info.This()->Equals(bottom));
1651 return v8::Handle<Value>();
1652}
1653
1654
1655v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
1656 Local<Value> value,
1657 const AccessorInfo& info) {
1658 ApiTestFuzzer::Fuzz();
1659 CHECK(info.This()->Equals(bottom));
1660 return v8::Handle<Value>();
1661}
1662
Iain Merrick75681382010-08-19 15:07:18 +01001663v8::Handle<v8::Integer> CheckThisIndexedPropertyQuery(
Steve Blocka7e24c12009-10-30 11:49:00 +00001664 uint32_t index,
1665 const AccessorInfo& info) {
1666 ApiTestFuzzer::Fuzz();
1667 CHECK(info.This()->Equals(bottom));
Iain Merrick75681382010-08-19 15:07:18 +01001668 return v8::Handle<v8::Integer>();
Steve Blocka7e24c12009-10-30 11:49:00 +00001669}
1670
1671
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001672v8::Handle<v8::Integer> CheckThisNamedPropertyQuery(Local<String> property,
Steve Blocka7e24c12009-10-30 11:49:00 +00001673 const AccessorInfo& info) {
1674 ApiTestFuzzer::Fuzz();
1675 CHECK(info.This()->Equals(bottom));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001676 return v8::Handle<v8::Integer>();
Steve Blocka7e24c12009-10-30 11:49:00 +00001677}
1678
1679
1680v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
1681 uint32_t index,
1682 const AccessorInfo& info) {
1683 ApiTestFuzzer::Fuzz();
1684 CHECK(info.This()->Equals(bottom));
1685 return v8::Handle<v8::Boolean>();
1686}
1687
1688
1689v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
1690 Local<String> property,
1691 const AccessorInfo& info) {
1692 ApiTestFuzzer::Fuzz();
1693 CHECK(info.This()->Equals(bottom));
1694 return v8::Handle<v8::Boolean>();
1695}
1696
1697
1698v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
1699 const AccessorInfo& info) {
1700 ApiTestFuzzer::Fuzz();
1701 CHECK(info.This()->Equals(bottom));
1702 return v8::Handle<v8::Array>();
1703}
1704
1705
1706v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
1707 const AccessorInfo& info) {
1708 ApiTestFuzzer::Fuzz();
1709 CHECK(info.This()->Equals(bottom));
1710 return v8::Handle<v8::Array>();
1711}
1712
1713
1714THREADED_TEST(PropertyHandlerInPrototype) {
1715 v8::HandleScope scope;
1716 LocalContext env;
1717
1718 // Set up a prototype chain with three interceptors.
1719 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1720 templ->InstanceTemplate()->SetIndexedPropertyHandler(
1721 CheckThisIndexedPropertyHandler,
1722 CheckThisIndexedPropertySetter,
1723 CheckThisIndexedPropertyQuery,
1724 CheckThisIndexedPropertyDeleter,
1725 CheckThisIndexedPropertyEnumerator);
1726
1727 templ->InstanceTemplate()->SetNamedPropertyHandler(
1728 CheckThisNamedPropertyHandler,
1729 CheckThisNamedPropertySetter,
1730 CheckThisNamedPropertyQuery,
1731 CheckThisNamedPropertyDeleter,
1732 CheckThisNamedPropertyEnumerator);
1733
1734 bottom = templ->GetFunction()->NewInstance();
1735 Local<v8::Object> top = templ->GetFunction()->NewInstance();
1736 Local<v8::Object> middle = templ->GetFunction()->NewInstance();
1737
1738 bottom->Set(v8_str("__proto__"), middle);
1739 middle->Set(v8_str("__proto__"), top);
1740 env->Global()->Set(v8_str("obj"), bottom);
1741
1742 // Indexed and named get.
1743 Script::Compile(v8_str("obj[0]"))->Run();
1744 Script::Compile(v8_str("obj.x"))->Run();
1745
1746 // Indexed and named set.
1747 Script::Compile(v8_str("obj[1] = 42"))->Run();
1748 Script::Compile(v8_str("obj.y = 42"))->Run();
1749
1750 // Indexed and named query.
1751 Script::Compile(v8_str("0 in obj"))->Run();
1752 Script::Compile(v8_str("'x' in obj"))->Run();
1753
1754 // Indexed and named deleter.
1755 Script::Compile(v8_str("delete obj[0]"))->Run();
1756 Script::Compile(v8_str("delete obj.x"))->Run();
1757
1758 // Enumerators.
1759 Script::Compile(v8_str("for (var p in obj) ;"))->Run();
1760}
1761
1762
1763static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
1764 const AccessorInfo& info) {
1765 ApiTestFuzzer::Fuzz();
1766 if (v8_str("pre")->Equals(key)) {
1767 return v8_str("PrePropertyHandler: pre");
1768 }
1769 return v8::Handle<String>();
1770}
1771
1772
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001773static v8::Handle<v8::Integer> PrePropertyHandlerQuery(Local<String> key,
1774 const AccessorInfo&) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001775 if (v8_str("pre")->Equals(key)) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001776 return v8::Integer::New(v8::None);
Steve Blocka7e24c12009-10-30 11:49:00 +00001777 }
1778
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001779 return v8::Handle<v8::Integer>(); // do not intercept the call
Steve Blocka7e24c12009-10-30 11:49:00 +00001780}
1781
1782
1783THREADED_TEST(PrePropertyHandler) {
1784 v8::HandleScope scope;
1785 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
1786 desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
1787 0,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001788 PrePropertyHandlerQuery);
Steve Blocka7e24c12009-10-30 11:49:00 +00001789 LocalContext env(NULL, desc->InstanceTemplate());
1790 Script::Compile(v8_str(
1791 "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
1792 v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
1793 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
1794 v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
1795 CHECK_EQ(v8_str("Object: on"), result_on);
1796 v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
1797 CHECK(result_post.IsEmpty());
1798}
1799
1800
1801THREADED_TEST(UndefinedIsNotEnumerable) {
1802 v8::HandleScope scope;
1803 LocalContext env;
1804 v8::Handle<Value> result = Script::Compile(v8_str(
1805 "this.propertyIsEnumerable(undefined)"))->Run();
1806 CHECK(result->IsFalse());
1807}
1808
1809
1810v8::Handle<Script> call_recursively_script;
Leon Clarke4515c472010-02-03 11:58:03 +00001811static const int kTargetRecursionDepth = 200; // near maximum
Steve Blocka7e24c12009-10-30 11:49:00 +00001812
1813
1814static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
1815 ApiTestFuzzer::Fuzz();
1816 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1817 if (depth == kTargetRecursionDepth) return v8::Undefined();
1818 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1819 return call_recursively_script->Run();
1820}
1821
1822
1823static v8::Handle<Value> CallFunctionRecursivelyCall(
1824 const v8::Arguments& args) {
1825 ApiTestFuzzer::Fuzz();
1826 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1827 if (depth == kTargetRecursionDepth) {
1828 printf("[depth = %d]\n", depth);
1829 return v8::Undefined();
1830 }
1831 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1832 v8::Handle<Value> function =
1833 args.This()->Get(v8_str("callFunctionRecursively"));
Steve Block6ded16b2010-05-10 14:33:55 +01001834 return function.As<Function>()->Call(args.This(), 0, NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001835}
1836
1837
1838THREADED_TEST(DeepCrossLanguageRecursion) {
1839 v8::HandleScope scope;
1840 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
1841 global->Set(v8_str("callScriptRecursively"),
1842 v8::FunctionTemplate::New(CallScriptRecursivelyCall));
1843 global->Set(v8_str("callFunctionRecursively"),
1844 v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
1845 LocalContext env(NULL, global);
1846
1847 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1848 call_recursively_script = v8_compile("callScriptRecursively()");
Ben Murdochc7cc0282012-03-05 14:35:55 +00001849 call_recursively_script->Run();
Steve Blocka7e24c12009-10-30 11:49:00 +00001850 call_recursively_script = v8::Handle<Script>();
1851
1852 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1853 Script::Compile(v8_str("callFunctionRecursively()"))->Run();
1854}
1855
1856
1857static v8::Handle<Value>
1858 ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1859 ApiTestFuzzer::Fuzz();
1860 return v8::ThrowException(key);
1861}
1862
1863
1864static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
1865 Local<Value>,
1866 const AccessorInfo&) {
1867 v8::ThrowException(key);
1868 return v8::Undefined(); // not the same as v8::Handle<v8::Value>()
1869}
1870
1871
1872THREADED_TEST(CallbackExceptionRegression) {
1873 v8::HandleScope scope;
1874 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1875 obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
1876 ThrowingPropertyHandlerSet);
1877 LocalContext env;
1878 env->Global()->Set(v8_str("obj"), obj->NewInstance());
1879 v8::Handle<Value> otto = Script::Compile(v8_str(
1880 "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
1881 CHECK_EQ(v8_str("otto"), otto);
1882 v8::Handle<Value> netto = Script::Compile(v8_str(
1883 "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
1884 CHECK_EQ(v8_str("netto"), netto);
1885}
1886
1887
Steve Blocka7e24c12009-10-30 11:49:00 +00001888THREADED_TEST(FunctionPrototype) {
1889 v8::HandleScope scope;
1890 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
1891 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
1892 LocalContext env;
1893 env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
1894 Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
1895 CHECK_EQ(script->Run()->Int32Value(), 321);
1896}
1897
1898
1899THREADED_TEST(InternalFields) {
1900 v8::HandleScope scope;
1901 LocalContext env;
1902
1903 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1904 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1905 instance_templ->SetInternalFieldCount(1);
1906 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1907 CHECK_EQ(1, obj->InternalFieldCount());
1908 CHECK(obj->GetInternalField(0)->IsUndefined());
1909 obj->SetInternalField(0, v8_num(17));
1910 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
1911}
1912
1913
Steve Block6ded16b2010-05-10 14:33:55 +01001914THREADED_TEST(GlobalObjectInternalFields) {
1915 v8::HandleScope scope;
1916 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
1917 global_template->SetInternalFieldCount(1);
1918 LocalContext env(NULL, global_template);
1919 v8::Handle<v8::Object> global_proxy = env->Global();
1920 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
1921 CHECK_EQ(1, global->InternalFieldCount());
1922 CHECK(global->GetInternalField(0)->IsUndefined());
1923 global->SetInternalField(0, v8_num(17));
1924 CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
1925}
1926
1927
Steve Blocka7e24c12009-10-30 11:49:00 +00001928THREADED_TEST(InternalFieldsNativePointers) {
1929 v8::HandleScope scope;
1930 LocalContext env;
1931
1932 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1933 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1934 instance_templ->SetInternalFieldCount(1);
1935 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1936 CHECK_EQ(1, obj->InternalFieldCount());
1937 CHECK(obj->GetPointerFromInternalField(0) == NULL);
1938
1939 char* data = new char[100];
1940
1941 void* aligned = data;
Ben Murdochf87a2032010-10-22 12:50:53 +01001942 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
Steve Blocka7e24c12009-10-30 11:49:00 +00001943 void* unaligned = data + 1;
Ben Murdochf87a2032010-10-22 12:50:53 +01001944 CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
Steve Blocka7e24c12009-10-30 11:49:00 +00001945
1946 // Check reading and writing aligned pointers.
1947 obj->SetPointerInInternalField(0, aligned);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001948 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +00001949 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1950
1951 // Check reading and writing unaligned pointers.
1952 obj->SetPointerInInternalField(0, unaligned);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001953 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +00001954 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1955
1956 delete[] data;
1957}
1958
1959
Steve Block3ce2e202009-11-05 08:53:23 +00001960THREADED_TEST(InternalFieldsNativePointersAndExternal) {
1961 v8::HandleScope scope;
1962 LocalContext env;
1963
1964 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1965 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1966 instance_templ->SetInternalFieldCount(1);
1967 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1968 CHECK_EQ(1, obj->InternalFieldCount());
1969 CHECK(obj->GetPointerFromInternalField(0) == NULL);
1970
1971 char* data = new char[100];
1972
1973 void* aligned = data;
Ben Murdochf87a2032010-10-22 12:50:53 +01001974 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
Steve Block3ce2e202009-11-05 08:53:23 +00001975 void* unaligned = data + 1;
Ben Murdochf87a2032010-10-22 12:50:53 +01001976 CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
Steve Block3ce2e202009-11-05 08:53:23 +00001977
1978 obj->SetPointerInInternalField(0, aligned);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001979 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Block3ce2e202009-11-05 08:53:23 +00001980 CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0)));
1981
1982 obj->SetPointerInInternalField(0, unaligned);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001983 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Block3ce2e202009-11-05 08:53:23 +00001984 CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0)));
1985
1986 obj->SetInternalField(0, v8::External::Wrap(aligned));
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001987 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Block3ce2e202009-11-05 08:53:23 +00001988 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1989
1990 obj->SetInternalField(0, v8::External::Wrap(unaligned));
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001991 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Block3ce2e202009-11-05 08:53:23 +00001992 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1993
1994 delete[] data;
1995}
1996
1997
Steve Blocka7e24c12009-10-30 11:49:00 +00001998THREADED_TEST(IdentityHash) {
1999 v8::HandleScope scope;
2000 LocalContext env;
2001
2002 // Ensure that the test starts with an fresh heap to test whether the hash
2003 // code is based on the address.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002004 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +00002005 Local<v8::Object> obj = v8::Object::New();
2006 int hash = obj->GetIdentityHash();
2007 int hash1 = obj->GetIdentityHash();
2008 CHECK_EQ(hash, hash1);
2009 int hash2 = v8::Object::New()->GetIdentityHash();
2010 // Since the identity hash is essentially a random number two consecutive
2011 // objects should not be assigned the same hash code. If the test below fails
2012 // the random number generator should be evaluated.
2013 CHECK_NE(hash, hash2);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002014 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +00002015 int hash3 = v8::Object::New()->GetIdentityHash();
2016 // Make sure that the identity hash is not based on the initial address of
2017 // the object alone. If the test below fails the random number generator
2018 // should be evaluated.
2019 CHECK_NE(hash, hash3);
2020 int hash4 = obj->GetIdentityHash();
2021 CHECK_EQ(hash, hash4);
Steve Block1e0659c2011-05-24 12:43:12 +01002022
2023 // Check identity hashes behaviour in the presence of JS accessors.
2024 // Put a getter for 'v8::IdentityHash' on the Object's prototype:
2025 {
2026 CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
2027 Local<v8::Object> o1 = v8::Object::New();
2028 Local<v8::Object> o2 = v8::Object::New();
2029 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2030 }
2031 {
2032 CompileRun(
2033 "function cnst() { return 42; };\n"
2034 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
2035 Local<v8::Object> o1 = v8::Object::New();
2036 Local<v8::Object> o2 = v8::Object::New();
2037 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2038 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002039}
2040
2041
2042THREADED_TEST(HiddenProperties) {
2043 v8::HandleScope scope;
2044 LocalContext env;
2045
2046 v8::Local<v8::Object> obj = v8::Object::New();
2047 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
2048 v8::Local<v8::String> empty = v8_str("");
2049 v8::Local<v8::String> prop_name = v8_str("prop_name");
2050
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002051 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +00002052
2053 // Make sure delete of a non-existent hidden value works
2054 CHECK(obj->DeleteHiddenValue(key));
2055
2056 CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
2057 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
2058 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
2059 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2060
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002061 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +00002062
2063 // Make sure we do not find the hidden property.
2064 CHECK(!obj->Has(empty));
2065 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2066 CHECK(obj->Get(empty)->IsUndefined());
2067 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2068 CHECK(obj->Set(empty, v8::Integer::New(2003)));
2069 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2070 CHECK_EQ(2003, obj->Get(empty)->Int32Value());
2071
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002072 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +00002073
2074 // Add another property and delete it afterwards to force the object in
2075 // slow case.
2076 CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
2077 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2078 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
2079 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2080 CHECK(obj->Delete(prop_name));
2081 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2082
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002083 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +00002084
2085 CHECK(obj->DeleteHiddenValue(key));
2086 CHECK(obj->GetHiddenValue(key).IsEmpty());
2087}
2088
2089
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002090THREADED_TEST(Regress97784) {
2091 // Regression test for crbug.com/97784
2092 // Messing with the Object.prototype should not have effect on
2093 // hidden properties.
2094 v8::HandleScope scope;
2095 LocalContext env;
2096
2097 v8::Local<v8::Object> obj = v8::Object::New();
2098 v8::Local<v8::String> key = v8_str("hidden");
2099
2100 CompileRun(
2101 "set_called = false;"
2102 "Object.defineProperty("
2103 " Object.prototype,"
2104 " 'hidden',"
2105 " {get: function() { return 45; },"
2106 " set: function() { set_called = true; }})");
2107
2108 CHECK(obj->GetHiddenValue(key).IsEmpty());
2109 // Make sure that the getter and setter from Object.prototype is not invoked.
2110 // If it did we would have full access to the hidden properties in
2111 // the accessor.
2112 CHECK(obj->SetHiddenValue(key, v8::Integer::New(42)));
2113 ExpectFalse("set_called");
2114 CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
2115}
2116
2117
Steve Blockd0582a62009-12-15 09:54:21 +00002118static bool interceptor_for_hidden_properties_called;
Steve Blocka7e24c12009-10-30 11:49:00 +00002119static v8::Handle<Value> InterceptorForHiddenProperties(
2120 Local<String> name, const AccessorInfo& info) {
Steve Blockd0582a62009-12-15 09:54:21 +00002121 interceptor_for_hidden_properties_called = true;
Steve Blocka7e24c12009-10-30 11:49:00 +00002122 return v8::Handle<Value>();
2123}
2124
2125
2126THREADED_TEST(HiddenPropertiesWithInterceptors) {
2127 v8::HandleScope scope;
2128 LocalContext context;
2129
Steve Blockd0582a62009-12-15 09:54:21 +00002130 interceptor_for_hidden_properties_called = false;
2131
Steve Blocka7e24c12009-10-30 11:49:00 +00002132 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
2133
2134 // Associate an interceptor with an object and start setting hidden values.
2135 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
2136 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
2137 instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
2138 Local<v8::Function> function = fun_templ->GetFunction();
2139 Local<v8::Object> obj = function->NewInstance();
2140 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
2141 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
Steve Blockd0582a62009-12-15 09:54:21 +00002142 CHECK(!interceptor_for_hidden_properties_called);
Steve Blocka7e24c12009-10-30 11:49:00 +00002143}
2144
2145
2146THREADED_TEST(External) {
2147 v8::HandleScope scope;
2148 int x = 3;
2149 Local<v8::External> ext = v8::External::New(&x);
2150 LocalContext env;
2151 env->Global()->Set(v8_str("ext"), ext);
2152 Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
Steve Block6ded16b2010-05-10 14:33:55 +01002153 v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
Steve Blocka7e24c12009-10-30 11:49:00 +00002154 int* ptr = static_cast<int*>(reext->Value());
2155 CHECK_EQ(x, 3);
2156 *ptr = 10;
2157 CHECK_EQ(x, 10);
2158
2159 // Make sure unaligned pointers are wrapped properly.
2160 char* data = i::StrDup("0123456789");
2161 Local<v8::Value> zero = v8::External::Wrap(&data[0]);
2162 Local<v8::Value> one = v8::External::Wrap(&data[1]);
2163 Local<v8::Value> two = v8::External::Wrap(&data[2]);
2164 Local<v8::Value> three = v8::External::Wrap(&data[3]);
2165
2166 char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero));
2167 CHECK_EQ('0', *char_ptr);
2168 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one));
2169 CHECK_EQ('1', *char_ptr);
2170 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two));
2171 CHECK_EQ('2', *char_ptr);
2172 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three));
2173 CHECK_EQ('3', *char_ptr);
2174 i::DeleteArray(data);
2175}
2176
2177
2178THREADED_TEST(GlobalHandle) {
2179 v8::Persistent<String> global;
2180 {
2181 v8::HandleScope scope;
2182 Local<String> str = v8_str("str");
2183 global = v8::Persistent<String>::New(str);
2184 }
2185 CHECK_EQ(global->Length(), 3);
2186 global.Dispose();
2187}
2188
2189
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002190class WeakCallCounter {
2191 public:
2192 explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
2193 int id() { return id_; }
2194 void increment() { number_of_weak_calls_++; }
2195 int NumberOfWeakCalls() { return number_of_weak_calls_; }
2196 private:
2197 int id_;
2198 int number_of_weak_calls_;
2199};
2200
2201
Steve Block44f0eee2011-05-26 01:26:41 +01002202static void WeakPointerCallback(Persistent<Value> handle, void* id) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002203 WeakCallCounter* counter = reinterpret_cast<WeakCallCounter*>(id);
2204 CHECK_EQ(1234, counter->id());
2205 counter->increment();
Steve Block44f0eee2011-05-26 01:26:41 +01002206 handle.Dispose();
2207}
2208
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002209
Steve Block44f0eee2011-05-26 01:26:41 +01002210THREADED_TEST(ApiObjectGroups) {
2211 HandleScope scope;
2212 LocalContext env;
2213
Steve Block44f0eee2011-05-26 01:26:41 +01002214 Persistent<Object> g1s1;
2215 Persistent<Object> g1s2;
2216 Persistent<Object> g1c1;
2217 Persistent<Object> g2s1;
2218 Persistent<Object> g2s2;
2219 Persistent<Object> g2c1;
2220
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002221 WeakCallCounter counter(1234);
2222
Steve Block44f0eee2011-05-26 01:26:41 +01002223 {
2224 HandleScope scope;
2225 g1s1 = Persistent<Object>::New(Object::New());
2226 g1s2 = Persistent<Object>::New(Object::New());
2227 g1c1 = Persistent<Object>::New(Object::New());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002228 g1s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2229 g1s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2230 g1c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
Steve Block44f0eee2011-05-26 01:26:41 +01002231
2232 g2s1 = Persistent<Object>::New(Object::New());
2233 g2s2 = Persistent<Object>::New(Object::New());
2234 g2c1 = Persistent<Object>::New(Object::New());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002235 g2s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2236 g2s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2237 g2c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
Steve Block44f0eee2011-05-26 01:26:41 +01002238 }
2239
2240 Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
2241
2242 // Connect group 1 and 2, make a cycle.
2243 CHECK(g1s2->Set(0, g2s2));
2244 CHECK(g2s1->Set(0, g1s1));
2245
2246 {
2247 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2248 Persistent<Value> g1_children[] = { g1c1 };
2249 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2250 Persistent<Value> g2_children[] = { g2c1 };
2251 V8::AddObjectGroup(g1_objects, 2);
2252 V8::AddImplicitReferences(g1s1, g1_children, 1);
2253 V8::AddObjectGroup(g2_objects, 2);
2254 V8::AddImplicitReferences(g2s2, g2_children, 1);
2255 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002256 // Do a single full GC. Use kMakeHeapIterableMask to ensure that
2257 // incremental garbage collection is stopped.
2258 HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
Steve Block44f0eee2011-05-26 01:26:41 +01002259
2260 // All object should be alive.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002261 CHECK_EQ(0, counter.NumberOfWeakCalls());
Steve Block44f0eee2011-05-26 01:26:41 +01002262
2263 // Weaken the root.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002264 root.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
Steve Block44f0eee2011-05-26 01:26:41 +01002265 // But make children strong roots---all the objects (except for children)
2266 // should be collectable now.
2267 g1c1.ClearWeak();
2268 g2c1.ClearWeak();
2269
2270 // Groups are deleted, rebuild groups.
2271 {
2272 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2273 Persistent<Value> g1_children[] = { g1c1 };
2274 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2275 Persistent<Value> g2_children[] = { g2c1 };
2276 V8::AddObjectGroup(g1_objects, 2);
2277 V8::AddImplicitReferences(g1s1, g1_children, 1);
2278 V8::AddObjectGroup(g2_objects, 2);
2279 V8::AddImplicitReferences(g2s2, g2_children, 1);
2280 }
2281
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002282 HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
Steve Block44f0eee2011-05-26 01:26:41 +01002283
2284 // All objects should be gone. 5 global handles in total.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002285 CHECK_EQ(5, counter.NumberOfWeakCalls());
Steve Block44f0eee2011-05-26 01:26:41 +01002286
2287 // And now make children weak again and collect them.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002288 g1c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2289 g2c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
Steve Block44f0eee2011-05-26 01:26:41 +01002290
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002291 HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
2292 CHECK_EQ(7, counter.NumberOfWeakCalls());
Steve Block44f0eee2011-05-26 01:26:41 +01002293}
2294
2295
2296THREADED_TEST(ApiObjectGroupsCycle) {
2297 HandleScope scope;
2298 LocalContext env;
2299
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002300 WeakCallCounter counter(1234);
Steve Block44f0eee2011-05-26 01:26:41 +01002301
2302 Persistent<Object> g1s1;
2303 Persistent<Object> g1s2;
2304 Persistent<Object> g2s1;
2305 Persistent<Object> g2s2;
2306 Persistent<Object> g3s1;
2307 Persistent<Object> g3s2;
2308
2309 {
2310 HandleScope scope;
2311 g1s1 = Persistent<Object>::New(Object::New());
2312 g1s2 = Persistent<Object>::New(Object::New());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002313 g1s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2314 g1s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
Steve Block44f0eee2011-05-26 01:26:41 +01002315
2316 g2s1 = Persistent<Object>::New(Object::New());
2317 g2s2 = Persistent<Object>::New(Object::New());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002318 g2s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2319 g2s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
Steve Block44f0eee2011-05-26 01:26:41 +01002320
2321 g3s1 = Persistent<Object>::New(Object::New());
2322 g3s2 = Persistent<Object>::New(Object::New());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002323 g3s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2324 g3s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
Steve Block44f0eee2011-05-26 01:26:41 +01002325 }
2326
2327 Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
2328
2329 // Connect groups. We're building the following cycle:
2330 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
2331 // groups.
2332 {
2333 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2334 Persistent<Value> g1_children[] = { g2s1 };
2335 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2336 Persistent<Value> g2_children[] = { g3s1 };
2337 Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2338 Persistent<Value> g3_children[] = { g1s1 };
2339 V8::AddObjectGroup(g1_objects, 2);
2340 V8::AddImplicitReferences(g1s1, g1_children, 1);
2341 V8::AddObjectGroup(g2_objects, 2);
2342 V8::AddImplicitReferences(g2s1, g2_children, 1);
2343 V8::AddObjectGroup(g3_objects, 2);
2344 V8::AddImplicitReferences(g3s1, g3_children, 1);
2345 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002346 // Do a single full GC
2347 HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
Steve Block44f0eee2011-05-26 01:26:41 +01002348
2349 // All object should be alive.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002350 CHECK_EQ(0, counter.NumberOfWeakCalls());
Steve Block44f0eee2011-05-26 01:26:41 +01002351
2352 // Weaken the root.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002353 root.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
Steve Block44f0eee2011-05-26 01:26:41 +01002354
2355 // Groups are deleted, rebuild groups.
2356 {
2357 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2358 Persistent<Value> g1_children[] = { g2s1 };
2359 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2360 Persistent<Value> g2_children[] = { g3s1 };
2361 Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2362 Persistent<Value> g3_children[] = { g1s1 };
2363 V8::AddObjectGroup(g1_objects, 2);
2364 V8::AddImplicitReferences(g1s1, g1_children, 1);
2365 V8::AddObjectGroup(g2_objects, 2);
2366 V8::AddImplicitReferences(g2s1, g2_children, 1);
2367 V8::AddObjectGroup(g3_objects, 2);
2368 V8::AddImplicitReferences(g3s1, g3_children, 1);
2369 }
2370
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002371 HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
Steve Block44f0eee2011-05-26 01:26:41 +01002372
2373 // All objects should be gone. 7 global handles in total.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002374 CHECK_EQ(7, counter.NumberOfWeakCalls());
Steve Block44f0eee2011-05-26 01:26:41 +01002375}
2376
2377
Steve Blocka7e24c12009-10-30 11:49:00 +00002378THREADED_TEST(ScriptException) {
2379 v8::HandleScope scope;
2380 LocalContext env;
2381 Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
2382 v8::TryCatch try_catch;
2383 Local<Value> result = script->Run();
2384 CHECK(result.IsEmpty());
2385 CHECK(try_catch.HasCaught());
2386 String::AsciiValue exception_value(try_catch.Exception());
2387 CHECK_EQ(*exception_value, "panama!");
2388}
2389
2390
2391bool message_received;
2392
2393
2394static void check_message(v8::Handle<v8::Message> message,
2395 v8::Handle<Value> data) {
2396 CHECK_EQ(5.76, data->NumberValue());
2397 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
2398 CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
2399 message_received = true;
2400}
2401
2402
2403THREADED_TEST(MessageHandlerData) {
2404 message_received = false;
2405 v8::HandleScope scope;
2406 CHECK(!message_received);
2407 v8::V8::AddMessageListener(check_message, v8_num(5.76));
2408 LocalContext context;
2409 v8::ScriptOrigin origin =
2410 v8::ScriptOrigin(v8_str("6.75"));
2411 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
2412 &origin);
2413 script->SetData(v8_str("7.56"));
2414 script->Run();
2415 CHECK(message_received);
2416 // clear out the message listener
2417 v8::V8::RemoveMessageListeners(check_message);
2418}
2419
2420
2421THREADED_TEST(GetSetProperty) {
2422 v8::HandleScope scope;
2423 LocalContext context;
2424 context->Global()->Set(v8_str("foo"), v8_num(14));
2425 context->Global()->Set(v8_str("12"), v8_num(92));
2426 context->Global()->Set(v8::Integer::New(16), v8_num(32));
2427 context->Global()->Set(v8_num(13), v8_num(56));
2428 Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
2429 CHECK_EQ(14, foo->Int32Value());
2430 Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
2431 CHECK_EQ(92, twelve->Int32Value());
2432 Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
2433 CHECK_EQ(32, sixteen->Int32Value());
2434 Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
2435 CHECK_EQ(56, thirteen->Int32Value());
2436 CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
2437 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
2438 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
2439 CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
2440 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
2441 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
2442 CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
2443 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
2444 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
2445}
2446
2447
2448THREADED_TEST(PropertyAttributes) {
2449 v8::HandleScope scope;
2450 LocalContext context;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002451 // none
2452 Local<String> prop = v8_str("none");
2453 context->Global()->Set(prop, v8_num(7));
2454 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
Steve Blocka7e24c12009-10-30 11:49:00 +00002455 // read-only
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002456 prop = v8_str("read_only");
Steve Blocka7e24c12009-10-30 11:49:00 +00002457 context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
2458 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002459 CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
Steve Blocka7e24c12009-10-30 11:49:00 +00002460 Script::Compile(v8_str("read_only = 9"))->Run();
2461 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2462 context->Global()->Set(prop, v8_num(10));
2463 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2464 // dont-delete
2465 prop = v8_str("dont_delete");
2466 context->Global()->Set(prop, v8_num(13), v8::DontDelete);
2467 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
2468 Script::Compile(v8_str("delete dont_delete"))->Run();
2469 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002470 CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
2471 // dont-enum
2472 prop = v8_str("dont_enum");
2473 context->Global()->Set(prop, v8_num(28), v8::DontEnum);
2474 CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
2475 // absent
2476 prop = v8_str("absent");
2477 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
2478 Local<Value> fake_prop = v8_num(1);
2479 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
2480 // exception
2481 TryCatch try_catch;
2482 Local<Value> exception =
2483 CompileRun("({ toString: function() { throw 'exception';} })");
2484 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
2485 CHECK(try_catch.HasCaught());
2486 String::AsciiValue exception_value(try_catch.Exception());
2487 CHECK_EQ("exception", *exception_value);
2488 try_catch.Reset();
Steve Blocka7e24c12009-10-30 11:49:00 +00002489}
2490
2491
2492THREADED_TEST(Array) {
2493 v8::HandleScope scope;
2494 LocalContext context;
2495 Local<v8::Array> array = v8::Array::New();
2496 CHECK_EQ(0, array->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01002497 CHECK(array->Get(0)->IsUndefined());
Steve Blocka7e24c12009-10-30 11:49:00 +00002498 CHECK(!array->Has(0));
Steve Block6ded16b2010-05-10 14:33:55 +01002499 CHECK(array->Get(100)->IsUndefined());
Steve Blocka7e24c12009-10-30 11:49:00 +00002500 CHECK(!array->Has(100));
Steve Block6ded16b2010-05-10 14:33:55 +01002501 array->Set(2, v8_num(7));
Steve Blocka7e24c12009-10-30 11:49:00 +00002502 CHECK_EQ(3, array->Length());
2503 CHECK(!array->Has(0));
2504 CHECK(!array->Has(1));
2505 CHECK(array->Has(2));
Steve Block6ded16b2010-05-10 14:33:55 +01002506 CHECK_EQ(7, array->Get(2)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00002507 Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
Steve Block6ded16b2010-05-10 14:33:55 +01002508 Local<v8::Array> arr = obj.As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00002509 CHECK_EQ(3, arr->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01002510 CHECK_EQ(1, arr->Get(0)->Int32Value());
2511 CHECK_EQ(2, arr->Get(1)->Int32Value());
2512 CHECK_EQ(3, arr->Get(2)->Int32Value());
Steve Block44f0eee2011-05-26 01:26:41 +01002513 array = v8::Array::New(27);
2514 CHECK_EQ(27, array->Length());
2515 array = v8::Array::New(-27);
2516 CHECK_EQ(0, array->Length());
Steve Blocka7e24c12009-10-30 11:49:00 +00002517}
2518
2519
2520v8::Handle<Value> HandleF(const v8::Arguments& args) {
2521 v8::HandleScope scope;
2522 ApiTestFuzzer::Fuzz();
2523 Local<v8::Array> result = v8::Array::New(args.Length());
2524 for (int i = 0; i < args.Length(); i++)
Steve Block6ded16b2010-05-10 14:33:55 +01002525 result->Set(i, args[i]);
Steve Blocka7e24c12009-10-30 11:49:00 +00002526 return scope.Close(result);
2527}
2528
2529
2530THREADED_TEST(Vector) {
2531 v8::HandleScope scope;
2532 Local<ObjectTemplate> global = ObjectTemplate::New();
2533 global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
2534 LocalContext context(0, global);
2535
2536 const char* fun = "f()";
Steve Block6ded16b2010-05-10 14:33:55 +01002537 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00002538 CHECK_EQ(0, a0->Length());
2539
2540 const char* fun2 = "f(11)";
Steve Block6ded16b2010-05-10 14:33:55 +01002541 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00002542 CHECK_EQ(1, a1->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01002543 CHECK_EQ(11, a1->Get(0)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00002544
2545 const char* fun3 = "f(12, 13)";
Steve Block6ded16b2010-05-10 14:33:55 +01002546 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00002547 CHECK_EQ(2, a2->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01002548 CHECK_EQ(12, a2->Get(0)->Int32Value());
2549 CHECK_EQ(13, a2->Get(1)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00002550
2551 const char* fun4 = "f(14, 15, 16)";
Steve Block6ded16b2010-05-10 14:33:55 +01002552 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00002553 CHECK_EQ(3, a3->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01002554 CHECK_EQ(14, a3->Get(0)->Int32Value());
2555 CHECK_EQ(15, a3->Get(1)->Int32Value());
2556 CHECK_EQ(16, a3->Get(2)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00002557
2558 const char* fun5 = "f(17, 18, 19, 20)";
Steve Block6ded16b2010-05-10 14:33:55 +01002559 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00002560 CHECK_EQ(4, a4->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01002561 CHECK_EQ(17, a4->Get(0)->Int32Value());
2562 CHECK_EQ(18, a4->Get(1)->Int32Value());
2563 CHECK_EQ(19, a4->Get(2)->Int32Value());
2564 CHECK_EQ(20, a4->Get(3)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00002565}
2566
2567
2568THREADED_TEST(FunctionCall) {
2569 v8::HandleScope scope;
2570 LocalContext context;
2571 CompileRun(
2572 "function Foo() {"
2573 " var result = [];"
2574 " for (var i = 0; i < arguments.length; i++) {"
2575 " result.push(arguments[i]);"
2576 " }"
2577 " return result;"
2578 "}");
2579 Local<Function> Foo =
2580 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2581
2582 v8::Handle<Value>* args0 = NULL;
2583 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
2584 CHECK_EQ(0, a0->Length());
2585
2586 v8::Handle<Value> args1[] = { v8_num(1.1) };
2587 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
2588 CHECK_EQ(1, a1->Length());
2589 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2590
2591 v8::Handle<Value> args2[] = { v8_num(2.2),
2592 v8_num(3.3) };
2593 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
2594 CHECK_EQ(2, a2->Length());
2595 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2596 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2597
2598 v8::Handle<Value> args3[] = { v8_num(4.4),
2599 v8_num(5.5),
2600 v8_num(6.6) };
2601 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
2602 CHECK_EQ(3, a3->Length());
2603 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2604 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2605 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2606
2607 v8::Handle<Value> args4[] = { v8_num(7.7),
2608 v8_num(8.8),
2609 v8_num(9.9),
2610 v8_num(10.11) };
2611 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
2612 CHECK_EQ(4, a4->Length());
2613 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2614 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2615 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2616 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2617}
2618
2619
2620static const char* js_code_causing_out_of_memory =
2621 "var a = new Array(); while(true) a.push(a);";
2622
2623
2624// These tests run for a long time and prevent us from running tests
2625// that come after them so they cannot run in parallel.
2626TEST(OutOfMemory) {
2627 // It's not possible to read a snapshot into a heap with different dimensions.
Steve Block8defd9f2010-07-08 12:39:36 +01002628 if (i::Snapshot::IsEnabled()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00002629 // Set heap limits.
2630 static const int K = 1024;
2631 v8::ResourceConstraints constraints;
2632 constraints.set_max_young_space_size(256 * K);
2633 constraints.set_max_old_space_size(4 * K * K);
2634 v8::SetResourceConstraints(&constraints);
2635
2636 // Execute a script that causes out of memory.
2637 v8::HandleScope scope;
2638 LocalContext context;
2639 v8::V8::IgnoreOutOfMemoryException();
2640 Local<Script> script =
2641 Script::Compile(String::New(js_code_causing_out_of_memory));
2642 Local<Value> result = script->Run();
2643
2644 // Check for out of memory state.
2645 CHECK(result.IsEmpty());
2646 CHECK(context->HasOutOfMemoryException());
2647}
2648
2649
2650v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
2651 ApiTestFuzzer::Fuzz();
2652
2653 v8::HandleScope scope;
2654 LocalContext context;
2655 Local<Script> script =
2656 Script::Compile(String::New(js_code_causing_out_of_memory));
2657 Local<Value> result = script->Run();
2658
2659 // Check for out of memory state.
2660 CHECK(result.IsEmpty());
2661 CHECK(context->HasOutOfMemoryException());
2662
2663 return result;
2664}
2665
2666
2667TEST(OutOfMemoryNested) {
2668 // It's not possible to read a snapshot into a heap with different dimensions.
Steve Block8defd9f2010-07-08 12:39:36 +01002669 if (i::Snapshot::IsEnabled()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00002670 // Set heap limits.
2671 static const int K = 1024;
2672 v8::ResourceConstraints constraints;
2673 constraints.set_max_young_space_size(256 * K);
2674 constraints.set_max_old_space_size(4 * K * K);
2675 v8::SetResourceConstraints(&constraints);
2676
2677 v8::HandleScope scope;
2678 Local<ObjectTemplate> templ = ObjectTemplate::New();
2679 templ->Set(v8_str("ProvokeOutOfMemory"),
2680 v8::FunctionTemplate::New(ProvokeOutOfMemory));
2681 LocalContext context(0, templ);
2682 v8::V8::IgnoreOutOfMemoryException();
2683 Local<Value> result = CompileRun(
2684 "var thrown = false;"
2685 "try {"
2686 " ProvokeOutOfMemory();"
2687 "} catch (e) {"
2688 " thrown = true;"
2689 "}");
2690 // Check for out of memory state.
2691 CHECK(result.IsEmpty());
2692 CHECK(context->HasOutOfMemoryException());
2693}
2694
2695
2696TEST(HugeConsStringOutOfMemory) {
2697 // It's not possible to read a snapshot into a heap with different dimensions.
Steve Block8defd9f2010-07-08 12:39:36 +01002698 if (i::Snapshot::IsEnabled()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00002699 // Set heap limits.
2700 static const int K = 1024;
2701 v8::ResourceConstraints constraints;
2702 constraints.set_max_young_space_size(256 * K);
2703 constraints.set_max_old_space_size(2 * K * K);
2704 v8::SetResourceConstraints(&constraints);
2705
2706 // Execute a script that causes out of memory.
2707 v8::V8::IgnoreOutOfMemoryException();
2708
Steve Block44f0eee2011-05-26 01:26:41 +01002709 v8::HandleScope scope;
2710 LocalContext context;
2711
Steve Blocka7e24c12009-10-30 11:49:00 +00002712 // Build huge string. This should fail with out of memory exception.
2713 Local<Value> result = CompileRun(
2714 "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
Steve Block3ce2e202009-11-05 08:53:23 +00002715 "for (var i = 0; i < 22; i++) { str = str + str; }");
Steve Blocka7e24c12009-10-30 11:49:00 +00002716
2717 // Check for out of memory state.
2718 CHECK(result.IsEmpty());
2719 CHECK(context->HasOutOfMemoryException());
2720}
2721
2722
2723THREADED_TEST(ConstructCall) {
2724 v8::HandleScope scope;
2725 LocalContext context;
2726 CompileRun(
2727 "function Foo() {"
2728 " var result = [];"
2729 " for (var i = 0; i < arguments.length; i++) {"
2730 " result.push(arguments[i]);"
2731 " }"
2732 " return result;"
2733 "}");
2734 Local<Function> Foo =
2735 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2736
2737 v8::Handle<Value>* args0 = NULL;
2738 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
2739 CHECK_EQ(0, a0->Length());
2740
2741 v8::Handle<Value> args1[] = { v8_num(1.1) };
2742 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
2743 CHECK_EQ(1, a1->Length());
2744 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2745
2746 v8::Handle<Value> args2[] = { v8_num(2.2),
2747 v8_num(3.3) };
2748 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
2749 CHECK_EQ(2, a2->Length());
2750 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2751 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2752
2753 v8::Handle<Value> args3[] = { v8_num(4.4),
2754 v8_num(5.5),
2755 v8_num(6.6) };
2756 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
2757 CHECK_EQ(3, a3->Length());
2758 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2759 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2760 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2761
2762 v8::Handle<Value> args4[] = { v8_num(7.7),
2763 v8_num(8.8),
2764 v8_num(9.9),
2765 v8_num(10.11) };
2766 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
2767 CHECK_EQ(4, a4->Length());
2768 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2769 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2770 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2771 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2772}
2773
2774
2775static void CheckUncle(v8::TryCatch* try_catch) {
2776 CHECK(try_catch->HasCaught());
2777 String::AsciiValue str_value(try_catch->Exception());
2778 CHECK_EQ(*str_value, "uncle?");
2779 try_catch->Reset();
2780}
2781
2782
Steve Block6ded16b2010-05-10 14:33:55 +01002783THREADED_TEST(ConversionNumber) {
2784 v8::HandleScope scope;
2785 LocalContext env;
2786 // Very large number.
2787 CompileRun("var obj = Math.pow(2,32) * 1237;");
2788 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2789 CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
2790 CHECK_EQ(0, obj->ToInt32()->Value());
2791 CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned.
2792 // Large number.
2793 CompileRun("var obj = -1234567890123;");
2794 obj = env->Global()->Get(v8_str("obj"));
2795 CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
2796 CHECK_EQ(-1912276171, obj->ToInt32()->Value());
2797 CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT
2798 // Small positive integer.
2799 CompileRun("var obj = 42;");
2800 obj = env->Global()->Get(v8_str("obj"));
2801 CHECK_EQ(42.0, obj->ToNumber()->Value());
2802 CHECK_EQ(42, obj->ToInt32()->Value());
2803 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
2804 // Negative integer.
2805 CompileRun("var obj = -37;");
2806 obj = env->Global()->Get(v8_str("obj"));
2807 CHECK_EQ(-37.0, obj->ToNumber()->Value());
2808 CHECK_EQ(-37, obj->ToInt32()->Value());
2809 CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT
2810 // Positive non-int32 integer.
2811 CompileRun("var obj = 0x81234567;");
2812 obj = env->Global()->Get(v8_str("obj"));
2813 CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
2814 CHECK_EQ(-2128394905, obj->ToInt32()->Value());
2815 CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT
2816 // Fraction.
2817 CompileRun("var obj = 42.3;");
2818 obj = env->Global()->Get(v8_str("obj"));
2819 CHECK_EQ(42.3, obj->ToNumber()->Value());
2820 CHECK_EQ(42, obj->ToInt32()->Value());
2821 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
2822 // Large negative fraction.
2823 CompileRun("var obj = -5726623061.75;");
2824 obj = env->Global()->Get(v8_str("obj"));
2825 CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
2826 CHECK_EQ(-1431655765, obj->ToInt32()->Value());
2827 CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT
2828}
2829
2830
2831THREADED_TEST(isNumberType) {
2832 v8::HandleScope scope;
2833 LocalContext env;
2834 // Very large number.
2835 CompileRun("var obj = Math.pow(2,32) * 1237;");
2836 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2837 CHECK(!obj->IsInt32());
2838 CHECK(!obj->IsUint32());
2839 // Large negative number.
2840 CompileRun("var obj = -1234567890123;");
2841 obj = env->Global()->Get(v8_str("obj"));
2842 CHECK(!obj->IsInt32());
2843 CHECK(!obj->IsUint32());
2844 // Small positive integer.
2845 CompileRun("var obj = 42;");
2846 obj = env->Global()->Get(v8_str("obj"));
2847 CHECK(obj->IsInt32());
2848 CHECK(obj->IsUint32());
2849 // Negative integer.
2850 CompileRun("var obj = -37;");
2851 obj = env->Global()->Get(v8_str("obj"));
2852 CHECK(obj->IsInt32());
2853 CHECK(!obj->IsUint32());
2854 // Positive non-int32 integer.
2855 CompileRun("var obj = 0x81234567;");
2856 obj = env->Global()->Get(v8_str("obj"));
2857 CHECK(!obj->IsInt32());
2858 CHECK(obj->IsUint32());
2859 // Fraction.
2860 CompileRun("var obj = 42.3;");
2861 obj = env->Global()->Get(v8_str("obj"));
2862 CHECK(!obj->IsInt32());
2863 CHECK(!obj->IsUint32());
2864 // Large negative fraction.
2865 CompileRun("var obj = -5726623061.75;");
2866 obj = env->Global()->Get(v8_str("obj"));
2867 CHECK(!obj->IsInt32());
2868 CHECK(!obj->IsUint32());
Ben Murdochc7cc0282012-03-05 14:35:55 +00002869 // Positive zero
2870 CompileRun("var obj = 0.0;");
2871 obj = env->Global()->Get(v8_str("obj"));
2872 CHECK(obj->IsInt32());
2873 CHECK(obj->IsUint32());
2874 // Positive zero
2875 CompileRun("var obj = -0.0;");
2876 obj = env->Global()->Get(v8_str("obj"));
2877 CHECK(!obj->IsInt32());
2878 CHECK(!obj->IsUint32());
Steve Block6ded16b2010-05-10 14:33:55 +01002879}
2880
2881
Steve Blocka7e24c12009-10-30 11:49:00 +00002882THREADED_TEST(ConversionException) {
2883 v8::HandleScope scope;
2884 LocalContext env;
2885 CompileRun(
2886 "function TestClass() { };"
2887 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
2888 "var obj = new TestClass();");
2889 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2890
2891 v8::TryCatch try_catch;
2892
2893 Local<Value> to_string_result = obj->ToString();
2894 CHECK(to_string_result.IsEmpty());
2895 CheckUncle(&try_catch);
2896
2897 Local<Value> to_number_result = obj->ToNumber();
2898 CHECK(to_number_result.IsEmpty());
2899 CheckUncle(&try_catch);
2900
2901 Local<Value> to_integer_result = obj->ToInteger();
2902 CHECK(to_integer_result.IsEmpty());
2903 CheckUncle(&try_catch);
2904
2905 Local<Value> to_uint32_result = obj->ToUint32();
2906 CHECK(to_uint32_result.IsEmpty());
2907 CheckUncle(&try_catch);
2908
2909 Local<Value> to_int32_result = obj->ToInt32();
2910 CHECK(to_int32_result.IsEmpty());
2911 CheckUncle(&try_catch);
2912
2913 Local<Value> to_object_result = v8::Undefined()->ToObject();
2914 CHECK(to_object_result.IsEmpty());
2915 CHECK(try_catch.HasCaught());
2916 try_catch.Reset();
2917
2918 int32_t int32_value = obj->Int32Value();
2919 CHECK_EQ(0, int32_value);
2920 CheckUncle(&try_catch);
2921
2922 uint32_t uint32_value = obj->Uint32Value();
2923 CHECK_EQ(0, uint32_value);
2924 CheckUncle(&try_catch);
2925
2926 double number_value = obj->NumberValue();
2927 CHECK_NE(0, IsNaN(number_value));
2928 CheckUncle(&try_catch);
2929
2930 int64_t integer_value = obj->IntegerValue();
2931 CHECK_EQ(0.0, static_cast<double>(integer_value));
2932 CheckUncle(&try_catch);
2933}
2934
2935
2936v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
2937 ApiTestFuzzer::Fuzz();
2938 return v8::ThrowException(v8_str("konto"));
2939}
2940
2941
2942v8::Handle<Value> CCatcher(const v8::Arguments& args) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002943 if (args.Length() < 1) return v8::False();
Steve Blocka7e24c12009-10-30 11:49:00 +00002944 v8::HandleScope scope;
2945 v8::TryCatch try_catch;
2946 Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
2947 CHECK(!try_catch.HasCaught() || result.IsEmpty());
2948 return v8::Boolean::New(try_catch.HasCaught());
2949}
2950
2951
2952THREADED_TEST(APICatch) {
2953 v8::HandleScope scope;
2954 Local<ObjectTemplate> templ = ObjectTemplate::New();
2955 templ->Set(v8_str("ThrowFromC"),
2956 v8::FunctionTemplate::New(ThrowFromC));
2957 LocalContext context(0, templ);
2958 CompileRun(
2959 "var thrown = false;"
2960 "try {"
2961 " ThrowFromC();"
2962 "} catch (e) {"
2963 " thrown = true;"
2964 "}");
2965 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
2966 CHECK(thrown->BooleanValue());
2967}
2968
2969
2970THREADED_TEST(APIThrowTryCatch) {
2971 v8::HandleScope scope;
2972 Local<ObjectTemplate> templ = ObjectTemplate::New();
2973 templ->Set(v8_str("ThrowFromC"),
2974 v8::FunctionTemplate::New(ThrowFromC));
2975 LocalContext context(0, templ);
2976 v8::TryCatch try_catch;
2977 CompileRun("ThrowFromC();");
2978 CHECK(try_catch.HasCaught());
2979}
2980
2981
2982// Test that a try-finally block doesn't shadow a try-catch block
2983// when setting up an external handler.
2984//
2985// BUG(271): Some of the exception propagation does not work on the
2986// ARM simulator because the simulator separates the C++ stack and the
2987// JS stack. This test therefore fails on the simulator. The test is
2988// not threaded to allow the threading tests to run on the simulator.
2989TEST(TryCatchInTryFinally) {
2990 v8::HandleScope scope;
2991 Local<ObjectTemplate> templ = ObjectTemplate::New();
2992 templ->Set(v8_str("CCatcher"),
2993 v8::FunctionTemplate::New(CCatcher));
2994 LocalContext context(0, templ);
2995 Local<Value> result = CompileRun("try {"
2996 " try {"
2997 " CCatcher('throw 7;');"
2998 " } finally {"
2999 " }"
3000 "} catch (e) {"
3001 "}");
3002 CHECK(result->IsTrue());
3003}
3004
3005
Ben Murdochb8e0da22011-05-16 14:20:40 +01003006static void check_reference_error_message(
3007 v8::Handle<v8::Message> message,
3008 v8::Handle<v8::Value> data) {
3009 const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
3010 CHECK(message->Get()->Equals(v8_str(reference_error)));
3011}
3012
3013
Steve Block1e0659c2011-05-24 12:43:12 +01003014static v8::Handle<Value> Fail(const v8::Arguments& args) {
3015 ApiTestFuzzer::Fuzz();
3016 CHECK(false);
3017 return v8::Undefined();
3018}
3019
3020
3021// Test that overwritten methods are not invoked on uncaught exception
3022// formatting. However, they are invoked when performing normal error
3023// string conversions.
Ben Murdochb8e0da22011-05-16 14:20:40 +01003024TEST(APIThrowMessageOverwrittenToString) {
3025 v8::HandleScope scope;
3026 v8::V8::AddMessageListener(check_reference_error_message);
Steve Block1e0659c2011-05-24 12:43:12 +01003027 Local<ObjectTemplate> templ = ObjectTemplate::New();
3028 templ->Set(v8_str("fail"), v8::FunctionTemplate::New(Fail));
3029 LocalContext context(NULL, templ);
3030 CompileRun("asdf;");
3031 CompileRun("var limit = {};"
3032 "limit.valueOf = fail;"
3033 "Error.stackTraceLimit = limit;");
3034 CompileRun("asdf");
3035 CompileRun("Array.prototype.pop = fail;");
3036 CompileRun("Object.prototype.hasOwnProperty = fail;");
3037 CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
3038 CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
3039 CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
Ben Murdochb8e0da22011-05-16 14:20:40 +01003040 CompileRun("ReferenceError.prototype.toString ="
3041 " function() { return 'Whoops' }");
3042 CompileRun("asdf;");
Steve Block1e0659c2011-05-24 12:43:12 +01003043 CompileRun("ReferenceError.prototype.constructor.name = void 0;");
3044 CompileRun("asdf;");
3045 CompileRun("ReferenceError.prototype.constructor = void 0;");
3046 CompileRun("asdf;");
3047 CompileRun("ReferenceError.prototype.__proto__ = new Object();");
3048 CompileRun("asdf;");
3049 CompileRun("ReferenceError.prototype = new Object();");
3050 CompileRun("asdf;");
Ben Murdochb8e0da22011-05-16 14:20:40 +01003051 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
3052 CHECK(string->Equals(v8_str("Whoops")));
Steve Block1e0659c2011-05-24 12:43:12 +01003053 CompileRun("ReferenceError.prototype.constructor = new Object();"
3054 "ReferenceError.prototype.constructor.name = 1;"
3055 "Number.prototype.toString = function() { return 'Whoops'; };"
3056 "ReferenceError.prototype.toString = Object.prototype.toString;");
3057 CompileRun("asdf;");
Ben Murdochb8e0da22011-05-16 14:20:40 +01003058 v8::V8::RemoveMessageListeners(check_message);
3059}
3060
3061
Steve Blocka7e24c12009-10-30 11:49:00 +00003062static void receive_message(v8::Handle<v8::Message> message,
3063 v8::Handle<v8::Value> data) {
3064 message->Get();
3065 message_received = true;
3066}
3067
3068
3069TEST(APIThrowMessage) {
3070 message_received = false;
3071 v8::HandleScope scope;
3072 v8::V8::AddMessageListener(receive_message);
3073 Local<ObjectTemplate> templ = ObjectTemplate::New();
3074 templ->Set(v8_str("ThrowFromC"),
3075 v8::FunctionTemplate::New(ThrowFromC));
3076 LocalContext context(0, templ);
3077 CompileRun("ThrowFromC();");
3078 CHECK(message_received);
3079 v8::V8::RemoveMessageListeners(check_message);
3080}
3081
3082
3083TEST(APIThrowMessageAndVerboseTryCatch) {
3084 message_received = false;
3085 v8::HandleScope scope;
3086 v8::V8::AddMessageListener(receive_message);
3087 Local<ObjectTemplate> templ = ObjectTemplate::New();
3088 templ->Set(v8_str("ThrowFromC"),
3089 v8::FunctionTemplate::New(ThrowFromC));
3090 LocalContext context(0, templ);
3091 v8::TryCatch try_catch;
3092 try_catch.SetVerbose(true);
3093 Local<Value> result = CompileRun("ThrowFromC();");
3094 CHECK(try_catch.HasCaught());
3095 CHECK(result.IsEmpty());
3096 CHECK(message_received);
3097 v8::V8::RemoveMessageListeners(check_message);
3098}
3099
3100
Ben Murdoch8b112d22011-06-08 16:22:53 +01003101TEST(APIStackOverflowAndVerboseTryCatch) {
3102 message_received = false;
3103 v8::HandleScope scope;
3104 v8::V8::AddMessageListener(receive_message);
3105 LocalContext context;
3106 v8::TryCatch try_catch;
3107 try_catch.SetVerbose(true);
3108 Local<Value> result = CompileRun("function foo() { foo(); } foo();");
3109 CHECK(try_catch.HasCaught());
3110 CHECK(result.IsEmpty());
3111 CHECK(message_received);
3112 v8::V8::RemoveMessageListeners(receive_message);
3113}
3114
3115
Steve Blocka7e24c12009-10-30 11:49:00 +00003116THREADED_TEST(ExternalScriptException) {
3117 v8::HandleScope scope;
3118 Local<ObjectTemplate> templ = ObjectTemplate::New();
3119 templ->Set(v8_str("ThrowFromC"),
3120 v8::FunctionTemplate::New(ThrowFromC));
3121 LocalContext context(0, templ);
3122
3123 v8::TryCatch try_catch;
3124 Local<Script> script
3125 = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
3126 Local<Value> result = script->Run();
3127 CHECK(result.IsEmpty());
3128 CHECK(try_catch.HasCaught());
3129 String::AsciiValue exception_value(try_catch.Exception());
3130 CHECK_EQ("konto", *exception_value);
3131}
3132
3133
3134
3135v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
3136 ApiTestFuzzer::Fuzz();
3137 CHECK_EQ(4, args.Length());
3138 int count = args[0]->Int32Value();
3139 int cInterval = args[2]->Int32Value();
3140 if (count == 0) {
3141 return v8::ThrowException(v8_str("FromC"));
3142 } else {
3143 Local<v8::Object> global = Context::GetCurrent()->Global();
3144 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
3145 v8::Handle<Value> argv[] = { v8_num(count - 1),
3146 args[1],
3147 args[2],
3148 args[3] };
3149 if (count % cInterval == 0) {
3150 v8::TryCatch try_catch;
Steve Block6ded16b2010-05-10 14:33:55 +01003151 Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
Steve Blocka7e24c12009-10-30 11:49:00 +00003152 int expected = args[3]->Int32Value();
3153 if (try_catch.HasCaught()) {
3154 CHECK_EQ(expected, count);
3155 CHECK(result.IsEmpty());
Steve Block44f0eee2011-05-26 01:26:41 +01003156 CHECK(!i::Isolate::Current()->has_scheduled_exception());
Steve Blocka7e24c12009-10-30 11:49:00 +00003157 } else {
3158 CHECK_NE(expected, count);
3159 }
3160 return result;
3161 } else {
Steve Block6ded16b2010-05-10 14:33:55 +01003162 return fun.As<Function>()->Call(global, 4, argv);
Steve Blocka7e24c12009-10-30 11:49:00 +00003163 }
3164 }
3165}
3166
3167
3168v8::Handle<Value> JSCheck(const v8::Arguments& args) {
3169 ApiTestFuzzer::Fuzz();
3170 CHECK_EQ(3, args.Length());
3171 bool equality = args[0]->BooleanValue();
3172 int count = args[1]->Int32Value();
3173 int expected = args[2]->Int32Value();
3174 if (equality) {
3175 CHECK_EQ(count, expected);
3176 } else {
3177 CHECK_NE(count, expected);
3178 }
3179 return v8::Undefined();
3180}
3181
3182
3183THREADED_TEST(EvalInTryFinally) {
3184 v8::HandleScope scope;
3185 LocalContext context;
3186 v8::TryCatch try_catch;
3187 CompileRun("(function() {"
3188 " try {"
3189 " eval('asldkf (*&^&*^');"
3190 " } finally {"
3191 " return;"
3192 " }"
3193 "})()");
3194 CHECK(!try_catch.HasCaught());
3195}
3196
3197
3198// This test works by making a stack of alternating JavaScript and C
3199// activations. These activations set up exception handlers with regular
3200// intervals, one interval for C activations and another for JavaScript
3201// activations. When enough activations have been created an exception is
3202// thrown and we check that the right activation catches the exception and that
3203// no other activations do. The right activation is always the topmost one with
3204// a handler, regardless of whether it is in JavaScript or C.
3205//
3206// The notation used to describe a test case looks like this:
3207//
3208// *JS[4] *C[3] @JS[2] C[1] JS[0]
3209//
3210// Each entry is an activation, either JS or C. The index is the count at that
3211// level. Stars identify activations with exception handlers, the @ identifies
3212// the exception handler that should catch the exception.
3213//
3214// BUG(271): Some of the exception propagation does not work on the
3215// ARM simulator because the simulator separates the C++ stack and the
3216// JS stack. This test therefore fails on the simulator. The test is
3217// not threaded to allow the threading tests to run on the simulator.
3218TEST(ExceptionOrder) {
3219 v8::HandleScope scope;
3220 Local<ObjectTemplate> templ = ObjectTemplate::New();
3221 templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
3222 templ->Set(v8_str("CThrowCountDown"),
3223 v8::FunctionTemplate::New(CThrowCountDown));
3224 LocalContext context(0, templ);
3225 CompileRun(
3226 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
3227 " if (count == 0) throw 'FromJS';"
3228 " if (count % jsInterval == 0) {"
3229 " try {"
3230 " var value = CThrowCountDown(count - 1,"
3231 " jsInterval,"
3232 " cInterval,"
3233 " expected);"
3234 " check(false, count, expected);"
3235 " return value;"
3236 " } catch (e) {"
3237 " check(true, count, expected);"
3238 " }"
3239 " } else {"
3240 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
3241 " }"
3242 "}");
3243 Local<Function> fun =
3244 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
3245
3246 const int argc = 4;
3247 // count jsInterval cInterval expected
3248
3249 // *JS[4] *C[3] @JS[2] C[1] JS[0]
3250 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
3251 fun->Call(fun, argc, a0);
3252
3253 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
3254 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
3255 fun->Call(fun, argc, a1);
3256
3257 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
3258 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
3259 fun->Call(fun, argc, a2);
3260
3261 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
3262 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
3263 fun->Call(fun, argc, a3);
3264
3265 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
3266 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
3267 fun->Call(fun, argc, a4);
3268
3269 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
3270 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
3271 fun->Call(fun, argc, a5);
3272}
3273
3274
3275v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
3276 ApiTestFuzzer::Fuzz();
3277 CHECK_EQ(1, args.Length());
3278 return v8::ThrowException(args[0]);
3279}
3280
3281
3282THREADED_TEST(ThrowValues) {
3283 v8::HandleScope scope;
3284 Local<ObjectTemplate> templ = ObjectTemplate::New();
3285 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
3286 LocalContext context(0, templ);
3287 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
3288 "function Run(obj) {"
3289 " try {"
3290 " Throw(obj);"
3291 " } catch (e) {"
3292 " return e;"
3293 " }"
3294 " return 'no exception';"
3295 "}"
3296 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
3297 CHECK_EQ(5, result->Length());
3298 CHECK(result->Get(v8::Integer::New(0))->IsString());
3299 CHECK(result->Get(v8::Integer::New(1))->IsNumber());
3300 CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
3301 CHECK(result->Get(v8::Integer::New(2))->IsNumber());
3302 CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
3303 CHECK(result->Get(v8::Integer::New(3))->IsNull());
3304 CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
3305}
3306
3307
3308THREADED_TEST(CatchZero) {
3309 v8::HandleScope scope;
3310 LocalContext context;
3311 v8::TryCatch try_catch;
3312 CHECK(!try_catch.HasCaught());
3313 Script::Compile(v8_str("throw 10"))->Run();
3314 CHECK(try_catch.HasCaught());
3315 CHECK_EQ(10, try_catch.Exception()->Int32Value());
3316 try_catch.Reset();
3317 CHECK(!try_catch.HasCaught());
3318 Script::Compile(v8_str("throw 0"))->Run();
3319 CHECK(try_catch.HasCaught());
3320 CHECK_EQ(0, try_catch.Exception()->Int32Value());
3321}
3322
3323
3324THREADED_TEST(CatchExceptionFromWith) {
3325 v8::HandleScope scope;
3326 LocalContext context;
3327 v8::TryCatch try_catch;
3328 CHECK(!try_catch.HasCaught());
3329 Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
3330 CHECK(try_catch.HasCaught());
3331}
3332
3333
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003334THREADED_TEST(TryCatchAndFinallyHidingException) {
3335 v8::HandleScope scope;
3336 LocalContext context;
3337 v8::TryCatch try_catch;
3338 CHECK(!try_catch.HasCaught());
3339 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
3340 CompileRun("f({toString: function() { throw 42; }});");
3341 CHECK(!try_catch.HasCaught());
3342}
3343
3344
3345v8::Handle<v8::Value> WithTryCatch(const v8::Arguments& args) {
3346 v8::TryCatch try_catch;
3347 return v8::Undefined();
3348}
3349
3350
3351THREADED_TEST(TryCatchAndFinally) {
3352 v8::HandleScope scope;
3353 LocalContext context;
3354 context->Global()->Set(
3355 v8_str("native_with_try_catch"),
3356 v8::FunctionTemplate::New(WithTryCatch)->GetFunction());
3357 v8::TryCatch try_catch;
3358 CHECK(!try_catch.HasCaught());
3359 CompileRun(
3360 "try {\n"
3361 " throw new Error('a');\n"
3362 "} finally {\n"
3363 " native_with_try_catch();\n"
3364 "}\n");
3365 CHECK(try_catch.HasCaught());
3366}
3367
3368
Steve Blocka7e24c12009-10-30 11:49:00 +00003369THREADED_TEST(Equality) {
3370 v8::HandleScope scope;
3371 LocalContext context;
3372 // Check that equality works at all before relying on CHECK_EQ
3373 CHECK(v8_str("a")->Equals(v8_str("a")));
3374 CHECK(!v8_str("a")->Equals(v8_str("b")));
3375
3376 CHECK_EQ(v8_str("a"), v8_str("a"));
3377 CHECK_NE(v8_str("a"), v8_str("b"));
3378 CHECK_EQ(v8_num(1), v8_num(1));
3379 CHECK_EQ(v8_num(1.00), v8_num(1));
3380 CHECK_NE(v8_num(1), v8_num(2));
3381
3382 // Assume String is not symbol.
3383 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
3384 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
3385 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
3386 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
3387 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
3388 CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
3389 Local<Value> not_a_number = v8_num(i::OS::nan_value());
3390 CHECK(!not_a_number->StrictEquals(not_a_number));
3391 CHECK(v8::False()->StrictEquals(v8::False()));
3392 CHECK(!v8::False()->StrictEquals(v8::Undefined()));
3393
3394 v8::Handle<v8::Object> obj = v8::Object::New();
3395 v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
3396 CHECK(alias->StrictEquals(obj));
3397 alias.Dispose();
3398}
3399
3400
3401THREADED_TEST(MultiRun) {
3402 v8::HandleScope scope;
3403 LocalContext context;
3404 Local<Script> script = Script::Compile(v8_str("x"));
3405 for (int i = 0; i < 10; i++)
3406 script->Run();
3407}
3408
3409
3410static v8::Handle<Value> GetXValue(Local<String> name,
3411 const AccessorInfo& info) {
3412 ApiTestFuzzer::Fuzz();
3413 CHECK_EQ(info.Data(), v8_str("donut"));
3414 CHECK_EQ(name, v8_str("x"));
3415 return name;
3416}
3417
3418
3419THREADED_TEST(SimplePropertyRead) {
3420 v8::HandleScope scope;
3421 Local<ObjectTemplate> templ = ObjectTemplate::New();
3422 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3423 LocalContext context;
3424 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3425 Local<Script> script = Script::Compile(v8_str("obj.x"));
3426 for (int i = 0; i < 10; i++) {
3427 Local<Value> result = script->Run();
3428 CHECK_EQ(result, v8_str("x"));
3429 }
3430}
3431
Andrei Popescu31002712010-02-23 13:46:05 +00003432THREADED_TEST(DefinePropertyOnAPIAccessor) {
3433 v8::HandleScope scope;
3434 Local<ObjectTemplate> templ = ObjectTemplate::New();
3435 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3436 LocalContext context;
3437 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3438
3439 // Uses getOwnPropertyDescriptor to check the configurable status
3440 Local<Script> script_desc
Leon Clarkef7060e22010-06-03 12:02:55 +01003441 = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
Andrei Popescu31002712010-02-23 13:46:05 +00003442 "obj, 'x');"
3443 "prop.configurable;"));
3444 Local<Value> result = script_desc->Run();
3445 CHECK_EQ(result->BooleanValue(), true);
3446
3447 // Redefine get - but still configurable
3448 Local<Script> script_define
3449 = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
3450 " configurable: true };"
3451 "Object.defineProperty(obj, 'x', desc);"
3452 "obj.x"));
3453 result = script_define->Run();
3454 CHECK_EQ(result, v8_num(42));
3455
3456 // Check that the accessor is still configurable
3457 result = script_desc->Run();
3458 CHECK_EQ(result->BooleanValue(), true);
3459
3460 // Redefine to a non-configurable
3461 script_define
3462 = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
3463 " configurable: false };"
3464 "Object.defineProperty(obj, 'x', desc);"
3465 "obj.x"));
3466 result = script_define->Run();
3467 CHECK_EQ(result, v8_num(43));
3468 result = script_desc->Run();
3469 CHECK_EQ(result->BooleanValue(), false);
3470
3471 // Make sure that it is not possible to redefine again
3472 v8::TryCatch try_catch;
3473 result = script_define->Run();
3474 CHECK(try_catch.HasCaught());
3475 String::AsciiValue exception_value(try_catch.Exception());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003476 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
Andrei Popescu31002712010-02-23 13:46:05 +00003477}
3478
3479THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
3480 v8::HandleScope scope;
3481 Local<ObjectTemplate> templ = ObjectTemplate::New();
3482 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3483 LocalContext context;
3484 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3485
3486 Local<Script> script_desc = Script::Compile(v8_str("var prop ="
3487 "Object.getOwnPropertyDescriptor( "
3488 "obj, 'x');"
3489 "prop.configurable;"));
3490 Local<Value> result = script_desc->Run();
3491 CHECK_EQ(result->BooleanValue(), true);
3492
3493 Local<Script> script_define =
3494 Script::Compile(v8_str("var desc = {get: function(){return 42; },"
3495 " configurable: true };"
3496 "Object.defineProperty(obj, 'x', desc);"
3497 "obj.x"));
3498 result = script_define->Run();
3499 CHECK_EQ(result, v8_num(42));
3500
3501
3502 result = script_desc->Run();
3503 CHECK_EQ(result->BooleanValue(), true);
3504
3505
3506 script_define =
3507 Script::Compile(v8_str("var desc = {get: function(){return 43; },"
3508 " configurable: false };"
3509 "Object.defineProperty(obj, 'x', desc);"
3510 "obj.x"));
3511 result = script_define->Run();
3512 CHECK_EQ(result, v8_num(43));
3513 result = script_desc->Run();
3514
3515 CHECK_EQ(result->BooleanValue(), false);
3516
3517 v8::TryCatch try_catch;
3518 result = script_define->Run();
3519 CHECK(try_catch.HasCaught());
3520 String::AsciiValue exception_value(try_catch.Exception());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003521 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
Andrei Popescu31002712010-02-23 13:46:05 +00003522}
3523
3524
Leon Clarkef7060e22010-06-03 12:02:55 +01003525static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
3526 char const* name) {
3527 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
3528}
Andrei Popescu31002712010-02-23 13:46:05 +00003529
3530
Leon Clarkef7060e22010-06-03 12:02:55 +01003531THREADED_TEST(DefineAPIAccessorOnObject) {
3532 v8::HandleScope scope;
3533 Local<ObjectTemplate> templ = ObjectTemplate::New();
3534 LocalContext context;
3535
3536 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3537 CompileRun("var obj2 = {};");
3538
3539 CHECK(CompileRun("obj1.x")->IsUndefined());
3540 CHECK(CompileRun("obj2.x")->IsUndefined());
3541
3542 CHECK(GetGlobalProperty(&context, "obj1")->
3543 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3544
3545 ExpectString("obj1.x", "x");
3546 CHECK(CompileRun("obj2.x")->IsUndefined());
3547
3548 CHECK(GetGlobalProperty(&context, "obj2")->
3549 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3550
3551 ExpectString("obj1.x", "x");
3552 ExpectString("obj2.x", "x");
3553
3554 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3555 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3556
3557 CompileRun("Object.defineProperty(obj1, 'x',"
3558 "{ get: function() { return 'y'; }, configurable: true })");
3559
3560 ExpectString("obj1.x", "y");
3561 ExpectString("obj2.x", "x");
3562
3563 CompileRun("Object.defineProperty(obj2, 'x',"
3564 "{ get: function() { return 'y'; }, configurable: true })");
3565
3566 ExpectString("obj1.x", "y");
3567 ExpectString("obj2.x", "y");
3568
3569 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3570 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3571
3572 CHECK(GetGlobalProperty(&context, "obj1")->
3573 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3574 CHECK(GetGlobalProperty(&context, "obj2")->
3575 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3576
3577 ExpectString("obj1.x", "x");
3578 ExpectString("obj2.x", "x");
3579
3580 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3581 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3582
3583 // Define getters/setters, but now make them not configurable.
3584 CompileRun("Object.defineProperty(obj1, 'x',"
3585 "{ get: function() { return 'z'; }, configurable: false })");
3586 CompileRun("Object.defineProperty(obj2, 'x',"
3587 "{ get: function() { return 'z'; }, configurable: false })");
3588
3589 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3590 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3591
3592 ExpectString("obj1.x", "z");
3593 ExpectString("obj2.x", "z");
3594
3595 CHECK(!GetGlobalProperty(&context, "obj1")->
3596 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3597 CHECK(!GetGlobalProperty(&context, "obj2")->
3598 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3599
3600 ExpectString("obj1.x", "z");
3601 ExpectString("obj2.x", "z");
3602}
3603
3604
3605THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
3606 v8::HandleScope scope;
3607 Local<ObjectTemplate> templ = ObjectTemplate::New();
3608 LocalContext context;
3609
3610 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3611 CompileRun("var obj2 = {};");
3612
3613 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3614 v8_str("x"),
3615 GetXValue, NULL,
3616 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3617 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3618 v8_str("x"),
3619 GetXValue, NULL,
3620 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3621
3622 ExpectString("obj1.x", "x");
3623 ExpectString("obj2.x", "x");
3624
3625 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3626 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3627
3628 CHECK(!GetGlobalProperty(&context, "obj1")->
3629 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3630 CHECK(!GetGlobalProperty(&context, "obj2")->
3631 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3632
3633 {
3634 v8::TryCatch try_catch;
3635 CompileRun("Object.defineProperty(obj1, 'x',"
3636 "{get: function() { return 'func'; }})");
3637 CHECK(try_catch.HasCaught());
3638 String::AsciiValue exception_value(try_catch.Exception());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003639 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
Leon Clarkef7060e22010-06-03 12:02:55 +01003640 }
3641 {
3642 v8::TryCatch try_catch;
3643 CompileRun("Object.defineProperty(obj2, 'x',"
3644 "{get: function() { return 'func'; }})");
3645 CHECK(try_catch.HasCaught());
3646 String::AsciiValue exception_value(try_catch.Exception());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003647 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
Leon Clarkef7060e22010-06-03 12:02:55 +01003648 }
3649}
3650
3651
3652static v8::Handle<Value> Get239Value(Local<String> name,
3653 const AccessorInfo& info) {
3654 ApiTestFuzzer::Fuzz();
3655 CHECK_EQ(info.Data(), v8_str("donut"));
3656 CHECK_EQ(name, v8_str("239"));
3657 return name;
3658}
3659
3660
3661THREADED_TEST(ElementAPIAccessor) {
3662 v8::HandleScope scope;
3663 Local<ObjectTemplate> templ = ObjectTemplate::New();
3664 LocalContext context;
3665
3666 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3667 CompileRun("var obj2 = {};");
3668
3669 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3670 v8_str("239"),
3671 Get239Value, NULL,
3672 v8_str("donut")));
3673 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3674 v8_str("239"),
3675 Get239Value, NULL,
3676 v8_str("donut")));
3677
3678 ExpectString("obj1[239]", "239");
3679 ExpectString("obj2[239]", "239");
3680 ExpectString("obj1['239']", "239");
3681 ExpectString("obj2['239']", "239");
3682}
3683
Steve Blocka7e24c12009-10-30 11:49:00 +00003684
3685v8::Persistent<Value> xValue;
3686
3687
3688static void SetXValue(Local<String> name,
3689 Local<Value> value,
3690 const AccessorInfo& info) {
3691 CHECK_EQ(value, v8_num(4));
3692 CHECK_EQ(info.Data(), v8_str("donut"));
3693 CHECK_EQ(name, v8_str("x"));
3694 CHECK(xValue.IsEmpty());
3695 xValue = v8::Persistent<Value>::New(value);
3696}
3697
3698
3699THREADED_TEST(SimplePropertyWrite) {
3700 v8::HandleScope scope;
3701 Local<ObjectTemplate> templ = ObjectTemplate::New();
3702 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
3703 LocalContext context;
3704 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3705 Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
3706 for (int i = 0; i < 10; i++) {
3707 CHECK(xValue.IsEmpty());
3708 script->Run();
3709 CHECK_EQ(v8_num(4), xValue);
3710 xValue.Dispose();
3711 xValue = v8::Persistent<Value>();
3712 }
3713}
3714
3715
3716static v8::Handle<Value> XPropertyGetter(Local<String> property,
3717 const AccessorInfo& info) {
3718 ApiTestFuzzer::Fuzz();
3719 CHECK(info.Data()->IsUndefined());
3720 return property;
3721}
3722
3723
3724THREADED_TEST(NamedInterceptorPropertyRead) {
3725 v8::HandleScope scope;
3726 Local<ObjectTemplate> templ = ObjectTemplate::New();
3727 templ->SetNamedPropertyHandler(XPropertyGetter);
3728 LocalContext context;
3729 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3730 Local<Script> script = Script::Compile(v8_str("obj.x"));
3731 for (int i = 0; i < 10; i++) {
3732 Local<Value> result = script->Run();
3733 CHECK_EQ(result, v8_str("x"));
3734 }
3735}
3736
3737
Steve Block6ded16b2010-05-10 14:33:55 +01003738THREADED_TEST(NamedInterceptorDictionaryIC) {
3739 v8::HandleScope scope;
3740 Local<ObjectTemplate> templ = ObjectTemplate::New();
3741 templ->SetNamedPropertyHandler(XPropertyGetter);
3742 LocalContext context;
3743 // Create an object with a named interceptor.
3744 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
3745 Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
3746 for (int i = 0; i < 10; i++) {
3747 Local<Value> result = script->Run();
3748 CHECK_EQ(result, v8_str("x"));
3749 }
3750 // Create a slow case object and a function accessing a property in
3751 // that slow case object (with dictionary probing in generated
3752 // code). Then force object with a named interceptor into slow-case,
3753 // pass it to the function, and check that the interceptor is called
3754 // instead of accessing the local property.
3755 Local<Value> result =
3756 CompileRun("function get_x(o) { return o.x; };"
3757 "var obj = { x : 42, y : 0 };"
3758 "delete obj.y;"
3759 "for (var i = 0; i < 10; i++) get_x(obj);"
3760 "interceptor_obj.x = 42;"
3761 "interceptor_obj.y = 10;"
3762 "delete interceptor_obj.y;"
3763 "get_x(interceptor_obj)");
3764 CHECK_EQ(result, v8_str("x"));
3765}
3766
3767
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003768THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
3769 v8::HandleScope scope;
3770
3771 v8::Persistent<Context> context1 = Context::New();
3772
3773 context1->Enter();
3774 Local<ObjectTemplate> templ = ObjectTemplate::New();
3775 templ->SetNamedPropertyHandler(XPropertyGetter);
3776 // Create an object with a named interceptor.
3777 v8::Local<v8::Object> object = templ->NewInstance();
3778 context1->Global()->Set(v8_str("interceptor_obj"), object);
3779
3780 // Force the object into the slow case.
3781 CompileRun("interceptor_obj.y = 0;"
3782 "delete interceptor_obj.y;");
3783 context1->Exit();
3784
3785 {
3786 // Introduce the object into a different context.
3787 // Repeat named loads to exercise ICs.
3788 LocalContext context2;
3789 context2->Global()->Set(v8_str("interceptor_obj"), object);
3790 Local<Value> result =
3791 CompileRun("function get_x(o) { return o.x; }"
3792 "interceptor_obj.x = 42;"
3793 "for (var i=0; i != 10; i++) {"
3794 " get_x(interceptor_obj);"
3795 "}"
3796 "get_x(interceptor_obj)");
3797 // Check that the interceptor was actually invoked.
3798 CHECK_EQ(result, v8_str("x"));
3799 }
3800
3801 // Return to the original context and force some object to the slow case
3802 // to cause the NormalizedMapCache to verify.
3803 context1->Enter();
3804 CompileRun("var obj = { x : 0 }; delete obj.x;");
3805 context1->Exit();
3806
3807 context1.Dispose();
3808}
3809
3810
Andrei Popescu402d9372010-02-26 13:31:12 +00003811static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
3812 const AccessorInfo& info) {
3813 // Set x on the prototype object and do not handle the get request.
3814 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
Steve Block6ded16b2010-05-10 14:33:55 +01003815 proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
Andrei Popescu402d9372010-02-26 13:31:12 +00003816 return v8::Handle<Value>();
3817}
3818
3819
3820// This is a regression test for http://crbug.com/20104. Map
3821// transitions should not interfere with post interceptor lookup.
3822THREADED_TEST(NamedInterceptorMapTransitionRead) {
3823 v8::HandleScope scope;
3824 Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
3825 Local<v8::ObjectTemplate> instance_template
3826 = function_template->InstanceTemplate();
3827 instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
3828 LocalContext context;
3829 context->Global()->Set(v8_str("F"), function_template->GetFunction());
3830 // Create an instance of F and introduce a map transition for x.
3831 CompileRun("var o = new F(); o.x = 23;");
3832 // Create an instance of F and invoke the getter. The result should be 23.
3833 Local<Value> result = CompileRun("o = new F(); o.x");
3834 CHECK_EQ(result->Int32Value(), 23);
3835}
3836
3837
Steve Blocka7e24c12009-10-30 11:49:00 +00003838static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
3839 const AccessorInfo& info) {
3840 ApiTestFuzzer::Fuzz();
3841 if (index == 37) {
3842 return v8::Handle<Value>(v8_num(625));
3843 }
3844 return v8::Handle<Value>();
3845}
3846
3847
3848static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
3849 Local<Value> value,
3850 const AccessorInfo& info) {
3851 ApiTestFuzzer::Fuzz();
3852 if (index == 39) {
3853 return value;
3854 }
3855 return v8::Handle<Value>();
3856}
3857
3858
3859THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
3860 v8::HandleScope scope;
3861 Local<ObjectTemplate> templ = ObjectTemplate::New();
3862 templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
3863 IndexedPropertySetter);
3864 LocalContext context;
3865 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3866 Local<Script> getter_script = Script::Compile(v8_str(
3867 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
3868 Local<Script> setter_script = Script::Compile(v8_str(
3869 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
3870 "obj[17] = 23;"
3871 "obj.foo;"));
3872 Local<Script> interceptor_setter_script = Script::Compile(v8_str(
3873 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
3874 "obj[39] = 47;"
3875 "obj.foo;")); // This setter should not run, due to the interceptor.
3876 Local<Script> interceptor_getter_script = Script::Compile(v8_str(
3877 "obj[37];"));
3878 Local<Value> result = getter_script->Run();
3879 CHECK_EQ(v8_num(5), result);
3880 result = setter_script->Run();
3881 CHECK_EQ(v8_num(23), result);
3882 result = interceptor_setter_script->Run();
3883 CHECK_EQ(v8_num(23), result);
3884 result = interceptor_getter_script->Run();
3885 CHECK_EQ(v8_num(625), result);
3886}
3887
3888
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003889static v8::Handle<Value> UnboxedDoubleIndexedPropertyGetter(
3890 uint32_t index,
3891 const AccessorInfo& info) {
3892 ApiTestFuzzer::Fuzz();
3893 if (index < 25) {
3894 return v8::Handle<Value>(v8_num(index));
3895 }
3896 return v8::Handle<Value>();
3897}
3898
3899
3900static v8::Handle<Value> UnboxedDoubleIndexedPropertySetter(
3901 uint32_t index,
3902 Local<Value> value,
3903 const AccessorInfo& info) {
3904 ApiTestFuzzer::Fuzz();
3905 if (index < 25) {
3906 return v8::Handle<Value>(v8_num(index));
3907 }
3908 return v8::Handle<Value>();
3909}
3910
3911
3912Handle<v8::Array> UnboxedDoubleIndexedPropertyEnumerator(
3913 const AccessorInfo& info) {
3914 // Force the list of returned keys to be stored in a FastDoubleArray.
3915 Local<Script> indexed_property_names_script = Script::Compile(v8_str(
3916 "keys = new Array(); keys[125000] = 1;"
3917 "for(i = 0; i < 80000; i++) { keys[i] = i; };"
3918 "keys.length = 25; keys;"));
3919 Local<Value> result = indexed_property_names_script->Run();
3920 return Local<v8::Array>(::v8::Array::Cast(*result));
3921}
3922
3923
3924// Make sure that the the interceptor code in the runtime properly handles
3925// merging property name lists for double-array-backed arrays.
3926THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
3927 v8::HandleScope scope;
3928 Local<ObjectTemplate> templ = ObjectTemplate::New();
3929 templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
3930 UnboxedDoubleIndexedPropertySetter,
3931 0,
3932 0,
3933 UnboxedDoubleIndexedPropertyEnumerator);
3934 LocalContext context;
3935 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3936 // When obj is created, force it to be Stored in a FastDoubleArray.
3937 Local<Script> create_unboxed_double_script = Script::Compile(v8_str(
3938 "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
3939 "key_count = 0; "
3940 "for (x in obj) {key_count++;};"
3941 "obj;"));
3942 Local<Value> result = create_unboxed_double_script->Run();
3943 CHECK(result->ToObject()->HasRealIndexedProperty(2000));
3944 Local<Script> key_count_check = Script::Compile(v8_str(
3945 "key_count;"));
3946 result = key_count_check->Run();
3947 CHECK_EQ(v8_num(40013), result);
3948}
3949
3950
3951Handle<v8::Array> NonStrictArgsIndexedPropertyEnumerator(
3952 const AccessorInfo& info) {
3953 // Force the list of returned keys to be stored in a Arguments object.
3954 Local<Script> indexed_property_names_script = Script::Compile(v8_str(
3955 "function f(w,x) {"
3956 " return arguments;"
3957 "}"
3958 "keys = f(0, 1, 2, 3);"
3959 "keys;"));
3960 Local<Value> result = indexed_property_names_script->Run();
3961 return Local<v8::Array>(static_cast<v8::Array*>(::v8::Object::Cast(*result)));
3962}
3963
3964
3965static v8::Handle<Value> NonStrictIndexedPropertyGetter(
3966 uint32_t index,
3967 const AccessorInfo& info) {
3968 ApiTestFuzzer::Fuzz();
3969 if (index < 4) {
3970 return v8::Handle<Value>(v8_num(index));
3971 }
3972 return v8::Handle<Value>();
3973}
3974
3975
3976// Make sure that the the interceptor code in the runtime properly handles
3977// merging property name lists for non-string arguments arrays.
3978THREADED_TEST(IndexedInterceptorNonStrictArgsWithIndexedAccessor) {
3979 v8::HandleScope scope;
3980 Local<ObjectTemplate> templ = ObjectTemplate::New();
3981 templ->SetIndexedPropertyHandler(NonStrictIndexedPropertyGetter,
3982 0,
3983 0,
3984 0,
3985 NonStrictArgsIndexedPropertyEnumerator);
3986 LocalContext context;
3987 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3988 Local<Script> create_args_script =
3989 Script::Compile(v8_str(
3990 "var key_count = 0;"
3991 "for (x in obj) {key_count++;} key_count;"));
3992 Local<Value> result = create_args_script->Run();
3993 CHECK_EQ(v8_num(4), result);
3994}
3995
3996
Leon Clarked91b9f72010-01-27 17:25:45 +00003997static v8::Handle<Value> IdentityIndexedPropertyGetter(
3998 uint32_t index,
3999 const AccessorInfo& info) {
Ben Murdochf87a2032010-10-22 12:50:53 +01004000 return v8::Integer::NewFromUnsigned(index);
Leon Clarked91b9f72010-01-27 17:25:45 +00004001}
4002
4003
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004004THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
4005 v8::HandleScope scope;
4006 Local<ObjectTemplate> templ = ObjectTemplate::New();
4007 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4008
4009 LocalContext context;
4010 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4011
4012 // Check fast object case.
4013 const char* fast_case_code =
4014 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
4015 ExpectString(fast_case_code, "0");
4016
4017 // Check slow case.
4018 const char* slow_case_code =
4019 "obj.x = 1; delete obj.x;"
4020 "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
4021 ExpectString(slow_case_code, "1");
4022}
4023
4024
Leon Clarked91b9f72010-01-27 17:25:45 +00004025THREADED_TEST(IndexedInterceptorWithNoSetter) {
4026 v8::HandleScope scope;
4027 Local<ObjectTemplate> templ = ObjectTemplate::New();
4028 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4029
4030 LocalContext context;
4031 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4032
4033 const char* code =
4034 "try {"
4035 " obj[0] = 239;"
4036 " for (var i = 0; i < 100; i++) {"
4037 " var v = obj[0];"
4038 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
4039 " }"
4040 " 'PASSED'"
4041 "} catch(e) {"
4042 " e"
4043 "}";
4044 ExpectString(code, "PASSED");
4045}
4046
4047
Andrei Popescu402d9372010-02-26 13:31:12 +00004048THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
4049 v8::HandleScope scope;
4050 Local<ObjectTemplate> templ = ObjectTemplate::New();
4051 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4052
4053 LocalContext context;
4054 Local<v8::Object> obj = templ->NewInstance();
4055 obj->TurnOnAccessCheck();
4056 context->Global()->Set(v8_str("obj"), obj);
4057
4058 const char* code =
4059 "try {"
4060 " for (var i = 0; i < 100; i++) {"
4061 " var v = obj[0];"
4062 " if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
4063 " }"
4064 " 'PASSED'"
4065 "} catch(e) {"
4066 " e"
4067 "}";
4068 ExpectString(code, "PASSED");
4069}
4070
4071
4072THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
4073 i::FLAG_allow_natives_syntax = true;
4074 v8::HandleScope scope;
4075 Local<ObjectTemplate> templ = ObjectTemplate::New();
4076 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4077
4078 LocalContext context;
4079 Local<v8::Object> obj = templ->NewInstance();
4080 context->Global()->Set(v8_str("obj"), obj);
4081
4082 const char* code =
4083 "try {"
4084 " for (var i = 0; i < 100; i++) {"
4085 " var expected = i;"
4086 " if (i == 5) {"
4087 " %EnableAccessChecks(obj);"
4088 " expected = undefined;"
4089 " }"
4090 " var v = obj[i];"
4091 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4092 " if (i == 5) %DisableAccessChecks(obj);"
4093 " }"
4094 " 'PASSED'"
4095 "} catch(e) {"
4096 " e"
4097 "}";
4098 ExpectString(code, "PASSED");
4099}
4100
4101
4102THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
4103 v8::HandleScope scope;
4104 Local<ObjectTemplate> templ = ObjectTemplate::New();
4105 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4106
4107 LocalContext context;
4108 Local<v8::Object> obj = templ->NewInstance();
4109 context->Global()->Set(v8_str("obj"), obj);
4110
4111 const char* code =
4112 "try {"
4113 " for (var i = 0; i < 100; i++) {"
4114 " var v = obj[i];"
4115 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
4116 " }"
4117 " 'PASSED'"
4118 "} catch(e) {"
4119 " e"
4120 "}";
4121 ExpectString(code, "PASSED");
4122}
4123
4124
Ben Murdochf87a2032010-10-22 12:50:53 +01004125THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
4126 v8::HandleScope scope;
4127 Local<ObjectTemplate> templ = ObjectTemplate::New();
4128 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4129
4130 LocalContext context;
4131 Local<v8::Object> obj = templ->NewInstance();
4132 context->Global()->Set(v8_str("obj"), obj);
4133
4134 const char* code =
4135 "try {"
4136 " for (var i = 0; i < 100; i++) {"
4137 " var expected = i;"
4138 " var key = i;"
4139 " if (i == 25) {"
4140 " key = -1;"
4141 " expected = undefined;"
4142 " }"
4143 " if (i == 50) {"
4144 " /* probe minimal Smi number on 32-bit platforms */"
4145 " key = -(1 << 30);"
4146 " expected = undefined;"
4147 " }"
4148 " if (i == 75) {"
4149 " /* probe minimal Smi number on 64-bit platforms */"
4150 " key = 1 << 31;"
4151 " expected = undefined;"
4152 " }"
4153 " var v = obj[key];"
4154 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4155 " }"
4156 " 'PASSED'"
4157 "} catch(e) {"
4158 " e"
4159 "}";
4160 ExpectString(code, "PASSED");
4161}
4162
4163
Andrei Popescu402d9372010-02-26 13:31:12 +00004164THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
4165 v8::HandleScope scope;
4166 Local<ObjectTemplate> templ = ObjectTemplate::New();
4167 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4168
4169 LocalContext context;
4170 Local<v8::Object> obj = templ->NewInstance();
4171 context->Global()->Set(v8_str("obj"), obj);
4172
4173 const char* code =
4174 "try {"
4175 " for (var i = 0; i < 100; i++) {"
4176 " var expected = i;"
Ben Murdochf87a2032010-10-22 12:50:53 +01004177 " var key = i;"
Andrei Popescu402d9372010-02-26 13:31:12 +00004178 " if (i == 50) {"
Ben Murdochf87a2032010-10-22 12:50:53 +01004179 " key = 'foobar';"
Andrei Popescu402d9372010-02-26 13:31:12 +00004180 " expected = undefined;"
4181 " }"
Ben Murdochf87a2032010-10-22 12:50:53 +01004182 " var v = obj[key];"
Andrei Popescu402d9372010-02-26 13:31:12 +00004183 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4184 " }"
4185 " 'PASSED'"
4186 "} catch(e) {"
4187 " e"
4188 "}";
4189 ExpectString(code, "PASSED");
4190}
4191
4192
4193THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
4194 v8::HandleScope scope;
4195 Local<ObjectTemplate> templ = ObjectTemplate::New();
4196 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4197
4198 LocalContext context;
4199 Local<v8::Object> obj = templ->NewInstance();
4200 context->Global()->Set(v8_str("obj"), obj);
4201
4202 const char* code =
4203 "var original = obj;"
4204 "try {"
4205 " for (var i = 0; i < 100; i++) {"
4206 " var expected = i;"
4207 " if (i == 50) {"
4208 " obj = {50: 'foobar'};"
4209 " expected = 'foobar';"
4210 " }"
4211 " var v = obj[i];"
4212 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4213 " if (i == 50) obj = original;"
4214 " }"
4215 " 'PASSED'"
4216 "} catch(e) {"
4217 " e"
4218 "}";
4219 ExpectString(code, "PASSED");
4220}
4221
4222
4223THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
4224 v8::HandleScope scope;
4225 Local<ObjectTemplate> templ = ObjectTemplate::New();
4226 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4227
4228 LocalContext context;
4229 Local<v8::Object> obj = templ->NewInstance();
4230 context->Global()->Set(v8_str("obj"), obj);
4231
4232 const char* code =
4233 "var original = obj;"
4234 "try {"
4235 " for (var i = 0; i < 100; i++) {"
4236 " var expected = i;"
4237 " if (i == 5) {"
4238 " obj = 239;"
4239 " expected = undefined;"
4240 " }"
4241 " var v = obj[i];"
4242 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4243 " if (i == 5) obj = original;"
4244 " }"
4245 " 'PASSED'"
4246 "} catch(e) {"
4247 " e"
4248 "}";
4249 ExpectString(code, "PASSED");
4250}
4251
4252
4253THREADED_TEST(IndexedInterceptorOnProto) {
4254 v8::HandleScope scope;
4255 Local<ObjectTemplate> templ = ObjectTemplate::New();
4256 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4257
4258 LocalContext context;
4259 Local<v8::Object> obj = templ->NewInstance();
4260 context->Global()->Set(v8_str("obj"), obj);
4261
4262 const char* code =
4263 "var o = {__proto__: obj};"
4264 "try {"
4265 " for (var i = 0; i < 100; i++) {"
4266 " var v = o[i];"
4267 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
4268 " }"
4269 " 'PASSED'"
4270 "} catch(e) {"
4271 " e"
4272 "}";
4273 ExpectString(code, "PASSED");
4274}
4275
4276
Steve Blocka7e24c12009-10-30 11:49:00 +00004277THREADED_TEST(MultiContexts) {
4278 v8::HandleScope scope;
4279 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
4280 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
4281
4282 Local<String> password = v8_str("Password");
4283
4284 // Create an environment
4285 LocalContext context0(0, templ);
4286 context0->SetSecurityToken(password);
4287 v8::Handle<v8::Object> global0 = context0->Global();
4288 global0->Set(v8_str("custom"), v8_num(1234));
4289 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
4290
4291 // Create an independent environment
4292 LocalContext context1(0, templ);
4293 context1->SetSecurityToken(password);
4294 v8::Handle<v8::Object> global1 = context1->Global();
4295 global1->Set(v8_str("custom"), v8_num(1234));
4296 CHECK_NE(global0, global1);
4297 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
4298 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
4299
4300 // Now create a new context with the old global
4301 LocalContext context2(0, templ, global1);
4302 context2->SetSecurityToken(password);
4303 v8::Handle<v8::Object> global2 = context2->Global();
4304 CHECK_EQ(global1, global2);
4305 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
4306 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
4307}
4308
4309
4310THREADED_TEST(FunctionPrototypeAcrossContexts) {
4311 // Make sure that functions created by cloning boilerplates cannot
4312 // communicate through their __proto__ field.
4313
4314 v8::HandleScope scope;
4315
4316 LocalContext env0;
4317 v8::Handle<v8::Object> global0 =
4318 env0->Global();
4319 v8::Handle<v8::Object> object0 =
Steve Block6ded16b2010-05-10 14:33:55 +01004320 global0->Get(v8_str("Object")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00004321 v8::Handle<v8::Object> tostring0 =
Steve Block6ded16b2010-05-10 14:33:55 +01004322 object0->Get(v8_str("toString")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00004323 v8::Handle<v8::Object> proto0 =
Steve Block6ded16b2010-05-10 14:33:55 +01004324 tostring0->Get(v8_str("__proto__")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00004325 proto0->Set(v8_str("custom"), v8_num(1234));
4326
4327 LocalContext env1;
4328 v8::Handle<v8::Object> global1 =
4329 env1->Global();
4330 v8::Handle<v8::Object> object1 =
Steve Block6ded16b2010-05-10 14:33:55 +01004331 global1->Get(v8_str("Object")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00004332 v8::Handle<v8::Object> tostring1 =
Steve Block6ded16b2010-05-10 14:33:55 +01004333 object1->Get(v8_str("toString")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00004334 v8::Handle<v8::Object> proto1 =
Steve Block6ded16b2010-05-10 14:33:55 +01004335 tostring1->Get(v8_str("__proto__")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00004336 CHECK(!proto1->Has(v8_str("custom")));
4337}
4338
4339
4340THREADED_TEST(Regress892105) {
4341 // Make sure that object and array literals created by cloning
4342 // boilerplates cannot communicate through their __proto__
4343 // field. This is rather difficult to check, but we try to add stuff
4344 // to Object.prototype and Array.prototype and create a new
4345 // environment. This should succeed.
4346
4347 v8::HandleScope scope;
4348
4349 Local<String> source = v8_str("Object.prototype.obj = 1234;"
4350 "Array.prototype.arr = 4567;"
4351 "8901");
4352
4353 LocalContext env0;
4354 Local<Script> script0 = Script::Compile(source);
4355 CHECK_EQ(8901.0, script0->Run()->NumberValue());
4356
4357 LocalContext env1;
4358 Local<Script> script1 = Script::Compile(source);
4359 CHECK_EQ(8901.0, script1->Run()->NumberValue());
4360}
4361
4362
Steve Blocka7e24c12009-10-30 11:49:00 +00004363THREADED_TEST(UndetectableObject) {
4364 v8::HandleScope scope;
4365 LocalContext env;
4366
4367 Local<v8::FunctionTemplate> desc =
4368 v8::FunctionTemplate::New(0, v8::Handle<Value>());
4369 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4370
4371 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4372 env->Global()->Set(v8_str("undetectable"), obj);
4373
4374 ExpectString("undetectable.toString()", "[object Object]");
4375 ExpectString("typeof undetectable", "undefined");
4376 ExpectString("typeof(undetectable)", "undefined");
4377 ExpectBoolean("typeof undetectable == 'undefined'", true);
4378 ExpectBoolean("typeof undetectable == 'object'", false);
4379 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
4380 ExpectBoolean("!undetectable", true);
4381
4382 ExpectObject("true&&undetectable", obj);
4383 ExpectBoolean("false&&undetectable", false);
4384 ExpectBoolean("true||undetectable", true);
4385 ExpectObject("false||undetectable", obj);
4386
4387 ExpectObject("undetectable&&true", obj);
4388 ExpectObject("undetectable&&false", obj);
4389 ExpectBoolean("undetectable||true", true);
4390 ExpectBoolean("undetectable||false", false);
4391
4392 ExpectBoolean("undetectable==null", true);
4393 ExpectBoolean("null==undetectable", true);
4394 ExpectBoolean("undetectable==undefined", true);
4395 ExpectBoolean("undefined==undetectable", true);
4396 ExpectBoolean("undetectable==undetectable", true);
4397
4398
4399 ExpectBoolean("undetectable===null", false);
4400 ExpectBoolean("null===undetectable", false);
4401 ExpectBoolean("undetectable===undefined", false);
4402 ExpectBoolean("undefined===undetectable", false);
4403 ExpectBoolean("undetectable===undetectable", true);
4404}
4405
4406
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004407THREADED_TEST(VoidLiteral) {
4408 v8::HandleScope scope;
4409 LocalContext env;
4410
4411 Local<v8::FunctionTemplate> desc =
4412 v8::FunctionTemplate::New(0, v8::Handle<Value>());
4413 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4414
4415 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4416 env->Global()->Set(v8_str("undetectable"), obj);
4417
4418 ExpectBoolean("undefined == void 0", true);
4419 ExpectBoolean("undetectable == void 0", true);
4420 ExpectBoolean("null == void 0", true);
4421 ExpectBoolean("undefined === void 0", true);
4422 ExpectBoolean("undetectable === void 0", false);
4423 ExpectBoolean("null === void 0", false);
4424
4425 ExpectBoolean("void 0 == undefined", true);
4426 ExpectBoolean("void 0 == undetectable", true);
4427 ExpectBoolean("void 0 == null", true);
4428 ExpectBoolean("void 0 === undefined", true);
4429 ExpectBoolean("void 0 === undetectable", false);
4430 ExpectBoolean("void 0 === null", false);
4431
4432 ExpectString("(function() {"
4433 " try {"
4434 " return x === void 0;"
4435 " } catch(e) {"
4436 " return e.toString();"
4437 " }"
4438 "})()",
4439 "ReferenceError: x is not defined");
4440 ExpectString("(function() {"
4441 " try {"
4442 " return void 0 === x;"
4443 " } catch(e) {"
4444 " return e.toString();"
4445 " }"
4446 "})()",
4447 "ReferenceError: x is not defined");
4448}
4449
Steve Block8defd9f2010-07-08 12:39:36 +01004450
4451THREADED_TEST(ExtensibleOnUndetectable) {
4452 v8::HandleScope scope;
4453 LocalContext env;
4454
4455 Local<v8::FunctionTemplate> desc =
4456 v8::FunctionTemplate::New(0, v8::Handle<Value>());
4457 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4458
4459 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4460 env->Global()->Set(v8_str("undetectable"), obj);
4461
4462 Local<String> source = v8_str("undetectable.x = 42;"
4463 "undetectable.x");
4464
4465 Local<Script> script = Script::Compile(source);
4466
4467 CHECK_EQ(v8::Integer::New(42), script->Run());
4468
4469 ExpectBoolean("Object.isExtensible(undetectable)", true);
4470
4471 source = v8_str("Object.preventExtensions(undetectable);");
4472 script = Script::Compile(source);
4473 script->Run();
4474 ExpectBoolean("Object.isExtensible(undetectable)", false);
4475
4476 source = v8_str("undetectable.y = 2000;");
4477 script = Script::Compile(source);
Ben Murdochc7cc0282012-03-05 14:35:55 +00004478 script->Run();
Steve Block44f0eee2011-05-26 01:26:41 +01004479 ExpectBoolean("undetectable.y == undefined", true);
Steve Block8defd9f2010-07-08 12:39:36 +01004480}
4481
4482
4483
Steve Blocka7e24c12009-10-30 11:49:00 +00004484THREADED_TEST(UndetectableString) {
4485 v8::HandleScope scope;
4486 LocalContext env;
4487
4488 Local<String> obj = String::NewUndetectable("foo");
4489 env->Global()->Set(v8_str("undetectable"), obj);
4490
4491 ExpectString("undetectable", "foo");
4492 ExpectString("typeof undetectable", "undefined");
4493 ExpectString("typeof(undetectable)", "undefined");
4494 ExpectBoolean("typeof undetectable == 'undefined'", true);
4495 ExpectBoolean("typeof undetectable == 'string'", false);
4496 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
4497 ExpectBoolean("!undetectable", true);
4498
4499 ExpectObject("true&&undetectable", obj);
4500 ExpectBoolean("false&&undetectable", false);
4501 ExpectBoolean("true||undetectable", true);
4502 ExpectObject("false||undetectable", obj);
4503
4504 ExpectObject("undetectable&&true", obj);
4505 ExpectObject("undetectable&&false", obj);
4506 ExpectBoolean("undetectable||true", true);
4507 ExpectBoolean("undetectable||false", false);
4508
4509 ExpectBoolean("undetectable==null", true);
4510 ExpectBoolean("null==undetectable", true);
4511 ExpectBoolean("undetectable==undefined", true);
4512 ExpectBoolean("undefined==undetectable", true);
4513 ExpectBoolean("undetectable==undetectable", true);
4514
4515
4516 ExpectBoolean("undetectable===null", false);
4517 ExpectBoolean("null===undetectable", false);
4518 ExpectBoolean("undetectable===undefined", false);
4519 ExpectBoolean("undefined===undetectable", false);
4520 ExpectBoolean("undetectable===undetectable", true);
4521}
4522
4523
Ben Murdoch257744e2011-11-30 15:57:28 +00004524TEST(UndetectableOptimized) {
4525 i::FLAG_allow_natives_syntax = true;
4526 v8::HandleScope scope;
4527 LocalContext env;
4528
4529 Local<String> obj = String::NewUndetectable("foo");
4530 env->Global()->Set(v8_str("undetectable"), obj);
4531 env->Global()->Set(v8_str("detectable"), v8_str("bar"));
4532
4533 ExpectString(
4534 "function testBranch() {"
4535 " if (!%_IsUndetectableObject(undetectable)) throw 1;"
4536 " if (%_IsUndetectableObject(detectable)) throw 2;"
4537 "}\n"
4538 "function testBool() {"
4539 " var b1 = !%_IsUndetectableObject(undetectable);"
4540 " var b2 = %_IsUndetectableObject(detectable);"
4541 " if (b1) throw 3;"
4542 " if (b2) throw 4;"
4543 " return b1 == b2;"
4544 "}\n"
4545 "%OptimizeFunctionOnNextCall(testBranch);"
4546 "%OptimizeFunctionOnNextCall(testBool);"
4547 "for (var i = 0; i < 10; i++) {"
4548 " testBranch();"
4549 " testBool();"
4550 "}\n"
4551 "\"PASS\"",
4552 "PASS");
4553}
4554
4555
Steve Blocka7e24c12009-10-30 11:49:00 +00004556template <typename T> static void USE(T) { }
4557
4558
4559// This test is not intended to be run, just type checked.
Ben Murdoch589d6972011-11-30 16:04:58 +00004560static inline void PersistentHandles() {
Steve Blocka7e24c12009-10-30 11:49:00 +00004561 USE(PersistentHandles);
4562 Local<String> str = v8_str("foo");
4563 v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
4564 USE(p_str);
4565 Local<Script> scr = Script::Compile(v8_str(""));
4566 v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
4567 USE(p_scr);
4568 Local<ObjectTemplate> templ = ObjectTemplate::New();
4569 v8::Persistent<ObjectTemplate> p_templ =
4570 v8::Persistent<ObjectTemplate>::New(templ);
4571 USE(p_templ);
4572}
4573
4574
4575static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
4576 ApiTestFuzzer::Fuzz();
4577 return v8::Undefined();
4578}
4579
4580
4581THREADED_TEST(GlobalObjectTemplate) {
4582 v8::HandleScope handle_scope;
4583 Local<ObjectTemplate> global_template = ObjectTemplate::New();
4584 global_template->Set(v8_str("JSNI_Log"),
4585 v8::FunctionTemplate::New(HandleLogDelegator));
4586 v8::Persistent<Context> context = Context::New(0, global_template);
4587 Context::Scope context_scope(context);
4588 Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
4589 context.Dispose();
4590}
4591
4592
4593static const char* kSimpleExtensionSource =
4594 "function Foo() {"
4595 " return 4;"
4596 "}";
4597
4598
4599THREADED_TEST(SimpleExtensions) {
4600 v8::HandleScope handle_scope;
4601 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
4602 const char* extension_names[] = { "simpletest" };
4603 v8::ExtensionConfiguration extensions(1, extension_names);
4604 v8::Handle<Context> context = Context::New(&extensions);
4605 Context::Scope lock(context);
4606 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
4607 CHECK_EQ(result, v8::Integer::New(4));
4608}
4609
4610
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004611static const char* kEmbeddedExtensionSource =
4612 "function Ret54321(){return 54321;}~~@@$"
4613 "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
4614static const int kEmbeddedExtensionSourceValidLen = 34;
4615
4616
4617THREADED_TEST(ExtensionMissingSourceLength) {
4618 v8::HandleScope handle_scope;
4619 v8::RegisterExtension(new Extension("srclentest_fail",
4620 kEmbeddedExtensionSource));
4621 const char* extension_names[] = { "srclentest_fail" };
4622 v8::ExtensionConfiguration extensions(1, extension_names);
4623 v8::Handle<Context> context = Context::New(&extensions);
4624 CHECK_EQ(0, *context);
4625}
4626
4627
4628THREADED_TEST(ExtensionWithSourceLength) {
4629 for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
4630 source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
4631 v8::HandleScope handle_scope;
4632 i::ScopedVector<char> extension_name(32);
4633 i::OS::SNPrintF(extension_name, "ext #%d", source_len);
4634 v8::RegisterExtension(new Extension(extension_name.start(),
4635 kEmbeddedExtensionSource, 0, 0,
4636 source_len));
4637 const char* extension_names[1] = { extension_name.start() };
4638 v8::ExtensionConfiguration extensions(1, extension_names);
4639 v8::Handle<Context> context = Context::New(&extensions);
4640 if (source_len == kEmbeddedExtensionSourceValidLen) {
4641 Context::Scope lock(context);
4642 v8::Handle<Value> result = Script::Compile(v8_str("Ret54321()"))->Run();
4643 CHECK_EQ(v8::Integer::New(54321), result);
4644 } else {
4645 // Anything but exactly the right length should fail to compile.
4646 CHECK_EQ(0, *context);
4647 }
4648 }
4649}
4650
4651
Steve Blocka7e24c12009-10-30 11:49:00 +00004652static const char* kEvalExtensionSource1 =
4653 "function UseEval1() {"
4654 " var x = 42;"
4655 " return eval('x');"
4656 "}";
4657
4658
4659static const char* kEvalExtensionSource2 =
4660 "(function() {"
4661 " var x = 42;"
4662 " function e() {"
4663 " return eval('x');"
4664 " }"
4665 " this.UseEval2 = e;"
4666 "})()";
4667
4668
4669THREADED_TEST(UseEvalFromExtension) {
4670 v8::HandleScope handle_scope;
4671 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
4672 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
4673 const char* extension_names[] = { "evaltest1", "evaltest2" };
4674 v8::ExtensionConfiguration extensions(2, extension_names);
4675 v8::Handle<Context> context = Context::New(&extensions);
4676 Context::Scope lock(context);
4677 v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
4678 CHECK_EQ(result, v8::Integer::New(42));
4679 result = Script::Compile(v8_str("UseEval2()"))->Run();
4680 CHECK_EQ(result, v8::Integer::New(42));
4681}
4682
4683
4684static const char* kWithExtensionSource1 =
4685 "function UseWith1() {"
4686 " var x = 42;"
4687 " with({x:87}) { return x; }"
4688 "}";
4689
4690
4691
4692static const char* kWithExtensionSource2 =
4693 "(function() {"
4694 " var x = 42;"
4695 " function e() {"
4696 " with ({x:87}) { return x; }"
4697 " }"
4698 " this.UseWith2 = e;"
4699 "})()";
4700
4701
4702THREADED_TEST(UseWithFromExtension) {
4703 v8::HandleScope handle_scope;
4704 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
4705 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
4706 const char* extension_names[] = { "withtest1", "withtest2" };
4707 v8::ExtensionConfiguration extensions(2, extension_names);
4708 v8::Handle<Context> context = Context::New(&extensions);
4709 Context::Scope lock(context);
4710 v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
4711 CHECK_EQ(result, v8::Integer::New(87));
4712 result = Script::Compile(v8_str("UseWith2()"))->Run();
4713 CHECK_EQ(result, v8::Integer::New(87));
4714}
4715
4716
4717THREADED_TEST(AutoExtensions) {
4718 v8::HandleScope handle_scope;
4719 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
4720 extension->set_auto_enable(true);
4721 v8::RegisterExtension(extension);
4722 v8::Handle<Context> context = Context::New();
4723 Context::Scope lock(context);
4724 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
4725 CHECK_EQ(result, v8::Integer::New(4));
4726}
4727
4728
Steve Blockd0582a62009-12-15 09:54:21 +00004729static const char* kSyntaxErrorInExtensionSource =
4730 "[";
4731
4732
4733// Test that a syntax error in an extension does not cause a fatal
4734// error but results in an empty context.
4735THREADED_TEST(SyntaxErrorExtensions) {
4736 v8::HandleScope handle_scope;
4737 v8::RegisterExtension(new Extension("syntaxerror",
4738 kSyntaxErrorInExtensionSource));
4739 const char* extension_names[] = { "syntaxerror" };
4740 v8::ExtensionConfiguration extensions(1, extension_names);
4741 v8::Handle<Context> context = Context::New(&extensions);
4742 CHECK(context.IsEmpty());
4743}
4744
4745
4746static const char* kExceptionInExtensionSource =
4747 "throw 42";
4748
4749
4750// Test that an exception when installing an extension does not cause
4751// a fatal error but results in an empty context.
4752THREADED_TEST(ExceptionExtensions) {
4753 v8::HandleScope handle_scope;
4754 v8::RegisterExtension(new Extension("exception",
4755 kExceptionInExtensionSource));
4756 const char* extension_names[] = { "exception" };
4757 v8::ExtensionConfiguration extensions(1, extension_names);
4758 v8::Handle<Context> context = Context::New(&extensions);
4759 CHECK(context.IsEmpty());
4760}
4761
4762
Iain Merrick9ac36c92010-09-13 15:29:50 +01004763static const char* kNativeCallInExtensionSource =
4764 "function call_runtime_last_index_of(x) {"
4765 " return %StringLastIndexOf(x, 'bob', 10);"
4766 "}";
4767
4768
4769static const char* kNativeCallTest =
4770 "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
4771
4772// Test that a native runtime calls are supported in extensions.
4773THREADED_TEST(NativeCallInExtensions) {
4774 v8::HandleScope handle_scope;
4775 v8::RegisterExtension(new Extension("nativecall",
4776 kNativeCallInExtensionSource));
4777 const char* extension_names[] = { "nativecall" };
4778 v8::ExtensionConfiguration extensions(1, extension_names);
4779 v8::Handle<Context> context = Context::New(&extensions);
4780 Context::Scope lock(context);
4781 v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run();
4782 CHECK_EQ(result, v8::Integer::New(3));
4783}
4784
4785
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004786class NativeFunctionExtension : public Extension {
4787 public:
4788 NativeFunctionExtension(const char* name,
4789 const char* source,
4790 v8::InvocationCallback fun = &Echo)
4791 : Extension(name, source),
4792 function_(fun) { }
4793
4794 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
4795 v8::Handle<v8::String> name) {
4796 return v8::FunctionTemplate::New(function_);
4797 }
4798
4799 static v8::Handle<v8::Value> Echo(const v8::Arguments& args) {
4800 if (args.Length() >= 1) return (args[0]);
4801 return v8::Undefined();
4802 }
4803 private:
4804 v8::InvocationCallback function_;
4805};
4806
4807
4808THREADED_TEST(NativeFunctionDeclaration) {
4809 v8::HandleScope handle_scope;
4810 const char* name = "nativedecl";
4811 v8::RegisterExtension(new NativeFunctionExtension(name,
4812 "native function foo();"));
4813 const char* extension_names[] = { name };
4814 v8::ExtensionConfiguration extensions(1, extension_names);
4815 v8::Handle<Context> context = Context::New(&extensions);
4816 Context::Scope lock(context);
4817 v8::Handle<Value> result = Script::Compile(v8_str("foo(42);"))->Run();
4818 CHECK_EQ(result, v8::Integer::New(42));
4819}
4820
4821
4822THREADED_TEST(NativeFunctionDeclarationError) {
4823 v8::HandleScope handle_scope;
4824 const char* name = "nativedeclerr";
4825 // Syntax error in extension code.
4826 v8::RegisterExtension(new NativeFunctionExtension(name,
4827 "native\nfunction foo();"));
4828 const char* extension_names[] = { name };
4829 v8::ExtensionConfiguration extensions(1, extension_names);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004830 v8::Handle<Context> context(Context::New(&extensions));
Ben Murdochc7cc0282012-03-05 14:35:55 +00004831 CHECK(context.IsEmpty());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004832}
4833
Ben Murdochc7cc0282012-03-05 14:35:55 +00004834
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004835THREADED_TEST(NativeFunctionDeclarationErrorEscape) {
4836 v8::HandleScope handle_scope;
4837 const char* name = "nativedeclerresc";
4838 // Syntax error in extension code - escape code in "native" means that
4839 // it's not treated as a keyword.
4840 v8::RegisterExtension(new NativeFunctionExtension(
4841 name,
4842 "nativ\\u0065 function foo();"));
4843 const char* extension_names[] = { name };
4844 v8::ExtensionConfiguration extensions(1, extension_names);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004845 v8::Handle<Context> context(Context::New(&extensions));
Ben Murdochc7cc0282012-03-05 14:35:55 +00004846 CHECK(context.IsEmpty());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004847}
4848
4849
Steve Blocka7e24c12009-10-30 11:49:00 +00004850static void CheckDependencies(const char* name, const char* expected) {
4851 v8::HandleScope handle_scope;
4852 v8::ExtensionConfiguration config(1, &name);
4853 LocalContext context(&config);
4854 CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
4855}
4856
4857
4858/*
4859 * Configuration:
4860 *
4861 * /-- B <--\
4862 * A <- -- D <-- E
4863 * \-- C <--/
4864 */
4865THREADED_TEST(ExtensionDependency) {
4866 static const char* kEDeps[] = { "D" };
4867 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
4868 static const char* kDDeps[] = { "B", "C" };
4869 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
4870 static const char* kBCDeps[] = { "A" };
4871 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
4872 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
4873 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
4874 CheckDependencies("A", "undefinedA");
4875 CheckDependencies("B", "undefinedAB");
4876 CheckDependencies("C", "undefinedAC");
4877 CheckDependencies("D", "undefinedABCD");
4878 CheckDependencies("E", "undefinedABCDE");
4879 v8::HandleScope handle_scope;
4880 static const char* exts[2] = { "C", "E" };
4881 v8::ExtensionConfiguration config(2, exts);
4882 LocalContext context(&config);
4883 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
4884}
4885
4886
4887static const char* kExtensionTestScript =
4888 "native function A();"
4889 "native function B();"
4890 "native function C();"
4891 "function Foo(i) {"
4892 " if (i == 0) return A();"
4893 " if (i == 1) return B();"
4894 " if (i == 2) return C();"
4895 "}";
4896
4897
4898static v8::Handle<Value> CallFun(const v8::Arguments& args) {
4899 ApiTestFuzzer::Fuzz();
Leon Clarkee46be812010-01-19 14:06:41 +00004900 if (args.IsConstructCall()) {
4901 args.This()->Set(v8_str("data"), args.Data());
4902 return v8::Null();
4903 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004904 return args.Data();
4905}
4906
4907
4908class FunctionExtension : public Extension {
4909 public:
4910 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
4911 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
4912 v8::Handle<String> name);
4913};
4914
4915
4916static int lookup_count = 0;
4917v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
4918 v8::Handle<String> name) {
4919 lookup_count++;
4920 if (name->Equals(v8_str("A"))) {
4921 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
4922 } else if (name->Equals(v8_str("B"))) {
4923 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
4924 } else if (name->Equals(v8_str("C"))) {
4925 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
4926 } else {
4927 return v8::Handle<v8::FunctionTemplate>();
4928 }
4929}
4930
4931
4932THREADED_TEST(FunctionLookup) {
4933 v8::RegisterExtension(new FunctionExtension());
4934 v8::HandleScope handle_scope;
4935 static const char* exts[1] = { "functiontest" };
4936 v8::ExtensionConfiguration config(1, exts);
4937 LocalContext context(&config);
4938 CHECK_EQ(3, lookup_count);
4939 CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
4940 CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
4941 CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
4942}
4943
4944
Leon Clarkee46be812010-01-19 14:06:41 +00004945THREADED_TEST(NativeFunctionConstructCall) {
4946 v8::RegisterExtension(new FunctionExtension());
4947 v8::HandleScope handle_scope;
4948 static const char* exts[1] = { "functiontest" };
4949 v8::ExtensionConfiguration config(1, exts);
4950 LocalContext context(&config);
Leon Clarked91b9f72010-01-27 17:25:45 +00004951 for (int i = 0; i < 10; i++) {
4952 // Run a few times to ensure that allocation of objects doesn't
4953 // change behavior of a constructor function.
4954 CHECK_EQ(v8::Integer::New(8),
4955 Script::Compile(v8_str("(new A()).data"))->Run());
4956 CHECK_EQ(v8::Integer::New(7),
4957 Script::Compile(v8_str("(new B()).data"))->Run());
4958 CHECK_EQ(v8::Integer::New(6),
4959 Script::Compile(v8_str("(new C()).data"))->Run());
4960 }
Leon Clarkee46be812010-01-19 14:06:41 +00004961}
4962
4963
Steve Blocka7e24c12009-10-30 11:49:00 +00004964static const char* last_location;
4965static const char* last_message;
4966void StoringErrorCallback(const char* location, const char* message) {
4967 if (last_location == NULL) {
4968 last_location = location;
4969 last_message = message;
4970 }
4971}
4972
4973
4974// ErrorReporting creates a circular extensions configuration and
4975// tests that the fatal error handler gets called. This renders V8
4976// unusable and therefore this test cannot be run in parallel.
4977TEST(ErrorReporting) {
4978 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
4979 static const char* aDeps[] = { "B" };
4980 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
4981 static const char* bDeps[] = { "A" };
4982 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
4983 last_location = NULL;
4984 v8::ExtensionConfiguration config(1, bDeps);
4985 v8::Handle<Context> context = Context::New(&config);
4986 CHECK(context.IsEmpty());
4987 CHECK_NE(last_location, NULL);
4988}
4989
4990
4991static const char* js_code_causing_huge_string_flattening =
4992 "var str = 'X';"
4993 "for (var i = 0; i < 30; i++) {"
4994 " str = str + str;"
4995 "}"
4996 "str.match(/X/);";
4997
4998
4999void OOMCallback(const char* location, const char* message) {
5000 exit(0);
5001}
5002
5003
5004TEST(RegexpOutOfMemory) {
5005 // Execute a script that causes out of memory when flattening a string.
5006 v8::HandleScope scope;
5007 v8::V8::SetFatalErrorHandler(OOMCallback);
5008 LocalContext context;
5009 Local<Script> script =
5010 Script::Compile(String::New(js_code_causing_huge_string_flattening));
5011 last_location = NULL;
Ben Murdochc7cc0282012-03-05 14:35:55 +00005012 script->Run();
Steve Blocka7e24c12009-10-30 11:49:00 +00005013
5014 CHECK(false); // Should not return.
5015}
5016
5017
5018static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
5019 v8::Handle<Value> data) {
5020 CHECK_EQ(v8::Undefined(), data);
5021 CHECK(message->GetScriptResourceName()->IsUndefined());
5022 CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
5023 message->GetLineNumber();
5024 message->GetSourceLine();
5025}
5026
5027
5028THREADED_TEST(ErrorWithMissingScriptInfo) {
5029 v8::HandleScope scope;
5030 LocalContext context;
5031 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
5032 Script::Compile(v8_str("throw Error()"))->Run();
5033 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
5034}
5035
5036
5037int global_index = 0;
5038
5039class Snorkel {
5040 public:
5041 Snorkel() { index_ = global_index++; }
5042 int index_;
5043};
5044
5045class Whammy {
5046 public:
5047 Whammy() {
5048 cursor_ = 0;
5049 }
5050 ~Whammy() {
5051 script_.Dispose();
5052 }
5053 v8::Handle<Script> getScript() {
5054 if (script_.IsEmpty())
5055 script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
5056 return Local<Script>(*script_);
5057 }
5058
5059 public:
5060 static const int kObjectCount = 256;
5061 int cursor_;
5062 v8::Persistent<v8::Object> objects_[kObjectCount];
5063 v8::Persistent<Script> script_;
5064};
5065
5066static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
5067 Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
5068 delete snorkel;
5069 obj.ClearWeak();
5070}
5071
5072v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
5073 const AccessorInfo& info) {
5074 Whammy* whammy =
5075 static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
5076
5077 v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
5078
5079 v8::Handle<v8::Object> obj = v8::Object::New();
5080 v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
5081 if (!prev.IsEmpty()) {
5082 prev->Set(v8_str("next"), obj);
5083 prev.MakeWeak(new Snorkel(), &HandleWeakReference);
5084 whammy->objects_[whammy->cursor_].Clear();
5085 }
5086 whammy->objects_[whammy->cursor_] = global;
5087 whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
5088 return whammy->getScript()->Run();
5089}
5090
5091THREADED_TEST(WeakReference) {
5092 v8::HandleScope handle_scope;
5093 v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
Ben Murdoch3bec4d22010-07-22 14:51:16 +01005094 Whammy* whammy = new Whammy();
Steve Blocka7e24c12009-10-30 11:49:00 +00005095 templ->SetNamedPropertyHandler(WhammyPropertyGetter,
5096 0, 0, 0, 0,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01005097 v8::External::New(whammy));
Steve Blocka7e24c12009-10-30 11:49:00 +00005098 const char* extension_list[] = { "v8/gc" };
5099 v8::ExtensionConfiguration extensions(1, extension_list);
5100 v8::Persistent<Context> context = Context::New(&extensions);
5101 Context::Scope context_scope(context);
5102
5103 v8::Handle<v8::Object> interceptor = templ->NewInstance();
5104 context->Global()->Set(v8_str("whammy"), interceptor);
5105 const char* code =
5106 "var last;"
5107 "for (var i = 0; i < 10000; i++) {"
5108 " var obj = whammy.length;"
5109 " if (last) last.next = obj;"
5110 " last = obj;"
5111 "}"
5112 "gc();"
5113 "4";
5114 v8::Handle<Value> result = CompileRun(code);
5115 CHECK_EQ(4.0, result->NumberValue());
Ben Murdoch3bec4d22010-07-22 14:51:16 +01005116 delete whammy;
Steve Blocka7e24c12009-10-30 11:49:00 +00005117 context.Dispose();
5118}
5119
5120
Ben Murdoch257744e2011-11-30 15:57:28 +00005121static void DisposeAndSetFlag(v8::Persistent<v8::Value> obj, void* data) {
Steve Blockd0582a62009-12-15 09:54:21 +00005122 obj.Dispose();
5123 obj.Clear();
Steve Blockd0582a62009-12-15 09:54:21 +00005124 *(reinterpret_cast<bool*>(data)) = true;
5125}
5126
Steve Blockd0582a62009-12-15 09:54:21 +00005127
Ben Murdoch257744e2011-11-30 15:57:28 +00005128THREADED_TEST(IndependentWeakHandle) {
Steve Blockd0582a62009-12-15 09:54:21 +00005129 v8::Persistent<Context> context = Context::New();
5130 Context::Scope context_scope(context);
5131
5132 v8::Persistent<v8::Object> object_a;
Steve Blockd0582a62009-12-15 09:54:21 +00005133
5134 {
5135 v8::HandleScope handle_scope;
Steve Blockd0582a62009-12-15 09:54:21 +00005136 object_a = v8::Persistent<v8::Object>::New(v8::Object::New());
5137 }
5138
5139 bool object_a_disposed = false;
Ben Murdoch257744e2011-11-30 15:57:28 +00005140 object_a.MakeWeak(&object_a_disposed, &DisposeAndSetFlag);
5141 object_a.MarkIndependent();
5142 HEAP->PerformScavenge();
5143 CHECK(object_a_disposed);
5144}
Steve Blockd0582a62009-12-15 09:54:21 +00005145
Ben Murdoch257744e2011-11-30 15:57:28 +00005146
5147static void InvokeScavenge() {
5148 HEAP->PerformScavenge();
5149}
5150
5151
5152static void InvokeMarkSweep() {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005153 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Ben Murdoch257744e2011-11-30 15:57:28 +00005154}
5155
5156
5157static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
5158 obj.Dispose();
5159 obj.Clear();
5160 *(reinterpret_cast<bool*>(data)) = true;
5161 InvokeScavenge();
5162}
5163
5164
5165static void ForceMarkSweep(v8::Persistent<v8::Value> obj, void* data) {
5166 obj.Dispose();
5167 obj.Clear();
5168 *(reinterpret_cast<bool*>(data)) = true;
5169 InvokeMarkSweep();
5170}
5171
5172
5173THREADED_TEST(GCFromWeakCallbacks) {
5174 v8::Persistent<Context> context = Context::New();
5175 Context::Scope context_scope(context);
5176
5177 static const int kNumberOfGCTypes = 2;
5178 v8::WeakReferenceCallback gc_forcing_callback[kNumberOfGCTypes] =
5179 {&ForceScavenge, &ForceMarkSweep};
5180
5181 typedef void (*GCInvoker)();
5182 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
5183
5184 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
5185 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
5186 v8::Persistent<v8::Object> object;
5187 {
5188 v8::HandleScope handle_scope;
5189 object = v8::Persistent<v8::Object>::New(v8::Object::New());
5190 }
5191 bool disposed = false;
5192 object.MakeWeak(&disposed, gc_forcing_callback[inner_gc]);
5193 object.MarkIndependent();
5194 invoke_gc[outer_gc]();
5195 CHECK(disposed);
5196 }
Steve Blockd0582a62009-12-15 09:54:21 +00005197 }
Ben Murdoch257744e2011-11-30 15:57:28 +00005198}
5199
5200
5201static void RevivingCallback(v8::Persistent<v8::Value> obj, void* data) {
5202 obj.ClearWeak();
5203 *(reinterpret_cast<bool*>(data)) = true;
5204}
5205
5206
5207THREADED_TEST(IndependentHandleRevival) {
5208 v8::Persistent<Context> context = Context::New();
5209 Context::Scope context_scope(context);
5210
5211 v8::Persistent<v8::Object> object;
5212 {
5213 v8::HandleScope handle_scope;
5214 object = v8::Persistent<v8::Object>::New(v8::Object::New());
5215 object->Set(v8_str("x"), v8::Integer::New(1));
5216 v8::Local<String> y_str = v8_str("y");
5217 object->Set(y_str, y_str);
5218 }
5219 bool revived = false;
5220 object.MakeWeak(&revived, &RevivingCallback);
5221 object.MarkIndependent();
5222 HEAP->PerformScavenge();
5223 CHECK(revived);
5224 HEAP->CollectAllGarbage(true);
5225 {
5226 v8::HandleScope handle_scope;
5227 v8::Local<String> y_str = v8_str("y");
5228 CHECK_EQ(v8::Integer::New(1), object->Get(v8_str("x")));
5229 CHECK(object->Get(y_str)->Equals(y_str));
5230 }
Steve Blockd0582a62009-12-15 09:54:21 +00005231}
5232
5233
Steve Blocka7e24c12009-10-30 11:49:00 +00005234v8::Handle<Function> args_fun;
5235
5236
5237static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
5238 ApiTestFuzzer::Fuzz();
5239 CHECK_EQ(args_fun, args.Callee());
5240 CHECK_EQ(3, args.Length());
5241 CHECK_EQ(v8::Integer::New(1), args[0]);
5242 CHECK_EQ(v8::Integer::New(2), args[1]);
5243 CHECK_EQ(v8::Integer::New(3), args[2]);
5244 CHECK_EQ(v8::Undefined(), args[3]);
5245 v8::HandleScope scope;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005246 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +00005247 return v8::Undefined();
5248}
5249
5250
5251THREADED_TEST(Arguments) {
5252 v8::HandleScope scope;
5253 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
5254 global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
5255 LocalContext context(NULL, global);
Steve Block6ded16b2010-05-10 14:33:55 +01005256 args_fun = context->Global()->Get(v8_str("f")).As<Function>();
Steve Blocka7e24c12009-10-30 11:49:00 +00005257 v8_compile("f(1, 2, 3)")->Run();
5258}
5259
5260
Steve Blocka7e24c12009-10-30 11:49:00 +00005261static v8::Handle<Value> NoBlockGetterX(Local<String> name,
5262 const AccessorInfo&) {
5263 return v8::Handle<Value>();
5264}
5265
5266
5267static v8::Handle<Value> NoBlockGetterI(uint32_t index,
5268 const AccessorInfo&) {
5269 return v8::Handle<Value>();
5270}
5271
5272
5273static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
5274 const AccessorInfo&) {
5275 if (!name->Equals(v8_str("foo"))) {
5276 return v8::Handle<v8::Boolean>(); // not intercepted
5277 }
5278
5279 return v8::False(); // intercepted, and don't delete the property
5280}
5281
5282
5283static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
5284 if (index != 2) {
5285 return v8::Handle<v8::Boolean>(); // not intercepted
5286 }
5287
5288 return v8::False(); // intercepted, and don't delete the property
5289}
5290
5291
5292THREADED_TEST(Deleter) {
5293 v8::HandleScope scope;
5294 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5295 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
5296 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
5297 LocalContext context;
5298 context->Global()->Set(v8_str("k"), obj->NewInstance());
5299 CompileRun(
5300 "k.foo = 'foo';"
5301 "k.bar = 'bar';"
5302 "k[2] = 2;"
5303 "k[4] = 4;");
5304 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
5305 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
5306
5307 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
5308 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
5309
5310 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
5311 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
5312
5313 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
5314 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
5315}
5316
5317
5318static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
5319 ApiTestFuzzer::Fuzz();
5320 if (name->Equals(v8_str("foo")) ||
5321 name->Equals(v8_str("bar")) ||
5322 name->Equals(v8_str("baz"))) {
5323 return v8::Undefined();
5324 }
5325 return v8::Handle<Value>();
5326}
5327
5328
5329static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
5330 ApiTestFuzzer::Fuzz();
5331 if (index == 0 || index == 1) return v8::Undefined();
5332 return v8::Handle<Value>();
5333}
5334
5335
5336static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
5337 ApiTestFuzzer::Fuzz();
5338 v8::Handle<v8::Array> result = v8::Array::New(3);
5339 result->Set(v8::Integer::New(0), v8_str("foo"));
5340 result->Set(v8::Integer::New(1), v8_str("bar"));
5341 result->Set(v8::Integer::New(2), v8_str("baz"));
5342 return result;
5343}
5344
5345
5346static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
5347 ApiTestFuzzer::Fuzz();
5348 v8::Handle<v8::Array> result = v8::Array::New(2);
5349 result->Set(v8::Integer::New(0), v8_str("0"));
5350 result->Set(v8::Integer::New(1), v8_str("1"));
5351 return result;
5352}
5353
5354
5355THREADED_TEST(Enumerators) {
5356 v8::HandleScope scope;
5357 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5358 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
5359 obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
5360 LocalContext context;
5361 context->Global()->Set(v8_str("k"), obj->NewInstance());
5362 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
5363 "k[10] = 0;"
5364 "k.a = 0;"
5365 "k[5] = 0;"
5366 "k.b = 0;"
5367 "k[4294967295] = 0;"
5368 "k.c = 0;"
5369 "k[4294967296] = 0;"
5370 "k.d = 0;"
5371 "k[140000] = 0;"
5372 "k.e = 0;"
5373 "k[30000000000] = 0;"
5374 "k.f = 0;"
5375 "var result = [];"
5376 "for (var prop in k) {"
5377 " result.push(prop);"
5378 "}"
5379 "result"));
5380 // Check that we get all the property names returned including the
5381 // ones from the enumerators in the right order: indexed properties
5382 // in numerical order, indexed interceptor properties, named
5383 // properties in insertion order, named interceptor properties.
5384 // This order is not mandated by the spec, so this test is just
5385 // documenting our behavior.
5386 CHECK_EQ(17, result->Length());
5387 // Indexed properties in numerical order.
5388 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
5389 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
5390 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
5391 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
5392 // Indexed interceptor properties in the order they are returned
5393 // from the enumerator interceptor.
5394 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
5395 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
5396 // Named properties in insertion order.
5397 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
5398 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
5399 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
5400 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
5401 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
5402 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
5403 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
5404 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
5405 // Named interceptor properties.
5406 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
5407 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
5408 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
5409}
5410
5411
5412int p_getter_count;
5413int p_getter_count2;
5414
5415
5416static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
5417 ApiTestFuzzer::Fuzz();
5418 p_getter_count++;
5419 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5420 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
5421 if (name->Equals(v8_str("p1"))) {
5422 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
5423 } else if (name->Equals(v8_str("p2"))) {
5424 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
5425 } else if (name->Equals(v8_str("p3"))) {
5426 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
5427 } else if (name->Equals(v8_str("p4"))) {
5428 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
5429 }
5430 return v8::Undefined();
5431}
5432
5433
5434static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
5435 ApiTestFuzzer::Fuzz();
5436 LocalContext context;
5437 context->Global()->Set(v8_str("o1"), obj->NewInstance());
5438 CompileRun(
5439 "o1.__proto__ = { };"
5440 "var o2 = { __proto__: o1 };"
5441 "var o3 = { __proto__: o2 };"
5442 "var o4 = { __proto__: o3 };"
5443 "for (var i = 0; i < 10; i++) o4.p4;"
5444 "for (var i = 0; i < 10; i++) o3.p3;"
5445 "for (var i = 0; i < 10; i++) o2.p2;"
5446 "for (var i = 0; i < 10; i++) o1.p1;");
5447}
5448
5449
5450static v8::Handle<Value> PGetter2(Local<String> name,
5451 const AccessorInfo& info) {
5452 ApiTestFuzzer::Fuzz();
5453 p_getter_count2++;
5454 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5455 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
5456 if (name->Equals(v8_str("p1"))) {
5457 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
5458 } else if (name->Equals(v8_str("p2"))) {
5459 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
5460 } else if (name->Equals(v8_str("p3"))) {
5461 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
5462 } else if (name->Equals(v8_str("p4"))) {
5463 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
5464 }
5465 return v8::Undefined();
5466}
5467
5468
5469THREADED_TEST(GetterHolders) {
5470 v8::HandleScope scope;
5471 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5472 obj->SetAccessor(v8_str("p1"), PGetter);
5473 obj->SetAccessor(v8_str("p2"), PGetter);
5474 obj->SetAccessor(v8_str("p3"), PGetter);
5475 obj->SetAccessor(v8_str("p4"), PGetter);
5476 p_getter_count = 0;
5477 RunHolderTest(obj);
5478 CHECK_EQ(40, p_getter_count);
5479}
5480
5481
5482THREADED_TEST(PreInterceptorHolders) {
5483 v8::HandleScope scope;
5484 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5485 obj->SetNamedPropertyHandler(PGetter2);
5486 p_getter_count2 = 0;
5487 RunHolderTest(obj);
5488 CHECK_EQ(40, p_getter_count2);
5489}
5490
5491
5492THREADED_TEST(ObjectInstantiation) {
5493 v8::HandleScope scope;
5494 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5495 templ->SetAccessor(v8_str("t"), PGetter2);
5496 LocalContext context;
5497 context->Global()->Set(v8_str("o"), templ->NewInstance());
5498 for (int i = 0; i < 100; i++) {
5499 v8::HandleScope inner_scope;
5500 v8::Handle<v8::Object> obj = templ->NewInstance();
5501 CHECK_NE(obj, context->Global()->Get(v8_str("o")));
5502 context->Global()->Set(v8_str("o2"), obj);
5503 v8::Handle<Value> value =
5504 Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
5505 CHECK_EQ(v8::True(), value);
5506 context->Global()->Set(v8_str("o"), obj);
5507 }
5508}
5509
5510
Ben Murdochb0fe1622011-05-05 13:52:32 +01005511static int StrCmp16(uint16_t* a, uint16_t* b) {
5512 while (true) {
5513 if (*a == 0 && *b == 0) return 0;
5514 if (*a != *b) return 0 + *a - *b;
5515 a++;
5516 b++;
5517 }
5518}
5519
5520
5521static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
5522 while (true) {
5523 if (n-- == 0) return 0;
5524 if (*a == 0 && *b == 0) return 0;
5525 if (*a != *b) return 0 + *a - *b;
5526 a++;
5527 b++;
5528 }
5529}
5530
5531
Steve Blocka7e24c12009-10-30 11:49:00 +00005532THREADED_TEST(StringWrite) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005533 LocalContext context;
Steve Blocka7e24c12009-10-30 11:49:00 +00005534 v8::HandleScope scope;
5535 v8::Handle<String> str = v8_str("abcde");
Ben Murdochb0fe1622011-05-05 13:52:32 +01005536 // abc<Icelandic eth><Unicode snowman>.
5537 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005538 const int kStride = 4; // Must match stride in for loops in JS below.
5539 CompileRun(
5540 "var left = '';"
5541 "for (var i = 0; i < 0xd800; i += 4) {"
5542 " left = left + String.fromCharCode(i);"
5543 "}");
5544 CompileRun(
5545 "var right = '';"
5546 "for (var i = 0; i < 0xd800; i += 4) {"
5547 " right = String.fromCharCode(i) + right;"
5548 "}");
5549 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5550 Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
5551 Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
Ben Murdochb0fe1622011-05-05 13:52:32 +01005552
5553 CHECK_EQ(5, str2->Length());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005554 CHECK_EQ(0xd800 / kStride, left_tree->Length());
5555 CHECK_EQ(0xd800 / kStride, right_tree->Length());
Steve Blocka7e24c12009-10-30 11:49:00 +00005556
5557 char buf[100];
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005558 char utf8buf[0xd800 * 3];
Ben Murdochb0fe1622011-05-05 13:52:32 +01005559 uint16_t wbuf[100];
Steve Blocka7e24c12009-10-30 11:49:00 +00005560 int len;
Ben Murdochb0fe1622011-05-05 13:52:32 +01005561 int charlen;
5562
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005563 memset(utf8buf, 0x1, 1000);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005564 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01005565 CHECK_EQ(9, len);
5566 CHECK_EQ(5, charlen);
5567 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005568
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005569 memset(utf8buf, 0x1, 1000);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005570 len = str2->WriteUtf8(utf8buf, 8, &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01005571 CHECK_EQ(8, len);
5572 CHECK_EQ(5, charlen);
5573 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005574
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005575 memset(utf8buf, 0x1, 1000);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005576 len = str2->WriteUtf8(utf8buf, 7, &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01005577 CHECK_EQ(5, len);
5578 CHECK_EQ(4, charlen);
5579 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005580
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005581 memset(utf8buf, 0x1, 1000);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005582 len = str2->WriteUtf8(utf8buf, 6, &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01005583 CHECK_EQ(5, len);
5584 CHECK_EQ(4, charlen);
5585 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005586
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005587 memset(utf8buf, 0x1, 1000);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005588 len = str2->WriteUtf8(utf8buf, 5, &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01005589 CHECK_EQ(5, len);
5590 CHECK_EQ(4, charlen);
5591 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005592
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005593 memset(utf8buf, 0x1, 1000);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005594 len = str2->WriteUtf8(utf8buf, 4, &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01005595 CHECK_EQ(3, len);
5596 CHECK_EQ(3, charlen);
5597 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005598
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005599 memset(utf8buf, 0x1, 1000);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005600 len = str2->WriteUtf8(utf8buf, 3, &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01005601 CHECK_EQ(3, len);
5602 CHECK_EQ(3, charlen);
5603 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005604
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005605 memset(utf8buf, 0x1, 1000);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005606 len = str2->WriteUtf8(utf8buf, 2, &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01005607 CHECK_EQ(2, len);
5608 CHECK_EQ(2, charlen);
5609 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
Steve Blocka7e24c12009-10-30 11:49:00 +00005610
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005611 memset(utf8buf, 0x1, sizeof(utf8buf));
5612 len = left_tree->Utf8Length();
5613 int utf8_expected =
5614 (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
5615 CHECK_EQ(utf8_expected, len);
5616 len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
5617 CHECK_EQ(utf8_expected, len);
5618 CHECK_EQ(0xd800 / kStride, charlen);
5619 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
5620 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
5621 CHECK_EQ(0xc0 - kStride,
5622 static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
5623 CHECK_EQ(1, utf8buf[utf8_expected]);
5624
5625 memset(utf8buf, 0x1, sizeof(utf8buf));
5626 len = right_tree->Utf8Length();
5627 CHECK_EQ(utf8_expected, len);
5628 len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
5629 CHECK_EQ(utf8_expected, len);
5630 CHECK_EQ(0xd800 / kStride, charlen);
5631 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
5632 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
5633 CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
5634 CHECK_EQ(1, utf8buf[utf8_expected]);
5635
Steve Blocka7e24c12009-10-30 11:49:00 +00005636 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005637 memset(wbuf, 0x1, sizeof(wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00005638 len = str->WriteAscii(buf);
Steve Block44f0eee2011-05-26 01:26:41 +01005639 CHECK_EQ(5, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005640 len = str->Write(wbuf);
Steve Block44f0eee2011-05-26 01:26:41 +01005641 CHECK_EQ(5, len);
5642 CHECK_EQ(0, strcmp("abcde", buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005643 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
Steve Block44f0eee2011-05-26 01:26:41 +01005644 CHECK_EQ(0, StrCmp16(answer1, wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00005645
5646 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005647 memset(wbuf, 0x1, sizeof(wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00005648 len = str->WriteAscii(buf, 0, 4);
Steve Block44f0eee2011-05-26 01:26:41 +01005649 CHECK_EQ(4, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005650 len = str->Write(wbuf, 0, 4);
Steve Block44f0eee2011-05-26 01:26:41 +01005651 CHECK_EQ(4, len);
5652 CHECK_EQ(0, strncmp("abcd\1", buf, 5));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005653 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
Steve Block44f0eee2011-05-26 01:26:41 +01005654 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
Steve Blocka7e24c12009-10-30 11:49:00 +00005655
5656 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005657 memset(wbuf, 0x1, sizeof(wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00005658 len = str->WriteAscii(buf, 0, 5);
Steve Block44f0eee2011-05-26 01:26:41 +01005659 CHECK_EQ(5, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005660 len = str->Write(wbuf, 0, 5);
Steve Block44f0eee2011-05-26 01:26:41 +01005661 CHECK_EQ(5, len);
5662 CHECK_EQ(0, strncmp("abcde\1", buf, 6));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005663 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
Steve Block44f0eee2011-05-26 01:26:41 +01005664 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
Steve Blocka7e24c12009-10-30 11:49:00 +00005665
5666 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005667 memset(wbuf, 0x1, sizeof(wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00005668 len = str->WriteAscii(buf, 0, 6);
Steve Block44f0eee2011-05-26 01:26:41 +01005669 CHECK_EQ(5, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005670 len = str->Write(wbuf, 0, 6);
Steve Block44f0eee2011-05-26 01:26:41 +01005671 CHECK_EQ(5, len);
5672 CHECK_EQ(0, strcmp("abcde", buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005673 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
Steve Block44f0eee2011-05-26 01:26:41 +01005674 CHECK_EQ(0, StrCmp16(answer4, wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00005675
5676 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005677 memset(wbuf, 0x1, sizeof(wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00005678 len = str->WriteAscii(buf, 4, -1);
Steve Block44f0eee2011-05-26 01:26:41 +01005679 CHECK_EQ(1, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005680 len = str->Write(wbuf, 4, -1);
Steve Block44f0eee2011-05-26 01:26:41 +01005681 CHECK_EQ(1, len);
5682 CHECK_EQ(0, strcmp("e", buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005683 uint16_t answer5[] = {'e', '\0'};
Steve Block44f0eee2011-05-26 01:26:41 +01005684 CHECK_EQ(0, StrCmp16(answer5, wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00005685
5686 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005687 memset(wbuf, 0x1, sizeof(wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00005688 len = str->WriteAscii(buf, 4, 6);
Steve Block44f0eee2011-05-26 01:26:41 +01005689 CHECK_EQ(1, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005690 len = str->Write(wbuf, 4, 6);
Steve Block44f0eee2011-05-26 01:26:41 +01005691 CHECK_EQ(1, len);
5692 CHECK_EQ(0, strcmp("e", buf));
5693 CHECK_EQ(0, StrCmp16(answer5, wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00005694
5695 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005696 memset(wbuf, 0x1, sizeof(wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00005697 len = str->WriteAscii(buf, 4, 1);
Steve Block44f0eee2011-05-26 01:26:41 +01005698 CHECK_EQ(1, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005699 len = str->Write(wbuf, 4, 1);
Steve Block44f0eee2011-05-26 01:26:41 +01005700 CHECK_EQ(1, len);
5701 CHECK_EQ(0, strncmp("e\1", buf, 2));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005702 uint16_t answer6[] = {'e', 0x101};
Steve Block44f0eee2011-05-26 01:26:41 +01005703 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005704
5705 memset(buf, 0x1, sizeof(buf));
5706 memset(wbuf, 0x1, sizeof(wbuf));
5707 len = str->WriteAscii(buf, 3, 1);
Steve Block44f0eee2011-05-26 01:26:41 +01005708 CHECK_EQ(1, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005709 len = str->Write(wbuf, 3, 1);
Steve Block44f0eee2011-05-26 01:26:41 +01005710 CHECK_EQ(1, len);
5711 CHECK_EQ(0, strncmp("d\1", buf, 2));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005712 uint16_t answer7[] = {'d', 0x101};
Steve Block44f0eee2011-05-26 01:26:41 +01005713 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005714
5715 memset(wbuf, 0x1, sizeof(wbuf));
5716 wbuf[5] = 'X';
5717 len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
5718 CHECK_EQ(5, len);
5719 CHECK_EQ('X', wbuf[5]);
5720 uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
5721 uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
5722 CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
5723 CHECK_NE(0, StrCmp16(answer8b, wbuf));
5724 wbuf[5] = '\0';
5725 CHECK_EQ(0, StrCmp16(answer8b, wbuf));
5726
5727 memset(buf, 0x1, sizeof(buf));
5728 buf[5] = 'X';
5729 len = str->WriteAscii(buf, 0, 6, String::NO_NULL_TERMINATION);
5730 CHECK_EQ(5, len);
5731 CHECK_EQ('X', buf[5]);
5732 CHECK_EQ(0, strncmp("abcde", buf, 5));
5733 CHECK_NE(0, strcmp("abcde", buf));
5734 buf[5] = '\0';
5735 CHECK_EQ(0, strcmp("abcde", buf));
5736
5737 memset(utf8buf, 0x1, sizeof(utf8buf));
5738 utf8buf[8] = 'X';
5739 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
5740 String::NO_NULL_TERMINATION);
5741 CHECK_EQ(8, len);
5742 CHECK_EQ('X', utf8buf[8]);
5743 CHECK_EQ(5, charlen);
5744 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
5745 CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
5746 utf8buf[8] = '\0';
5747 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
Steve Blocka7e24c12009-10-30 11:49:00 +00005748}
5749
5750
5751THREADED_TEST(ToArrayIndex) {
5752 v8::HandleScope scope;
5753 LocalContext context;
5754
5755 v8::Handle<String> str = v8_str("42");
5756 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
5757 CHECK(!index.IsEmpty());
5758 CHECK_EQ(42.0, index->Uint32Value());
5759 str = v8_str("42asdf");
5760 index = str->ToArrayIndex();
5761 CHECK(index.IsEmpty());
5762 str = v8_str("-42");
5763 index = str->ToArrayIndex();
5764 CHECK(index.IsEmpty());
5765 str = v8_str("4294967295");
5766 index = str->ToArrayIndex();
5767 CHECK(!index.IsEmpty());
5768 CHECK_EQ(4294967295.0, index->Uint32Value());
5769 v8::Handle<v8::Number> num = v8::Number::New(1);
5770 index = num->ToArrayIndex();
5771 CHECK(!index.IsEmpty());
5772 CHECK_EQ(1.0, index->Uint32Value());
5773 num = v8::Number::New(-1);
5774 index = num->ToArrayIndex();
5775 CHECK(index.IsEmpty());
5776 v8::Handle<v8::Object> obj = v8::Object::New();
5777 index = obj->ToArrayIndex();
5778 CHECK(index.IsEmpty());
5779}
5780
5781
5782THREADED_TEST(ErrorConstruction) {
5783 v8::HandleScope scope;
5784 LocalContext context;
5785
5786 v8::Handle<String> foo = v8_str("foo");
5787 v8::Handle<String> message = v8_str("message");
5788 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
5789 CHECK(range_error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01005790 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00005791 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
5792 CHECK(reference_error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01005793 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00005794 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
5795 CHECK(syntax_error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01005796 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00005797 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
5798 CHECK(type_error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01005799 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00005800 v8::Handle<Value> error = v8::Exception::Error(foo);
5801 CHECK(error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01005802 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00005803}
5804
5805
5806static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
5807 ApiTestFuzzer::Fuzz();
5808 return v8_num(10);
5809}
5810
5811
5812static void YSetter(Local<String> name,
5813 Local<Value> value,
5814 const AccessorInfo& info) {
5815 if (info.This()->Has(name)) {
5816 info.This()->Delete(name);
5817 }
5818 info.This()->Set(name, value);
5819}
5820
5821
5822THREADED_TEST(DeleteAccessor) {
5823 v8::HandleScope scope;
5824 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5825 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
5826 LocalContext context;
5827 v8::Handle<v8::Object> holder = obj->NewInstance();
5828 context->Global()->Set(v8_str("holder"), holder);
5829 v8::Handle<Value> result = CompileRun(
5830 "holder.y = 11; holder.y = 12; holder.y");
5831 CHECK_EQ(12, result->Uint32Value());
5832}
5833
5834
5835THREADED_TEST(TypeSwitch) {
5836 v8::HandleScope scope;
5837 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
5838 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
5839 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
5840 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
5841 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
5842 LocalContext context;
5843 v8::Handle<v8::Object> obj0 = v8::Object::New();
5844 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
5845 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
5846 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
5847 for (int i = 0; i < 10; i++) {
5848 CHECK_EQ(0, type_switch->match(obj0));
5849 CHECK_EQ(1, type_switch->match(obj1));
5850 CHECK_EQ(2, type_switch->match(obj2));
5851 CHECK_EQ(3, type_switch->match(obj3));
5852 CHECK_EQ(3, type_switch->match(obj3));
5853 CHECK_EQ(2, type_switch->match(obj2));
5854 CHECK_EQ(1, type_switch->match(obj1));
5855 CHECK_EQ(0, type_switch->match(obj0));
5856 }
5857}
5858
5859
5860// For use within the TestSecurityHandler() test.
5861static bool g_security_callback_result = false;
5862static bool NamedSecurityTestCallback(Local<v8::Object> global,
5863 Local<Value> name,
5864 v8::AccessType type,
5865 Local<Value> data) {
5866 // Always allow read access.
5867 if (type == v8::ACCESS_GET)
5868 return true;
5869
5870 // Sometimes allow other access.
5871 return g_security_callback_result;
5872}
5873
5874
5875static bool IndexedSecurityTestCallback(Local<v8::Object> global,
5876 uint32_t key,
5877 v8::AccessType type,
5878 Local<Value> data) {
5879 // Always allow read access.
5880 if (type == v8::ACCESS_GET)
5881 return true;
5882
5883 // Sometimes allow other access.
5884 return g_security_callback_result;
5885}
5886
5887
5888static int trouble_nesting = 0;
5889static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
5890 ApiTestFuzzer::Fuzz();
5891 trouble_nesting++;
5892
5893 // Call a JS function that throws an uncaught exception.
5894 Local<v8::Object> arg_this = Context::GetCurrent()->Global();
5895 Local<Value> trouble_callee = (trouble_nesting == 3) ?
5896 arg_this->Get(v8_str("trouble_callee")) :
5897 arg_this->Get(v8_str("trouble_caller"));
5898 CHECK(trouble_callee->IsFunction());
5899 return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
5900}
5901
5902
5903static int report_count = 0;
5904static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
5905 v8::Handle<Value>) {
5906 report_count++;
5907}
5908
5909
5910// Counts uncaught exceptions, but other tests running in parallel
5911// also have uncaught exceptions.
5912TEST(ApiUncaughtException) {
5913 report_count = 0;
5914 v8::HandleScope scope;
5915 LocalContext env;
5916 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
5917
5918 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
5919 v8::Local<v8::Object> global = env->Global();
5920 global->Set(v8_str("trouble"), fun->GetFunction());
5921
5922 Script::Compile(v8_str("function trouble_callee() {"
5923 " var x = null;"
5924 " return x.foo;"
5925 "};"
5926 "function trouble_caller() {"
5927 " trouble();"
5928 "};"))->Run();
5929 Local<Value> trouble = global->Get(v8_str("trouble"));
5930 CHECK(trouble->IsFunction());
5931 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
5932 CHECK(trouble_callee->IsFunction());
5933 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
5934 CHECK(trouble_caller->IsFunction());
5935 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
5936 CHECK_EQ(1, report_count);
5937 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
5938}
5939
Leon Clarke4515c472010-02-03 11:58:03 +00005940static const char* script_resource_name = "ExceptionInNativeScript.js";
5941static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
5942 v8::Handle<Value>) {
5943 v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
5944 CHECK(!name_val.IsEmpty() && name_val->IsString());
5945 v8::String::AsciiValue name(message->GetScriptResourceName());
5946 CHECK_EQ(script_resource_name, *name);
5947 CHECK_EQ(3, message->GetLineNumber());
5948 v8::String::AsciiValue source_line(message->GetSourceLine());
5949 CHECK_EQ(" new o.foo();", *source_line);
5950}
5951
5952TEST(ExceptionInNativeScript) {
5953 v8::HandleScope scope;
5954 LocalContext env;
5955 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
5956
5957 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
5958 v8::Local<v8::Object> global = env->Global();
5959 global->Set(v8_str("trouble"), fun->GetFunction());
5960
5961 Script::Compile(v8_str("function trouble() {\n"
5962 " var o = {};\n"
5963 " new o.foo();\n"
5964 "};"), v8::String::New(script_resource_name))->Run();
5965 Local<Value> trouble = global->Get(v8_str("trouble"));
5966 CHECK(trouble->IsFunction());
5967 Function::Cast(*trouble)->Call(global, 0, NULL);
5968 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
5969}
5970
Steve Blocka7e24c12009-10-30 11:49:00 +00005971
5972TEST(CompilationErrorUsingTryCatchHandler) {
5973 v8::HandleScope scope;
5974 LocalContext env;
5975 v8::TryCatch try_catch;
5976 Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
5977 CHECK_NE(NULL, *try_catch.Exception());
5978 CHECK(try_catch.HasCaught());
5979}
5980
5981
5982TEST(TryCatchFinallyUsingTryCatchHandler) {
5983 v8::HandleScope scope;
5984 LocalContext env;
5985 v8::TryCatch try_catch;
5986 Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
5987 CHECK(!try_catch.HasCaught());
5988 Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
5989 CHECK(try_catch.HasCaught());
5990 try_catch.Reset();
5991 Script::Compile(v8_str("(function() {"
5992 "try { throw ''; } finally { return; }"
5993 "})()"))->Run();
5994 CHECK(!try_catch.HasCaught());
5995 Script::Compile(v8_str("(function()"
5996 " { try { throw ''; } finally { throw 0; }"
5997 "})()"))->Run();
5998 CHECK(try_catch.HasCaught());
5999}
6000
6001
6002// SecurityHandler can't be run twice
6003TEST(SecurityHandler) {
6004 v8::HandleScope scope0;
6005 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
6006 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
6007 IndexedSecurityTestCallback);
6008 // Create an environment
6009 v8::Persistent<Context> context0 =
6010 Context::New(NULL, global_template);
6011 context0->Enter();
6012
6013 v8::Handle<v8::Object> global0 = context0->Global();
6014 v8::Handle<Script> script0 = v8_compile("foo = 111");
6015 script0->Run();
6016 global0->Set(v8_str("0"), v8_num(999));
6017 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
6018 CHECK_EQ(111, foo0->Int32Value());
6019 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
6020 CHECK_EQ(999, z0->Int32Value());
6021
6022 // Create another environment, should fail security checks.
6023 v8::HandleScope scope1;
6024
6025 v8::Persistent<Context> context1 =
6026 Context::New(NULL, global_template);
6027 context1->Enter();
6028
6029 v8::Handle<v8::Object> global1 = context1->Global();
6030 global1->Set(v8_str("othercontext"), global0);
6031 // This set will fail the security check.
6032 v8::Handle<Script> script1 =
6033 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
6034 script1->Run();
6035 // This read will pass the security check.
6036 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
6037 CHECK_EQ(111, foo1->Int32Value());
6038 // This read will pass the security check.
6039 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
6040 CHECK_EQ(999, z1->Int32Value());
6041
6042 // Create another environment, should pass security checks.
6043 { g_security_callback_result = true; // allow security handler to pass.
6044 v8::HandleScope scope2;
6045 LocalContext context2;
6046 v8::Handle<v8::Object> global2 = context2->Global();
6047 global2->Set(v8_str("othercontext"), global0);
6048 v8::Handle<Script> script2 =
6049 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
6050 script2->Run();
6051 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
6052 CHECK_EQ(333, foo2->Int32Value());
6053 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
6054 CHECK_EQ(888, z2->Int32Value());
6055 }
6056
6057 context1->Exit();
6058 context1.Dispose();
6059
6060 context0->Exit();
6061 context0.Dispose();
6062}
6063
6064
6065THREADED_TEST(SecurityChecks) {
6066 v8::HandleScope handle_scope;
6067 LocalContext env1;
6068 v8::Persistent<Context> env2 = Context::New();
6069
6070 Local<Value> foo = v8_str("foo");
6071 Local<Value> bar = v8_str("bar");
6072
6073 // Set to the same domain.
6074 env1->SetSecurityToken(foo);
6075
6076 // Create a function in env1.
6077 Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
6078 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
6079 CHECK(spy->IsFunction());
6080
6081 // Create another function accessing global objects.
6082 Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
6083 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
6084 CHECK(spy2->IsFunction());
6085
6086 // Switch to env2 in the same domain and invoke spy on env2.
6087 {
6088 env2->SetSecurityToken(foo);
6089 // Enter env2
6090 Context::Scope scope_env2(env2);
6091 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
6092 CHECK(result->IsFunction());
6093 }
6094
6095 {
6096 env2->SetSecurityToken(bar);
6097 Context::Scope scope_env2(env2);
6098
6099 // Call cross_domain_call, it should throw an exception
6100 v8::TryCatch try_catch;
6101 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
6102 CHECK(try_catch.HasCaught());
6103 }
6104
6105 env2.Dispose();
6106}
6107
6108
6109// Regression test case for issue 1183439.
6110THREADED_TEST(SecurityChecksForPrototypeChain) {
6111 v8::HandleScope scope;
6112 LocalContext current;
6113 v8::Persistent<Context> other = Context::New();
6114
6115 // Change context to be able to get to the Object function in the
6116 // other context without hitting the security checks.
6117 v8::Local<Value> other_object;
6118 { Context::Scope scope(other);
6119 other_object = other->Global()->Get(v8_str("Object"));
6120 other->Global()->Set(v8_num(42), v8_num(87));
6121 }
6122
6123 current->Global()->Set(v8_str("other"), other->Global());
6124 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
6125
6126 // Make sure the security check fails here and we get an undefined
6127 // result instead of getting the Object function. Repeat in a loop
6128 // to make sure to exercise the IC code.
6129 v8::Local<Script> access_other0 = v8_compile("other.Object");
6130 v8::Local<Script> access_other1 = v8_compile("other[42]");
6131 for (int i = 0; i < 5; i++) {
6132 CHECK(!access_other0->Run()->Equals(other_object));
6133 CHECK(access_other0->Run()->IsUndefined());
6134 CHECK(!access_other1->Run()->Equals(v8_num(87)));
6135 CHECK(access_other1->Run()->IsUndefined());
6136 }
6137
6138 // Create an object that has 'other' in its prototype chain and make
6139 // sure we cannot access the Object function indirectly through
6140 // that. Repeat in a loop to make sure to exercise the IC code.
6141 v8_compile("function F() { };"
6142 "F.prototype = other;"
6143 "var f = new F();")->Run();
6144 v8::Local<Script> access_f0 = v8_compile("f.Object");
6145 v8::Local<Script> access_f1 = v8_compile("f[42]");
6146 for (int j = 0; j < 5; j++) {
6147 CHECK(!access_f0->Run()->Equals(other_object));
6148 CHECK(access_f0->Run()->IsUndefined());
6149 CHECK(!access_f1->Run()->Equals(v8_num(87)));
6150 CHECK(access_f1->Run()->IsUndefined());
6151 }
6152
6153 // Now it gets hairy: Set the prototype for the other global object
6154 // to be the current global object. The prototype chain for 'f' now
6155 // goes through 'other' but ends up in the current global object.
6156 { Context::Scope scope(other);
6157 other->Global()->Set(v8_str("__proto__"), current->Global());
6158 }
6159 // Set a named and an index property on the current global
6160 // object. To force the lookup to go through the other global object,
6161 // the properties must not exist in the other global object.
6162 current->Global()->Set(v8_str("foo"), v8_num(100));
6163 current->Global()->Set(v8_num(99), v8_num(101));
6164 // Try to read the properties from f and make sure that the access
6165 // gets stopped by the security checks on the other global object.
6166 Local<Script> access_f2 = v8_compile("f.foo");
6167 Local<Script> access_f3 = v8_compile("f[99]");
6168 for (int k = 0; k < 5; k++) {
6169 CHECK(!access_f2->Run()->Equals(v8_num(100)));
6170 CHECK(access_f2->Run()->IsUndefined());
6171 CHECK(!access_f3->Run()->Equals(v8_num(101)));
6172 CHECK(access_f3->Run()->IsUndefined());
6173 }
6174 other.Dispose();
6175}
6176
6177
6178THREADED_TEST(CrossDomainDelete) {
6179 v8::HandleScope handle_scope;
6180 LocalContext env1;
6181 v8::Persistent<Context> env2 = Context::New();
6182
6183 Local<Value> foo = v8_str("foo");
6184 Local<Value> bar = v8_str("bar");
6185
6186 // Set to the same domain.
6187 env1->SetSecurityToken(foo);
6188 env2->SetSecurityToken(foo);
6189
6190 env1->Global()->Set(v8_str("prop"), v8_num(3));
6191 env2->Global()->Set(v8_str("env1"), env1->Global());
6192
6193 // Change env2 to a different domain and delete env1.prop.
6194 env2->SetSecurityToken(bar);
6195 {
6196 Context::Scope scope_env2(env2);
6197 Local<Value> result =
6198 Script::Compile(v8_str("delete env1.prop"))->Run();
6199 CHECK(result->IsFalse());
6200 }
6201
6202 // Check that env1.prop still exists.
6203 Local<Value> v = env1->Global()->Get(v8_str("prop"));
6204 CHECK(v->IsNumber());
6205 CHECK_EQ(3, v->Int32Value());
6206
6207 env2.Dispose();
6208}
6209
6210
6211THREADED_TEST(CrossDomainIsPropertyEnumerable) {
6212 v8::HandleScope handle_scope;
6213 LocalContext env1;
6214 v8::Persistent<Context> env2 = Context::New();
6215
6216 Local<Value> foo = v8_str("foo");
6217 Local<Value> bar = v8_str("bar");
6218
6219 // Set to the same domain.
6220 env1->SetSecurityToken(foo);
6221 env2->SetSecurityToken(foo);
6222
6223 env1->Global()->Set(v8_str("prop"), v8_num(3));
6224 env2->Global()->Set(v8_str("env1"), env1->Global());
6225
6226 // env1.prop is enumerable in env2.
6227 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
6228 {
6229 Context::Scope scope_env2(env2);
6230 Local<Value> result = Script::Compile(test)->Run();
6231 CHECK(result->IsTrue());
6232 }
6233
6234 // Change env2 to a different domain and test again.
6235 env2->SetSecurityToken(bar);
6236 {
6237 Context::Scope scope_env2(env2);
6238 Local<Value> result = Script::Compile(test)->Run();
6239 CHECK(result->IsFalse());
6240 }
6241
6242 env2.Dispose();
6243}
6244
6245
6246THREADED_TEST(CrossDomainForIn) {
6247 v8::HandleScope handle_scope;
6248 LocalContext env1;
6249 v8::Persistent<Context> env2 = Context::New();
6250
6251 Local<Value> foo = v8_str("foo");
6252 Local<Value> bar = v8_str("bar");
6253
6254 // Set to the same domain.
6255 env1->SetSecurityToken(foo);
6256 env2->SetSecurityToken(foo);
6257
6258 env1->Global()->Set(v8_str("prop"), v8_num(3));
6259 env2->Global()->Set(v8_str("env1"), env1->Global());
6260
6261 // Change env2 to a different domain and set env1's global object
6262 // as the __proto__ of an object in env2 and enumerate properties
6263 // in for-in. It shouldn't enumerate properties on env1's global
6264 // object.
6265 env2->SetSecurityToken(bar);
6266 {
6267 Context::Scope scope_env2(env2);
6268 Local<Value> result =
6269 CompileRun("(function(){var obj = {'__proto__':env1};"
6270 "for (var p in obj)"
6271 " if (p == 'prop') return false;"
6272 "return true;})()");
6273 CHECK(result->IsTrue());
6274 }
6275 env2.Dispose();
6276}
6277
6278
6279TEST(ContextDetachGlobal) {
6280 v8::HandleScope handle_scope;
6281 LocalContext env1;
6282 v8::Persistent<Context> env2 = Context::New();
6283
6284 Local<v8::Object> global1 = env1->Global();
6285
6286 Local<Value> foo = v8_str("foo");
6287
6288 // Set to the same domain.
6289 env1->SetSecurityToken(foo);
6290 env2->SetSecurityToken(foo);
6291
6292 // Enter env2
6293 env2->Enter();
6294
Andrei Popescu74b3c142010-03-29 12:03:09 +01006295 // Create a function in env2 and add a reference to it in env1.
Steve Blocka7e24c12009-10-30 11:49:00 +00006296 Local<v8::Object> global2 = env2->Global();
6297 global2->Set(v8_str("prop"), v8::Integer::New(1));
6298 CompileRun("function getProp() {return prop;}");
6299
6300 env1->Global()->Set(v8_str("getProp"),
6301 global2->Get(v8_str("getProp")));
6302
Andrei Popescu74b3c142010-03-29 12:03:09 +01006303 // Detach env2's global, and reuse the global object of env2
Steve Blocka7e24c12009-10-30 11:49:00 +00006304 env2->Exit();
6305 env2->DetachGlobal();
6306 // env2 has a new global object.
6307 CHECK(!env2->Global()->Equals(global2));
6308
6309 v8::Persistent<Context> env3 =
6310 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
6311 env3->SetSecurityToken(v8_str("bar"));
6312 env3->Enter();
6313
6314 Local<v8::Object> global3 = env3->Global();
6315 CHECK_EQ(global2, global3);
6316 CHECK(global3->Get(v8_str("prop"))->IsUndefined());
6317 CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
6318 global3->Set(v8_str("prop"), v8::Integer::New(-1));
6319 global3->Set(v8_str("prop2"), v8::Integer::New(2));
6320 env3->Exit();
6321
6322 // Call getProp in env1, and it should return the value 1
6323 {
6324 Local<Value> get_prop = global1->Get(v8_str("getProp"));
6325 CHECK(get_prop->IsFunction());
6326 v8::TryCatch try_catch;
6327 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
6328 CHECK(!try_catch.HasCaught());
6329 CHECK_EQ(1, r->Int32Value());
6330 }
6331
6332 // Check that env3 is not accessible from env1
6333 {
6334 Local<Value> r = global3->Get(v8_str("prop2"));
6335 CHECK(r->IsUndefined());
6336 }
6337
6338 env2.Dispose();
6339 env3.Dispose();
6340}
6341
6342
Andrei Popescu74b3c142010-03-29 12:03:09 +01006343TEST(DetachAndReattachGlobal) {
6344 v8::HandleScope scope;
6345 LocalContext env1;
6346
6347 // Create second environment.
6348 v8::Persistent<Context> env2 = Context::New();
6349
6350 Local<Value> foo = v8_str("foo");
6351
6352 // Set same security token for env1 and env2.
6353 env1->SetSecurityToken(foo);
6354 env2->SetSecurityToken(foo);
6355
6356 // Create a property on the global object in env2.
6357 {
6358 v8::Context::Scope scope(env2);
6359 env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
6360 }
6361
6362 // Create a reference to env2 global from env1 global.
6363 env1->Global()->Set(v8_str("other"), env2->Global());
6364
6365 // Check that we have access to other.p in env2 from env1.
6366 Local<Value> result = CompileRun("other.p");
6367 CHECK(result->IsInt32());
6368 CHECK_EQ(42, result->Int32Value());
6369
6370 // Hold on to global from env2 and detach global from env2.
6371 Local<v8::Object> global2 = env2->Global();
6372 env2->DetachGlobal();
6373
6374 // Check that the global has been detached. No other.p property can
6375 // be found.
6376 result = CompileRun("other.p");
6377 CHECK(result->IsUndefined());
6378
6379 // Reuse global2 for env3.
6380 v8::Persistent<Context> env3 =
6381 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
6382 CHECK_EQ(global2, env3->Global());
6383
6384 // Start by using the same security token for env3 as for env1 and env2.
6385 env3->SetSecurityToken(foo);
6386
6387 // Create a property on the global object in env3.
6388 {
6389 v8::Context::Scope scope(env3);
6390 env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
6391 }
6392
6393 // Check that other.p is now the property in env3 and that we have access.
6394 result = CompileRun("other.p");
6395 CHECK(result->IsInt32());
6396 CHECK_EQ(24, result->Int32Value());
6397
6398 // Change security token for env3 to something different from env1 and env2.
6399 env3->SetSecurityToken(v8_str("bar"));
6400
6401 // Check that we do not have access to other.p in env1. |other| is now
6402 // the global object for env3 which has a different security token,
6403 // so access should be blocked.
6404 result = CompileRun("other.p");
6405 CHECK(result->IsUndefined());
6406
6407 // Detach the global for env3 and reattach it to env2.
6408 env3->DetachGlobal();
6409 env2->ReattachGlobal(global2);
6410
6411 // Check that we have access to other.p again in env1. |other| is now
6412 // the global object for env2 which has the same security token as env1.
6413 result = CompileRun("other.p");
6414 CHECK(result->IsInt32());
6415 CHECK_EQ(42, result->Int32Value());
6416
6417 env2.Dispose();
6418 env3.Dispose();
6419}
6420
6421
Steve Block1e0659c2011-05-24 12:43:12 +01006422static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
Steve Blocka7e24c12009-10-30 11:49:00 +00006423static bool NamedAccessBlocker(Local<v8::Object> global,
6424 Local<Value> name,
6425 v8::AccessType type,
6426 Local<Value> data) {
Steve Block1e0659c2011-05-24 12:43:12 +01006427 return Context::GetCurrent()->Global()->Equals(global) ||
6428 allowed_access_type[type];
Steve Blocka7e24c12009-10-30 11:49:00 +00006429}
6430
6431
6432static bool IndexedAccessBlocker(Local<v8::Object> global,
6433 uint32_t key,
6434 v8::AccessType type,
6435 Local<Value> data) {
Steve Block1e0659c2011-05-24 12:43:12 +01006436 return Context::GetCurrent()->Global()->Equals(global) ||
6437 allowed_access_type[type];
Steve Blocka7e24c12009-10-30 11:49:00 +00006438}
6439
6440
6441static int g_echo_value = -1;
6442static v8::Handle<Value> EchoGetter(Local<String> name,
6443 const AccessorInfo& info) {
6444 return v8_num(g_echo_value);
6445}
6446
6447
6448static void EchoSetter(Local<String> name,
6449 Local<Value> value,
6450 const AccessorInfo&) {
6451 if (value->IsNumber())
6452 g_echo_value = value->Int32Value();
6453}
6454
6455
6456static v8::Handle<Value> UnreachableGetter(Local<String> name,
6457 const AccessorInfo& info) {
6458 CHECK(false); // This function should not be called..
6459 return v8::Undefined();
6460}
6461
6462
6463static void UnreachableSetter(Local<String>, Local<Value>,
6464 const AccessorInfo&) {
6465 CHECK(false); // This function should nto be called.
6466}
6467
6468
Steve Block1e0659c2011-05-24 12:43:12 +01006469TEST(AccessControl) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006470 v8::HandleScope handle_scope;
6471 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
6472
6473 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
6474 IndexedAccessBlocker);
6475
6476 // Add an accessor accessible by cross-domain JS code.
6477 global_template->SetAccessor(
6478 v8_str("accessible_prop"),
6479 EchoGetter, EchoSetter,
6480 v8::Handle<Value>(),
6481 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
6482
6483 // Add an accessor that is not accessible by cross-domain JS code.
6484 global_template->SetAccessor(v8_str("blocked_prop"),
6485 UnreachableGetter, UnreachableSetter,
6486 v8::Handle<Value>(),
6487 v8::DEFAULT);
6488
6489 // Create an environment
6490 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6491 context0->Enter();
6492
6493 v8::Handle<v8::Object> global0 = context0->Global();
6494
Steve Block1e0659c2011-05-24 12:43:12 +01006495 // Define a property with JS getter and setter.
6496 CompileRun(
6497 "function getter() { return 'getter'; };\n"
6498 "function setter() { return 'setter'; }\n"
6499 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
6500
6501 Local<Value> getter = global0->Get(v8_str("getter"));
6502 Local<Value> setter = global0->Get(v8_str("setter"));
6503
6504 // And define normal element.
6505 global0->Set(239, v8_str("239"));
6506
6507 // Define an element with JS getter and setter.
6508 CompileRun(
6509 "function el_getter() { return 'el_getter'; };\n"
6510 "function el_setter() { return 'el_setter'; };\n"
6511 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
6512
6513 Local<Value> el_getter = global0->Get(v8_str("el_getter"));
6514 Local<Value> el_setter = global0->Get(v8_str("el_setter"));
6515
Steve Blocka7e24c12009-10-30 11:49:00 +00006516 v8::HandleScope scope1;
6517
6518 v8::Persistent<Context> context1 = Context::New();
6519 context1->Enter();
6520
6521 v8::Handle<v8::Object> global1 = context1->Global();
6522 global1->Set(v8_str("other"), global0);
6523
Steve Block1e0659c2011-05-24 12:43:12 +01006524 // Access blocked property.
6525 CompileRun("other.blocked_prop = 1");
6526
6527 ExpectUndefined("other.blocked_prop");
6528 ExpectUndefined(
6529 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
6530 ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
6531
6532 // Enable ACCESS_HAS
6533 allowed_access_type[v8::ACCESS_HAS] = true;
6534 ExpectUndefined("other.blocked_prop");
6535 // ... and now we can get the descriptor...
6536 ExpectUndefined(
6537 "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
6538 // ... and enumerate the property.
6539 ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
6540 allowed_access_type[v8::ACCESS_HAS] = false;
6541
6542 // Access blocked element.
6543 CompileRun("other[239] = 1");
6544
6545 ExpectUndefined("other[239]");
6546 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
6547 ExpectFalse("propertyIsEnumerable.call(other, '239')");
6548
6549 // Enable ACCESS_HAS
6550 allowed_access_type[v8::ACCESS_HAS] = true;
6551 ExpectUndefined("other[239]");
6552 // ... and now we can get the descriptor...
6553 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
6554 // ... and enumerate the property.
6555 ExpectTrue("propertyIsEnumerable.call(other, '239')");
6556 allowed_access_type[v8::ACCESS_HAS] = false;
6557
6558 // Access a property with JS accessor.
6559 CompileRun("other.js_accessor_p = 2");
6560
6561 ExpectUndefined("other.js_accessor_p");
6562 ExpectUndefined(
6563 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
6564
6565 // Enable ACCESS_HAS.
6566 allowed_access_type[v8::ACCESS_HAS] = true;
6567 ExpectUndefined("other.js_accessor_p");
6568 ExpectUndefined(
6569 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
6570 ExpectUndefined(
6571 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
6572 ExpectUndefined(
6573 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6574 allowed_access_type[v8::ACCESS_HAS] = false;
6575
6576 // Enable both ACCESS_HAS and ACCESS_GET.
6577 allowed_access_type[v8::ACCESS_HAS] = true;
6578 allowed_access_type[v8::ACCESS_GET] = true;
6579
6580 ExpectString("other.js_accessor_p", "getter");
6581 ExpectObject(
6582 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
6583 ExpectUndefined(
6584 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
6585 ExpectUndefined(
6586 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6587
6588 allowed_access_type[v8::ACCESS_GET] = false;
6589 allowed_access_type[v8::ACCESS_HAS] = false;
6590
6591 // Enable both ACCESS_HAS and ACCESS_SET.
6592 allowed_access_type[v8::ACCESS_HAS] = true;
6593 allowed_access_type[v8::ACCESS_SET] = true;
6594
6595 ExpectUndefined("other.js_accessor_p");
6596 ExpectUndefined(
6597 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
6598 ExpectObject(
6599 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
6600 ExpectUndefined(
6601 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6602
6603 allowed_access_type[v8::ACCESS_SET] = false;
6604 allowed_access_type[v8::ACCESS_HAS] = false;
6605
6606 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
6607 allowed_access_type[v8::ACCESS_HAS] = true;
6608 allowed_access_type[v8::ACCESS_GET] = true;
6609 allowed_access_type[v8::ACCESS_SET] = true;
6610
6611 ExpectString("other.js_accessor_p", "getter");
6612 ExpectObject(
6613 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
6614 ExpectObject(
6615 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
6616 ExpectUndefined(
6617 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6618
6619 allowed_access_type[v8::ACCESS_SET] = false;
6620 allowed_access_type[v8::ACCESS_GET] = false;
6621 allowed_access_type[v8::ACCESS_HAS] = false;
6622
6623 // Access an element with JS accessor.
6624 CompileRun("other[42] = 2");
6625
6626 ExpectUndefined("other[42]");
6627 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
6628
6629 // Enable ACCESS_HAS.
6630 allowed_access_type[v8::ACCESS_HAS] = true;
6631 ExpectUndefined("other[42]");
6632 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
6633 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
6634 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6635 allowed_access_type[v8::ACCESS_HAS] = false;
6636
6637 // Enable both ACCESS_HAS and ACCESS_GET.
6638 allowed_access_type[v8::ACCESS_HAS] = true;
6639 allowed_access_type[v8::ACCESS_GET] = true;
6640
6641 ExpectString("other[42]", "el_getter");
6642 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
6643 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
6644 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6645
6646 allowed_access_type[v8::ACCESS_GET] = false;
6647 allowed_access_type[v8::ACCESS_HAS] = false;
6648
6649 // Enable both ACCESS_HAS and ACCESS_SET.
6650 allowed_access_type[v8::ACCESS_HAS] = true;
6651 allowed_access_type[v8::ACCESS_SET] = true;
6652
6653 ExpectUndefined("other[42]");
6654 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
6655 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
6656 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6657
6658 allowed_access_type[v8::ACCESS_SET] = false;
6659 allowed_access_type[v8::ACCESS_HAS] = false;
6660
6661 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
6662 allowed_access_type[v8::ACCESS_HAS] = true;
6663 allowed_access_type[v8::ACCESS_GET] = true;
6664 allowed_access_type[v8::ACCESS_SET] = true;
6665
6666 ExpectString("other[42]", "el_getter");
6667 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
6668 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
6669 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6670
6671 allowed_access_type[v8::ACCESS_SET] = false;
6672 allowed_access_type[v8::ACCESS_GET] = false;
6673 allowed_access_type[v8::ACCESS_HAS] = false;
6674
Steve Blocka7e24c12009-10-30 11:49:00 +00006675 v8::Handle<Value> value;
6676
Steve Blocka7e24c12009-10-30 11:49:00 +00006677 // Access accessible property
Steve Block1e0659c2011-05-24 12:43:12 +01006678 value = CompileRun("other.accessible_prop = 3");
Steve Blocka7e24c12009-10-30 11:49:00 +00006679 CHECK(value->IsNumber());
6680 CHECK_EQ(3, value->Int32Value());
Andrei Popescu31002712010-02-23 13:46:05 +00006681 CHECK_EQ(3, g_echo_value);
Steve Blocka7e24c12009-10-30 11:49:00 +00006682
Steve Block1e0659c2011-05-24 12:43:12 +01006683 value = CompileRun("other.accessible_prop");
Steve Blocka7e24c12009-10-30 11:49:00 +00006684 CHECK(value->IsNumber());
6685 CHECK_EQ(3, value->Int32Value());
6686
Steve Block1e0659c2011-05-24 12:43:12 +01006687 value = CompileRun(
6688 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
6689 CHECK(value->IsNumber());
6690 CHECK_EQ(3, value->Int32Value());
6691
6692 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
Steve Blocka7e24c12009-10-30 11:49:00 +00006693 CHECK(value->IsTrue());
6694
6695 // Enumeration doesn't enumerate accessors from inaccessible objects in
6696 // the prototype chain even if the accessors are in themselves accessible.
Steve Block1e0659c2011-05-24 12:43:12 +01006697 value =
Steve Blocka7e24c12009-10-30 11:49:00 +00006698 CompileRun("(function(){var obj = {'__proto__':other};"
6699 "for (var p in obj)"
6700 " if (p == 'accessible_prop' || p == 'blocked_prop') {"
6701 " return false;"
6702 " }"
6703 "return true;})()");
Steve Block1e0659c2011-05-24 12:43:12 +01006704 CHECK(value->IsTrue());
Steve Blocka7e24c12009-10-30 11:49:00 +00006705
6706 context1->Exit();
6707 context0->Exit();
6708 context1.Dispose();
6709 context0.Dispose();
6710}
6711
6712
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006713TEST(AccessControlES5) {
6714 v8::HandleScope handle_scope;
6715 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
6716
6717 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
6718 IndexedAccessBlocker);
6719
Steve Block44f0eee2011-05-26 01:26:41 +01006720 // Add accessible accessor.
6721 global_template->SetAccessor(
6722 v8_str("accessible_prop"),
6723 EchoGetter, EchoSetter,
6724 v8::Handle<Value>(),
6725 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
6726
6727
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006728 // Add an accessor that is not accessible by cross-domain JS code.
6729 global_template->SetAccessor(v8_str("blocked_prop"),
6730 UnreachableGetter, UnreachableSetter,
6731 v8::Handle<Value>(),
6732 v8::DEFAULT);
6733
6734 // Create an environment
6735 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6736 context0->Enter();
6737
6738 v8::Handle<v8::Object> global0 = context0->Global();
6739
6740 v8::Persistent<Context> context1 = Context::New();
6741 context1->Enter();
6742 v8::Handle<v8::Object> global1 = context1->Global();
6743 global1->Set(v8_str("other"), global0);
6744
6745 // Regression test for issue 1154.
6746 ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
6747
6748 ExpectUndefined("other.blocked_prop");
6749
6750 // Regression test for issue 1027.
6751 CompileRun("Object.defineProperty(\n"
6752 " other, 'blocked_prop', {configurable: false})");
6753 ExpectUndefined("other.blocked_prop");
6754 ExpectUndefined(
6755 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
6756
6757 // Regression test for issue 1171.
6758 ExpectTrue("Object.isExtensible(other)");
6759 CompileRun("Object.preventExtensions(other)");
6760 ExpectTrue("Object.isExtensible(other)");
6761
6762 // Object.seal and Object.freeze.
6763 CompileRun("Object.freeze(other)");
6764 ExpectTrue("Object.isExtensible(other)");
6765
6766 CompileRun("Object.seal(other)");
6767 ExpectTrue("Object.isExtensible(other)");
Steve Block44f0eee2011-05-26 01:26:41 +01006768
6769 // Regression test for issue 1250.
6770 // Make sure that we can set the accessible accessors value using normal
6771 // assignment.
6772 CompileRun("other.accessible_prop = 42");
6773 CHECK_EQ(42, g_echo_value);
6774
6775 v8::Handle<Value> value;
6776 // We follow Safari in ignoring assignments to host object accessors.
6777 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
6778 value = CompileRun("other.accessible_prop == 42");
6779 CHECK(value->IsTrue());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006780}
6781
6782
Leon Clarke4515c472010-02-03 11:58:03 +00006783static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
6784 Local<Value> name,
6785 v8::AccessType type,
6786 Local<Value> data) {
6787 return false;
6788}
6789
6790
6791static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
6792 uint32_t key,
6793 v8::AccessType type,
6794 Local<Value> data) {
6795 return false;
6796}
6797
6798
6799THREADED_TEST(AccessControlGetOwnPropertyNames) {
6800 v8::HandleScope handle_scope;
6801 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
6802
6803 obj_template->Set(v8_str("x"), v8::Integer::New(42));
6804 obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
6805 GetOwnPropertyNamesIndexedBlocker);
6806
6807 // Create an environment
6808 v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
6809 context0->Enter();
6810
6811 v8::Handle<v8::Object> global0 = context0->Global();
6812
6813 v8::HandleScope scope1;
6814
6815 v8::Persistent<Context> context1 = Context::New();
6816 context1->Enter();
6817
6818 v8::Handle<v8::Object> global1 = context1->Global();
6819 global1->Set(v8_str("other"), global0);
6820 global1->Set(v8_str("object"), obj_template->NewInstance());
6821
6822 v8::Handle<Value> value;
6823
6824 // Attempt to get the property names of the other global object and
6825 // of an object that requires access checks. Accessing the other
6826 // global object should be blocked by access checks on the global
6827 // proxy object. Accessing the object that requires access checks
6828 // is blocked by the access checks on the object itself.
6829 value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
6830 CHECK(value->IsTrue());
6831
6832 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
6833 CHECK(value->IsTrue());
6834
6835 context1->Exit();
6836 context0->Exit();
6837 context1.Dispose();
6838 context0.Dispose();
6839}
6840
6841
Steve Block8defd9f2010-07-08 12:39:36 +01006842static v8::Handle<v8::Array> NamedPropertyEnumerator(const AccessorInfo& info) {
6843 v8::Handle<v8::Array> result = v8::Array::New(1);
6844 result->Set(0, v8_str("x"));
6845 return result;
6846}
6847
6848
6849THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
6850 v8::HandleScope handle_scope;
6851 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
6852
6853 obj_template->Set(v8_str("x"), v8::Integer::New(42));
6854 obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
6855 NamedPropertyEnumerator);
6856
6857 LocalContext context;
6858 v8::Handle<v8::Object> global = context->Global();
6859 global->Set(v8_str("object"), obj_template->NewInstance());
6860
6861 v8::Handle<Value> value =
6862 CompileRun("Object.getOwnPropertyNames(object).join(',')");
6863 CHECK_EQ(v8_str("x"), value);
6864}
6865
6866
Steve Blocka7e24c12009-10-30 11:49:00 +00006867static v8::Handle<Value> ConstTenGetter(Local<String> name,
6868 const AccessorInfo& info) {
6869 return v8_num(10);
6870}
6871
6872
6873THREADED_TEST(CrossDomainAccessors) {
6874 v8::HandleScope handle_scope;
6875
6876 v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
6877
6878 v8::Handle<v8::ObjectTemplate> global_template =
6879 func_template->InstanceTemplate();
6880
6881 v8::Handle<v8::ObjectTemplate> proto_template =
6882 func_template->PrototypeTemplate();
6883
6884 // Add an accessor to proto that's accessible by cross-domain JS code.
6885 proto_template->SetAccessor(v8_str("accessible"),
6886 ConstTenGetter, 0,
6887 v8::Handle<Value>(),
6888 v8::ALL_CAN_READ);
6889
6890 // Add an accessor that is not accessible by cross-domain JS code.
6891 global_template->SetAccessor(v8_str("unreachable"),
6892 UnreachableGetter, 0,
6893 v8::Handle<Value>(),
6894 v8::DEFAULT);
6895
6896 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6897 context0->Enter();
6898
6899 Local<v8::Object> global = context0->Global();
6900 // Add a normal property that shadows 'accessible'
6901 global->Set(v8_str("accessible"), v8_num(11));
6902
6903 // Enter a new context.
6904 v8::HandleScope scope1;
6905 v8::Persistent<Context> context1 = Context::New();
6906 context1->Enter();
6907
6908 v8::Handle<v8::Object> global1 = context1->Global();
6909 global1->Set(v8_str("other"), global);
6910
6911 // Should return 10, instead of 11
6912 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
6913 CHECK(value->IsNumber());
6914 CHECK_EQ(10, value->Int32Value());
6915
6916 value = v8_compile("other.unreachable")->Run();
6917 CHECK(value->IsUndefined());
6918
6919 context1->Exit();
6920 context0->Exit();
6921 context1.Dispose();
6922 context0.Dispose();
6923}
6924
6925
6926static int named_access_count = 0;
6927static int indexed_access_count = 0;
6928
6929static bool NamedAccessCounter(Local<v8::Object> global,
6930 Local<Value> name,
6931 v8::AccessType type,
6932 Local<Value> data) {
6933 named_access_count++;
6934 return true;
6935}
6936
6937
6938static bool IndexedAccessCounter(Local<v8::Object> global,
6939 uint32_t key,
6940 v8::AccessType type,
6941 Local<Value> data) {
6942 indexed_access_count++;
6943 return true;
6944}
6945
6946
6947// This one is too easily disturbed by other tests.
6948TEST(AccessControlIC) {
6949 named_access_count = 0;
6950 indexed_access_count = 0;
6951
6952 v8::HandleScope handle_scope;
6953
6954 // Create an environment.
6955 v8::Persistent<Context> context0 = Context::New();
6956 context0->Enter();
6957
6958 // Create an object that requires access-check functions to be
6959 // called for cross-domain access.
6960 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
6961 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
6962 IndexedAccessCounter);
6963 Local<v8::Object> object = object_template->NewInstance();
6964
6965 v8::HandleScope scope1;
6966
6967 // Create another environment.
6968 v8::Persistent<Context> context1 = Context::New();
6969 context1->Enter();
6970
6971 // Make easy access to the object from the other environment.
6972 v8::Handle<v8::Object> global1 = context1->Global();
6973 global1->Set(v8_str("obj"), object);
6974
6975 v8::Handle<Value> value;
6976
6977 // Check that the named access-control function is called every time.
6978 CompileRun("function testProp(obj) {"
6979 " for (var i = 0; i < 10; i++) obj.prop = 1;"
6980 " for (var j = 0; j < 10; j++) obj.prop;"
6981 " return obj.prop"
6982 "}");
6983 value = CompileRun("testProp(obj)");
6984 CHECK(value->IsNumber());
6985 CHECK_EQ(1, value->Int32Value());
6986 CHECK_EQ(21, named_access_count);
6987
6988 // Check that the named access-control function is called every time.
6989 CompileRun("var p = 'prop';"
6990 "function testKeyed(obj) {"
6991 " for (var i = 0; i < 10; i++) obj[p] = 1;"
6992 " for (var j = 0; j < 10; j++) obj[p];"
6993 " return obj[p];"
6994 "}");
6995 // Use obj which requires access checks. No inline caching is used
6996 // in that case.
6997 value = CompileRun("testKeyed(obj)");
6998 CHECK(value->IsNumber());
6999 CHECK_EQ(1, value->Int32Value());
7000 CHECK_EQ(42, named_access_count);
7001 // Force the inline caches into generic state and try again.
7002 CompileRun("testKeyed({ a: 0 })");
7003 CompileRun("testKeyed({ b: 0 })");
7004 value = CompileRun("testKeyed(obj)");
7005 CHECK(value->IsNumber());
7006 CHECK_EQ(1, value->Int32Value());
7007 CHECK_EQ(63, named_access_count);
7008
7009 // Check that the indexed access-control function is called every time.
7010 CompileRun("function testIndexed(obj) {"
7011 " for (var i = 0; i < 10; i++) obj[0] = 1;"
7012 " for (var j = 0; j < 10; j++) obj[0];"
7013 " return obj[0]"
7014 "}");
7015 value = CompileRun("testIndexed(obj)");
7016 CHECK(value->IsNumber());
7017 CHECK_EQ(1, value->Int32Value());
7018 CHECK_EQ(21, indexed_access_count);
7019 // Force the inline caches into generic state.
7020 CompileRun("testIndexed(new Array(1))");
7021 // Test that the indexed access check is called.
7022 value = CompileRun("testIndexed(obj)");
7023 CHECK(value->IsNumber());
7024 CHECK_EQ(1, value->Int32Value());
7025 CHECK_EQ(42, indexed_access_count);
7026
7027 // Check that the named access check is called when invoking
7028 // functions on an object that requires access checks.
7029 CompileRun("obj.f = function() {}");
7030 CompileRun("function testCallNormal(obj) {"
7031 " for (var i = 0; i < 10; i++) obj.f();"
7032 "}");
7033 CompileRun("testCallNormal(obj)");
7034 CHECK_EQ(74, named_access_count);
7035
7036 // Force obj into slow case.
7037 value = CompileRun("delete obj.prop");
7038 CHECK(value->BooleanValue());
7039 // Force inline caches into dictionary probing mode.
7040 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
7041 // Test that the named access check is called.
7042 value = CompileRun("testProp(obj);");
7043 CHECK(value->IsNumber());
7044 CHECK_EQ(1, value->Int32Value());
7045 CHECK_EQ(96, named_access_count);
7046
7047 // Force the call inline cache into dictionary probing mode.
7048 CompileRun("o.f = function() {}; testCallNormal(o)");
7049 // Test that the named access check is still called for each
7050 // invocation of the function.
7051 value = CompileRun("testCallNormal(obj)");
7052 CHECK_EQ(106, named_access_count);
7053
7054 context1->Exit();
7055 context0->Exit();
7056 context1.Dispose();
7057 context0.Dispose();
7058}
7059
7060
7061static bool NamedAccessFlatten(Local<v8::Object> global,
7062 Local<Value> name,
7063 v8::AccessType type,
7064 Local<Value> data) {
7065 char buf[100];
7066 int len;
7067
7068 CHECK(name->IsString());
7069
7070 memset(buf, 0x1, sizeof(buf));
Steve Block6ded16b2010-05-10 14:33:55 +01007071 len = name.As<String>()->WriteAscii(buf);
Steve Blocka7e24c12009-10-30 11:49:00 +00007072 CHECK_EQ(4, len);
7073
7074 uint16_t buf2[100];
7075
7076 memset(buf, 0x1, sizeof(buf));
Steve Block6ded16b2010-05-10 14:33:55 +01007077 len = name.As<String>()->Write(buf2);
Steve Blocka7e24c12009-10-30 11:49:00 +00007078 CHECK_EQ(4, len);
7079
7080 return true;
7081}
7082
7083
7084static bool IndexedAccessFlatten(Local<v8::Object> global,
7085 uint32_t key,
7086 v8::AccessType type,
7087 Local<Value> data) {
7088 return true;
7089}
7090
7091
7092// Regression test. In access checks, operations that may cause
7093// garbage collection are not allowed. It used to be the case that
7094// using the Write operation on a string could cause a garbage
7095// collection due to flattening of the string. This is no longer the
7096// case.
7097THREADED_TEST(AccessControlFlatten) {
7098 named_access_count = 0;
7099 indexed_access_count = 0;
7100
7101 v8::HandleScope handle_scope;
7102
7103 // Create an environment.
7104 v8::Persistent<Context> context0 = Context::New();
7105 context0->Enter();
7106
7107 // Create an object that requires access-check functions to be
7108 // called for cross-domain access.
7109 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
7110 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
7111 IndexedAccessFlatten);
7112 Local<v8::Object> object = object_template->NewInstance();
7113
7114 v8::HandleScope scope1;
7115
7116 // Create another environment.
7117 v8::Persistent<Context> context1 = Context::New();
7118 context1->Enter();
7119
7120 // Make easy access to the object from the other environment.
7121 v8::Handle<v8::Object> global1 = context1->Global();
7122 global1->Set(v8_str("obj"), object);
7123
7124 v8::Handle<Value> value;
7125
7126 value = v8_compile("var p = 'as' + 'df';")->Run();
7127 value = v8_compile("obj[p];")->Run();
7128
7129 context1->Exit();
7130 context0->Exit();
7131 context1.Dispose();
7132 context0.Dispose();
7133}
7134
7135
7136static v8::Handle<Value> AccessControlNamedGetter(
7137 Local<String>, const AccessorInfo&) {
7138 return v8::Integer::New(42);
7139}
7140
7141
7142static v8::Handle<Value> AccessControlNamedSetter(
7143 Local<String>, Local<Value> value, const AccessorInfo&) {
7144 return value;
7145}
7146
7147
7148static v8::Handle<Value> AccessControlIndexedGetter(
7149 uint32_t index,
7150 const AccessorInfo& info) {
7151 return v8_num(42);
7152}
7153
7154
7155static v8::Handle<Value> AccessControlIndexedSetter(
7156 uint32_t, Local<Value> value, const AccessorInfo&) {
7157 return value;
7158}
7159
7160
7161THREADED_TEST(AccessControlInterceptorIC) {
7162 named_access_count = 0;
7163 indexed_access_count = 0;
7164
7165 v8::HandleScope handle_scope;
7166
7167 // Create an environment.
7168 v8::Persistent<Context> context0 = Context::New();
7169 context0->Enter();
7170
7171 // Create an object that requires access-check functions to be
7172 // called for cross-domain access. The object also has interceptors
7173 // interceptor.
7174 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
7175 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
7176 IndexedAccessCounter);
7177 object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
7178 AccessControlNamedSetter);
7179 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
7180 AccessControlIndexedSetter);
7181 Local<v8::Object> object = object_template->NewInstance();
7182
7183 v8::HandleScope scope1;
7184
7185 // Create another environment.
7186 v8::Persistent<Context> context1 = Context::New();
7187 context1->Enter();
7188
7189 // Make easy access to the object from the other environment.
7190 v8::Handle<v8::Object> global1 = context1->Global();
7191 global1->Set(v8_str("obj"), object);
7192
7193 v8::Handle<Value> value;
7194
7195 // Check that the named access-control function is called every time
7196 // eventhough there is an interceptor on the object.
7197 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
7198 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
7199 "obj.x")->Run();
7200 CHECK(value->IsNumber());
7201 CHECK_EQ(42, value->Int32Value());
7202 CHECK_EQ(21, named_access_count);
7203
7204 value = v8_compile("var p = 'x';")->Run();
7205 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
7206 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
7207 "obj[p]")->Run();
7208 CHECK(value->IsNumber());
7209 CHECK_EQ(42, value->Int32Value());
7210 CHECK_EQ(42, named_access_count);
7211
7212 // Check that the indexed access-control function is called every
7213 // time eventhough there is an interceptor on the object.
7214 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
7215 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
7216 "obj[0]")->Run();
7217 CHECK(value->IsNumber());
7218 CHECK_EQ(42, value->Int32Value());
7219 CHECK_EQ(21, indexed_access_count);
7220
7221 context1->Exit();
7222 context0->Exit();
7223 context1.Dispose();
7224 context0.Dispose();
7225}
7226
7227
7228THREADED_TEST(Version) {
7229 v8::V8::GetVersion();
7230}
7231
7232
7233static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
7234 ApiTestFuzzer::Fuzz();
7235 return v8_num(12);
7236}
7237
7238
7239THREADED_TEST(InstanceProperties) {
7240 v8::HandleScope handle_scope;
7241 LocalContext context;
7242
7243 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7244 Local<ObjectTemplate> instance = t->InstanceTemplate();
7245
7246 instance->Set(v8_str("x"), v8_num(42));
7247 instance->Set(v8_str("f"),
7248 v8::FunctionTemplate::New(InstanceFunctionCallback));
7249
7250 Local<Value> o = t->GetFunction()->NewInstance();
7251
7252 context->Global()->Set(v8_str("i"), o);
7253 Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
7254 CHECK_EQ(42, value->Int32Value());
7255
7256 value = Script::Compile(v8_str("i.f()"))->Run();
7257 CHECK_EQ(12, value->Int32Value());
7258}
7259
7260
7261static v8::Handle<Value>
7262GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
7263 ApiTestFuzzer::Fuzz();
7264 return v8::Handle<Value>();
7265}
7266
7267
7268THREADED_TEST(GlobalObjectInstanceProperties) {
7269 v8::HandleScope handle_scope;
7270
7271 Local<Value> global_object;
7272
7273 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7274 t->InstanceTemplate()->SetNamedPropertyHandler(
7275 GlobalObjectInstancePropertiesGet);
7276 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7277 instance_template->Set(v8_str("x"), v8_num(42));
7278 instance_template->Set(v8_str("f"),
7279 v8::FunctionTemplate::New(InstanceFunctionCallback));
7280
Ben Murdochb0fe1622011-05-05 13:52:32 +01007281 // The script to check how Crankshaft compiles missing global function
7282 // invocations. function g is not defined and should throw on call.
7283 const char* script =
7284 "function wrapper(call) {"
7285 " var x = 0, y = 1;"
7286 " for (var i = 0; i < 1000; i++) {"
7287 " x += i * 100;"
7288 " y += i * 100;"
7289 " }"
7290 " if (call) g();"
7291 "}"
7292 "for (var i = 0; i < 17; i++) wrapper(false);"
7293 "var thrown = 0;"
7294 "try { wrapper(true); } catch (e) { thrown = 1; };"
7295 "thrown";
7296
Steve Blocka7e24c12009-10-30 11:49:00 +00007297 {
7298 LocalContext env(NULL, instance_template);
7299 // Hold on to the global object so it can be used again in another
7300 // environment initialization.
7301 global_object = env->Global();
7302
7303 Local<Value> value = Script::Compile(v8_str("x"))->Run();
7304 CHECK_EQ(42, value->Int32Value());
7305 value = Script::Compile(v8_str("f()"))->Run();
7306 CHECK_EQ(12, value->Int32Value());
Ben Murdochb0fe1622011-05-05 13:52:32 +01007307 value = Script::Compile(v8_str(script))->Run();
7308 CHECK_EQ(1, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00007309 }
7310
7311 {
7312 // Create new environment reusing the global object.
7313 LocalContext env(NULL, instance_template, global_object);
7314 Local<Value> value = Script::Compile(v8_str("x"))->Run();
7315 CHECK_EQ(42, value->Int32Value());
7316 value = Script::Compile(v8_str("f()"))->Run();
7317 CHECK_EQ(12, value->Int32Value());
Ben Murdochb0fe1622011-05-05 13:52:32 +01007318 value = Script::Compile(v8_str(script))->Run();
7319 CHECK_EQ(1, value->Int32Value());
7320 }
7321}
7322
7323
7324THREADED_TEST(CallKnownGlobalReceiver) {
7325 v8::HandleScope handle_scope;
7326
7327 Local<Value> global_object;
7328
7329 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7330 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7331
7332 // The script to check that we leave global object not
7333 // global object proxy on stack when we deoptimize from inside
7334 // arguments evaluation.
7335 // To provoke error we need to both force deoptimization
7336 // from arguments evaluation and to force CallIC to take
7337 // CallIC_Miss code path that can't cope with global proxy.
7338 const char* script =
7339 "function bar(x, y) { try { } finally { } }"
7340 "function baz(x) { try { } finally { } }"
7341 "function bom(x) { try { } finally { } }"
7342 "function foo(x) { bar([x], bom(2)); }"
7343 "for (var i = 0; i < 10000; i++) foo(1);"
7344 "foo";
7345
7346 Local<Value> foo;
7347 {
7348 LocalContext env(NULL, instance_template);
7349 // Hold on to the global object so it can be used again in another
7350 // environment initialization.
7351 global_object = env->Global();
7352 foo = Script::Compile(v8_str(script))->Run();
7353 }
7354
7355 {
7356 // Create new environment reusing the global object.
7357 LocalContext env(NULL, instance_template, global_object);
7358 env->Global()->Set(v8_str("foo"), foo);
Ben Murdochc7cc0282012-03-05 14:35:55 +00007359 Script::Compile(v8_str("foo()"))->Run();
Steve Blocka7e24c12009-10-30 11:49:00 +00007360 }
7361}
7362
7363
7364static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
7365 ApiTestFuzzer::Fuzz();
7366 return v8_num(42);
7367}
7368
7369
7370static int shadow_y;
7371static int shadow_y_setter_call_count;
7372static int shadow_y_getter_call_count;
7373
7374
7375static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
7376 shadow_y_setter_call_count++;
7377 shadow_y = 42;
7378}
7379
7380
7381static v8::Handle<Value> ShadowYGetter(Local<String> name,
7382 const AccessorInfo& info) {
7383 ApiTestFuzzer::Fuzz();
7384 shadow_y_getter_call_count++;
7385 return v8_num(shadow_y);
7386}
7387
7388
7389static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
7390 const AccessorInfo& info) {
7391 return v8::Handle<Value>();
7392}
7393
7394
7395static v8::Handle<Value> ShadowNamedGet(Local<String> key,
7396 const AccessorInfo&) {
7397 return v8::Handle<Value>();
7398}
7399
7400
7401THREADED_TEST(ShadowObject) {
7402 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
7403 v8::HandleScope handle_scope;
7404
7405 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
7406 LocalContext context(NULL, global_template);
7407
7408 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7409 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
7410 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
7411 Local<ObjectTemplate> proto = t->PrototypeTemplate();
7412 Local<ObjectTemplate> instance = t->InstanceTemplate();
7413
7414 // Only allow calls of f on instances of t.
7415 Local<v8::Signature> signature = v8::Signature::New(t);
7416 proto->Set(v8_str("f"),
7417 v8::FunctionTemplate::New(ShadowFunctionCallback,
7418 Local<Value>(),
7419 signature));
7420 proto->Set(v8_str("x"), v8_num(12));
7421
7422 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
7423
7424 Local<Value> o = t->GetFunction()->NewInstance();
7425 context->Global()->Set(v8_str("__proto__"), o);
7426
7427 Local<Value> value =
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007428 Script::Compile(v8_str("this.propertyIsEnumerable(0)"))->Run();
Steve Blocka7e24c12009-10-30 11:49:00 +00007429 CHECK(value->IsBoolean());
7430 CHECK(!value->BooleanValue());
7431
7432 value = Script::Compile(v8_str("x"))->Run();
7433 CHECK_EQ(12, value->Int32Value());
7434
7435 value = Script::Compile(v8_str("f()"))->Run();
7436 CHECK_EQ(42, value->Int32Value());
7437
7438 Script::Compile(v8_str("y = 42"))->Run();
7439 CHECK_EQ(1, shadow_y_setter_call_count);
7440 value = Script::Compile(v8_str("y"))->Run();
7441 CHECK_EQ(1, shadow_y_getter_call_count);
7442 CHECK_EQ(42, value->Int32Value());
7443}
7444
7445
7446THREADED_TEST(HiddenPrototype) {
7447 v8::HandleScope handle_scope;
7448 LocalContext context;
7449
7450 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
7451 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
7452 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
7453 t1->SetHiddenPrototype(true);
7454 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
7455 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
7456 t2->SetHiddenPrototype(true);
7457 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
7458 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
7459 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
7460
7461 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
7462 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
7463 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
7464 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
7465
7466 // Setting the prototype on an object skips hidden prototypes.
7467 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7468 o0->Set(v8_str("__proto__"), o1);
7469 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7470 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7471 o0->Set(v8_str("__proto__"), o2);
7472 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7473 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7474 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7475 o0->Set(v8_str("__proto__"), o3);
7476 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7477 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7478 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7479 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
7480
7481 // Getting the prototype of o0 should get the first visible one
7482 // which is o3. Therefore, z should not be defined on the prototype
7483 // object.
7484 Local<Value> proto = o0->Get(v8_str("__proto__"));
7485 CHECK(proto->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01007486 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
Steve Blocka7e24c12009-10-30 11:49:00 +00007487}
7488
7489
Andrei Popescu402d9372010-02-26 13:31:12 +00007490THREADED_TEST(SetPrototype) {
7491 v8::HandleScope handle_scope;
7492 LocalContext context;
7493
7494 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
7495 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
7496 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
7497 t1->SetHiddenPrototype(true);
7498 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
7499 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
7500 t2->SetHiddenPrototype(true);
7501 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
7502 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
7503 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
7504
7505 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
7506 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
7507 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
7508 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
7509
7510 // Setting the prototype on an object does not skip hidden prototypes.
7511 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7512 CHECK(o0->SetPrototype(o1));
7513 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7514 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7515 CHECK(o1->SetPrototype(o2));
7516 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7517 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7518 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7519 CHECK(o2->SetPrototype(o3));
7520 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7521 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7522 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7523 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
7524
7525 // Getting the prototype of o0 should get the first visible one
7526 // which is o3. Therefore, z should not be defined on the prototype
7527 // object.
7528 Local<Value> proto = o0->Get(v8_str("__proto__"));
7529 CHECK(proto->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01007530 CHECK_EQ(proto.As<v8::Object>(), o3);
Andrei Popescu402d9372010-02-26 13:31:12 +00007531
7532 // However, Object::GetPrototype ignores hidden prototype.
7533 Local<Value> proto0 = o0->GetPrototype();
7534 CHECK(proto0->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01007535 CHECK_EQ(proto0.As<v8::Object>(), o1);
Andrei Popescu402d9372010-02-26 13:31:12 +00007536
7537 Local<Value> proto1 = o1->GetPrototype();
7538 CHECK(proto1->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01007539 CHECK_EQ(proto1.As<v8::Object>(), o2);
Andrei Popescu402d9372010-02-26 13:31:12 +00007540
7541 Local<Value> proto2 = o2->GetPrototype();
7542 CHECK(proto2->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01007543 CHECK_EQ(proto2.As<v8::Object>(), o3);
Andrei Popescu402d9372010-02-26 13:31:12 +00007544}
7545
7546
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007547// Getting property names of an object with a prototype chain that
7548// triggers dictionary elements in GetLocalPropertyNames() shouldn't
7549// crash the runtime.
7550THREADED_TEST(Regress91517) {
7551 i::FLAG_allow_natives_syntax = true;
7552 v8::HandleScope handle_scope;
7553 LocalContext context;
7554
7555 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
7556 t1->SetHiddenPrototype(true);
7557 t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
7558 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
7559 t2->SetHiddenPrototype(true);
7560 t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
7561 t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New());
7562 t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
7563 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
7564 t3->SetHiddenPrototype(true);
7565 t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
7566 Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New();
7567 t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
7568
7569 // Force dictionary-based properties.
7570 i::ScopedVector<char> name_buf(1024);
7571 for (int i = 1; i <= 1000; i++) {
7572 i::OS::SNPrintF(name_buf, "sdf%d", i);
7573 t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
7574 }
7575
7576 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
7577 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
7578 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
7579 Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
7580
7581 // Create prototype chain of hidden prototypes.
7582 CHECK(o4->SetPrototype(o3));
7583 CHECK(o3->SetPrototype(o2));
7584 CHECK(o2->SetPrototype(o1));
7585
7586 // Call the runtime version of GetLocalPropertyNames() on the natively
7587 // created object through JavaScript.
7588 context->Global()->Set(v8_str("obj"), o4);
7589 CompileRun("var names = %GetLocalPropertyNames(obj);");
7590
7591 ExpectInt32("names.length", 1006);
7592 ExpectTrue("names.indexOf(\"baz\") >= 0");
7593 ExpectTrue("names.indexOf(\"boo\") >= 0");
7594 ExpectTrue("names.indexOf(\"foo\") >= 0");
7595 ExpectTrue("names.indexOf(\"fuz1\") >= 0");
7596 ExpectTrue("names.indexOf(\"fuz2\") >= 0");
7597 ExpectFalse("names[1005] == undefined");
7598}
7599
7600
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007601THREADED_TEST(FunctionReadOnlyPrototype) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007602 v8::HandleScope handle_scope;
7603 LocalContext context;
7604
7605 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007606 t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
7607 t1->ReadOnlyPrototype();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007608 context->Global()->Set(v8_str("func1"), t1->GetFunction());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007609 // Configured value of ReadOnly flag.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007610 CHECK(CompileRun(
7611 "(function() {"
7612 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007613 " return (descriptor['writable'] == false);"
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007614 "})()")->BooleanValue());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007615 CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
7616 CHECK_EQ(42,
7617 CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007618
7619 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007620 t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007621 context->Global()->Set(v8_str("func2"), t2->GetFunction());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007622 // Default value of ReadOnly flag.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007623 CHECK(CompileRun(
7624 "(function() {"
7625 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007626 " return (descriptor['writable'] == true);"
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007627 "})()")->BooleanValue());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007628 CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007629}
7630
7631
Andrei Popescu402d9372010-02-26 13:31:12 +00007632THREADED_TEST(SetPrototypeThrows) {
7633 v8::HandleScope handle_scope;
7634 LocalContext context;
7635
7636 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7637
7638 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
7639 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
7640
7641 CHECK(o0->SetPrototype(o1));
7642 // If setting the prototype leads to the cycle, SetPrototype should
7643 // return false and keep VM in sane state.
7644 v8::TryCatch try_catch;
7645 CHECK(!o1->SetPrototype(o0));
7646 CHECK(!try_catch.HasCaught());
Steve Block44f0eee2011-05-26 01:26:41 +01007647 ASSERT(!i::Isolate::Current()->has_pending_exception());
Andrei Popescu402d9372010-02-26 13:31:12 +00007648
7649 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
7650}
7651
7652
Steve Blocka7e24c12009-10-30 11:49:00 +00007653THREADED_TEST(GetterSetterExceptions) {
7654 v8::HandleScope handle_scope;
7655 LocalContext context;
7656 CompileRun(
7657 "function Foo() { };"
7658 "function Throw() { throw 5; };"
7659 "var x = { };"
7660 "x.__defineSetter__('set', Throw);"
7661 "x.__defineGetter__('get', Throw);");
7662 Local<v8::Object> x =
7663 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
7664 v8::TryCatch try_catch;
7665 x->Set(v8_str("set"), v8::Integer::New(8));
7666 x->Get(v8_str("get"));
7667 x->Set(v8_str("set"), v8::Integer::New(8));
7668 x->Get(v8_str("get"));
7669 x->Set(v8_str("set"), v8::Integer::New(8));
7670 x->Get(v8_str("get"));
7671 x->Set(v8_str("set"), v8::Integer::New(8));
7672 x->Get(v8_str("get"));
7673}
7674
7675
7676THREADED_TEST(Constructor) {
7677 v8::HandleScope handle_scope;
7678 LocalContext context;
7679 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7680 templ->SetClassName(v8_str("Fun"));
7681 Local<Function> cons = templ->GetFunction();
7682 context->Global()->Set(v8_str("Fun"), cons);
7683 Local<v8::Object> inst = cons->NewInstance();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007684 i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
Ben Murdochc7cc0282012-03-05 14:35:55 +00007685 CHECK(obj->IsJSObject());
Steve Blocka7e24c12009-10-30 11:49:00 +00007686 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
7687 CHECK(value->BooleanValue());
7688}
7689
Ben Murdoch257744e2011-11-30 15:57:28 +00007690
7691static Handle<Value> ConstructorCallback(const Arguments& args) {
7692 ApiTestFuzzer::Fuzz();
7693 Local<Object> This;
7694
7695 if (args.IsConstructCall()) {
7696 Local<Object> Holder = args.Holder();
7697 This = Object::New();
7698 Local<Value> proto = Holder->GetPrototype();
7699 if (proto->IsObject()) {
7700 This->SetPrototype(proto);
7701 }
7702 } else {
7703 This = args.This();
7704 }
7705
7706 This->Set(v8_str("a"), args[0]);
7707 return This;
7708}
7709
7710
7711static Handle<Value> FakeConstructorCallback(const Arguments& args) {
7712 ApiTestFuzzer::Fuzz();
7713 return args[0];
7714}
7715
7716
7717THREADED_TEST(ConstructorForObject) {
7718 v8::HandleScope handle_scope;
7719 LocalContext context;
7720
7721 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7722 instance_template->SetCallAsFunctionHandler(ConstructorCallback);
7723 Local<Object> instance = instance_template->NewInstance();
7724 context->Global()->Set(v8_str("obj"), instance);
7725 v8::TryCatch try_catch;
7726 Local<Value> value;
7727 CHECK(!try_catch.HasCaught());
7728
7729 // Call the Object's constructor with a 32-bit signed integer.
7730 value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
7731 CHECK(!try_catch.HasCaught());
7732 CHECK(value->IsInt32());
7733 CHECK_EQ(28, value->Int32Value());
7734
7735 Local<Value> args1[] = { v8_num(28) };
7736 Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
7737 CHECK(value_obj1->IsObject());
7738 Local<Object> object1 = Local<Object>::Cast(value_obj1);
7739 value = object1->Get(v8_str("a"));
7740 CHECK(value->IsInt32());
7741 CHECK(!try_catch.HasCaught());
7742 CHECK_EQ(28, value->Int32Value());
7743
7744 // Call the Object's constructor with a String.
7745 value = CompileRun(
7746 "(function() { var o = new obj('tipli'); return o.a; })()");
7747 CHECK(!try_catch.HasCaught());
7748 CHECK(value->IsString());
7749 String::AsciiValue string_value1(value->ToString());
7750 CHECK_EQ("tipli", *string_value1);
7751
7752 Local<Value> args2[] = { v8_str("tipli") };
7753 Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
7754 CHECK(value_obj2->IsObject());
7755 Local<Object> object2 = Local<Object>::Cast(value_obj2);
7756 value = object2->Get(v8_str("a"));
7757 CHECK(!try_catch.HasCaught());
7758 CHECK(value->IsString());
7759 String::AsciiValue string_value2(value->ToString());
7760 CHECK_EQ("tipli", *string_value2);
7761
7762 // Call the Object's constructor with a Boolean.
7763 value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
7764 CHECK(!try_catch.HasCaught());
7765 CHECK(value->IsBoolean());
7766 CHECK_EQ(true, value->BooleanValue());
7767
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007768 Handle<Value> args3[] = { v8::True() };
Ben Murdoch257744e2011-11-30 15:57:28 +00007769 Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
7770 CHECK(value_obj3->IsObject());
7771 Local<Object> object3 = Local<Object>::Cast(value_obj3);
7772 value = object3->Get(v8_str("a"));
7773 CHECK(!try_catch.HasCaught());
7774 CHECK(value->IsBoolean());
7775 CHECK_EQ(true, value->BooleanValue());
7776
7777 // Call the Object's constructor with undefined.
7778 Handle<Value> args4[] = { v8::Undefined() };
7779 Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
7780 CHECK(value_obj4->IsObject());
7781 Local<Object> object4 = Local<Object>::Cast(value_obj4);
7782 value = object4->Get(v8_str("a"));
7783 CHECK(!try_catch.HasCaught());
7784 CHECK(value->IsUndefined());
7785
7786 // Call the Object's constructor with null.
7787 Handle<Value> args5[] = { v8::Null() };
7788 Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
7789 CHECK(value_obj5->IsObject());
7790 Local<Object> object5 = Local<Object>::Cast(value_obj5);
7791 value = object5->Get(v8_str("a"));
7792 CHECK(!try_catch.HasCaught());
7793 CHECK(value->IsNull());
7794 }
7795
7796 // Check exception handling when there is no constructor set for the Object.
7797 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7798 Local<Object> instance = instance_template->NewInstance();
7799 context->Global()->Set(v8_str("obj2"), instance);
7800 v8::TryCatch try_catch;
7801 Local<Value> value;
7802 CHECK(!try_catch.HasCaught());
7803
7804 value = CompileRun("new obj2(28)");
7805 CHECK(try_catch.HasCaught());
7806 String::AsciiValue exception_value1(try_catch.Exception());
7807 CHECK_EQ("TypeError: object is not a function", *exception_value1);
7808 try_catch.Reset();
7809
7810 Local<Value> args[] = { v8_num(29) };
7811 value = instance->CallAsConstructor(1, args);
7812 CHECK(try_catch.HasCaught());
7813 String::AsciiValue exception_value2(try_catch.Exception());
7814 CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
7815 try_catch.Reset();
7816 }
7817
7818 // Check the case when constructor throws exception.
7819 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7820 instance_template->SetCallAsFunctionHandler(ThrowValue);
7821 Local<Object> instance = instance_template->NewInstance();
7822 context->Global()->Set(v8_str("obj3"), instance);
7823 v8::TryCatch try_catch;
7824 Local<Value> value;
7825 CHECK(!try_catch.HasCaught());
7826
7827 value = CompileRun("new obj3(22)");
7828 CHECK(try_catch.HasCaught());
7829 String::AsciiValue exception_value1(try_catch.Exception());
7830 CHECK_EQ("22", *exception_value1);
7831 try_catch.Reset();
7832
7833 Local<Value> args[] = { v8_num(23) };
7834 value = instance->CallAsConstructor(1, args);
7835 CHECK(try_catch.HasCaught());
7836 String::AsciiValue exception_value2(try_catch.Exception());
7837 CHECK_EQ("23", *exception_value2);
7838 try_catch.Reset();
7839 }
7840
7841 // Check whether constructor returns with an object or non-object.
7842 { Local<FunctionTemplate> function_template =
7843 FunctionTemplate::New(FakeConstructorCallback);
7844 Local<Function> function = function_template->GetFunction();
7845 Local<Object> instance1 = function;
7846 context->Global()->Set(v8_str("obj4"), instance1);
7847 v8::TryCatch try_catch;
7848 Local<Value> value;
7849 CHECK(!try_catch.HasCaught());
7850
7851 CHECK(instance1->IsObject());
7852 CHECK(instance1->IsFunction());
7853
7854 value = CompileRun("new obj4(28)");
7855 CHECK(!try_catch.HasCaught());
7856 CHECK(value->IsObject());
7857
7858 Local<Value> args1[] = { v8_num(28) };
7859 value = instance1->CallAsConstructor(1, args1);
7860 CHECK(!try_catch.HasCaught());
7861 CHECK(value->IsObject());
7862
7863 Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7864 instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
7865 Local<Object> instance2 = instance_template->NewInstance();
7866 context->Global()->Set(v8_str("obj5"), instance2);
7867 CHECK(!try_catch.HasCaught());
7868
7869 CHECK(instance2->IsObject());
7870 CHECK(!instance2->IsFunction());
7871
7872 value = CompileRun("new obj5(28)");
7873 CHECK(!try_catch.HasCaught());
7874 CHECK(!value->IsObject());
7875
7876 Local<Value> args2[] = { v8_num(28) };
7877 value = instance2->CallAsConstructor(1, args2);
7878 CHECK(!try_catch.HasCaught());
7879 CHECK(!value->IsObject());
7880 }
7881}
7882
7883
Steve Blocka7e24c12009-10-30 11:49:00 +00007884THREADED_TEST(FunctionDescriptorException) {
7885 v8::HandleScope handle_scope;
7886 LocalContext context;
7887 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7888 templ->SetClassName(v8_str("Fun"));
7889 Local<Function> cons = templ->GetFunction();
7890 context->Global()->Set(v8_str("Fun"), cons);
7891 Local<Value> value = CompileRun(
7892 "function test() {"
7893 " try {"
7894 " (new Fun()).blah()"
7895 " } catch (e) {"
7896 " var str = String(e);"
7897 " if (str.indexOf('TypeError') == -1) return 1;"
7898 " if (str.indexOf('[object Fun]') != -1) return 2;"
Steve Block1e0659c2011-05-24 12:43:12 +01007899 " if (str.indexOf('#<Fun>') == -1) return 3;"
Steve Blocka7e24c12009-10-30 11:49:00 +00007900 " return 0;"
7901 " }"
7902 " return 4;"
7903 "}"
7904 "test();");
7905 CHECK_EQ(0, value->Int32Value());
7906}
7907
7908
7909THREADED_TEST(EvalAliasedDynamic) {
7910 v8::HandleScope scope;
7911 LocalContext current;
7912
7913 // Tests where aliased eval can only be resolved dynamically.
7914 Local<Script> script =
7915 Script::Compile(v8_str("function f(x) { "
7916 " var foo = 2;"
7917 " with (x) { return eval('foo'); }"
7918 "}"
7919 "foo = 0;"
7920 "result1 = f(new Object());"
7921 "result2 = f(this);"
7922 "var x = new Object();"
7923 "x.eval = function(x) { return 1; };"
7924 "result3 = f(x);"));
7925 script->Run();
7926 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
7927 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
7928 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
7929
7930 v8::TryCatch try_catch;
7931 script =
7932 Script::Compile(v8_str("function f(x) { "
7933 " var bar = 2;"
7934 " with (x) { return eval('bar'); }"
7935 "}"
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007936 "result4 = f(this)"));
Steve Blocka7e24c12009-10-30 11:49:00 +00007937 script->Run();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007938 CHECK(!try_catch.HasCaught());
7939 CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
7940
Steve Blocka7e24c12009-10-30 11:49:00 +00007941 try_catch.Reset();
7942}
7943
7944
7945THREADED_TEST(CrossEval) {
7946 v8::HandleScope scope;
7947 LocalContext other;
7948 LocalContext current;
7949
7950 Local<String> token = v8_str("<security token>");
7951 other->SetSecurityToken(token);
7952 current->SetSecurityToken(token);
7953
Ben Murdochc7cc0282012-03-05 14:35:55 +00007954 // Set up reference from current to other.
Steve Blocka7e24c12009-10-30 11:49:00 +00007955 current->Global()->Set(v8_str("other"), other->Global());
7956
7957 // Check that new variables are introduced in other context.
7958 Local<Script> script =
7959 Script::Compile(v8_str("other.eval('var foo = 1234')"));
7960 script->Run();
7961 Local<Value> foo = other->Global()->Get(v8_str("foo"));
7962 CHECK_EQ(1234, foo->Int32Value());
7963 CHECK(!current->Global()->Has(v8_str("foo")));
7964
7965 // Check that writing to non-existing properties introduces them in
7966 // the other context.
7967 script =
7968 Script::Compile(v8_str("other.eval('na = 1234')"));
7969 script->Run();
7970 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
7971 CHECK(!current->Global()->Has(v8_str("na")));
7972
7973 // Check that global variables in current context are not visible in other
7974 // context.
7975 v8::TryCatch try_catch;
7976 script =
7977 Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
7978 Local<Value> result = script->Run();
7979 CHECK(try_catch.HasCaught());
7980 try_catch.Reset();
7981
7982 // Check that local variables in current context are not visible in other
7983 // context.
7984 script =
7985 Script::Compile(v8_str("(function() { "
7986 " var baz = 87;"
7987 " return other.eval('baz');"
7988 "})();"));
7989 result = script->Run();
7990 CHECK(try_catch.HasCaught());
7991 try_catch.Reset();
7992
7993 // Check that global variables in the other environment are visible
7994 // when evaluting code.
7995 other->Global()->Set(v8_str("bis"), v8_num(1234));
7996 script = Script::Compile(v8_str("other.eval('bis')"));
7997 CHECK_EQ(1234, script->Run()->Int32Value());
7998 CHECK(!try_catch.HasCaught());
7999
8000 // Check that the 'this' pointer points to the global object evaluating
8001 // code.
8002 other->Global()->Set(v8_str("t"), other->Global());
8003 script = Script::Compile(v8_str("other.eval('this == t')"));
8004 result = script->Run();
8005 CHECK(result->IsTrue());
8006 CHECK(!try_catch.HasCaught());
8007
8008 // Check that variables introduced in with-statement are not visible in
8009 // other context.
8010 script =
8011 Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
8012 result = script->Run();
8013 CHECK(try_catch.HasCaught());
8014 try_catch.Reset();
8015
8016 // Check that you cannot use 'eval.call' with another object than the
8017 // current global object.
8018 script =
8019 Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
8020 result = script->Run();
8021 CHECK(try_catch.HasCaught());
8022}
8023
8024
8025// Test that calling eval in a context which has been detached from
8026// its global throws an exception. This behavior is consistent with
8027// other JavaScript implementations.
8028THREADED_TEST(EvalInDetachedGlobal) {
8029 v8::HandleScope scope;
8030
8031 v8::Persistent<Context> context0 = Context::New();
8032 v8::Persistent<Context> context1 = Context::New();
8033
Ben Murdochc7cc0282012-03-05 14:35:55 +00008034 // Set up function in context0 that uses eval from context0.
Steve Blocka7e24c12009-10-30 11:49:00 +00008035 context0->Enter();
8036 v8::Handle<v8::Value> fun =
8037 CompileRun("var x = 42;"
8038 "(function() {"
8039 " var e = eval;"
8040 " return function(s) { return e(s); }"
8041 "})()");
8042 context0->Exit();
8043
8044 // Put the function into context1 and call it before and after
8045 // detaching the global. Before detaching, the call succeeds and
8046 // after detaching and exception is thrown.
8047 context1->Enter();
8048 context1->Global()->Set(v8_str("fun"), fun);
8049 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
8050 CHECK_EQ(42, x_value->Int32Value());
8051 context0->DetachGlobal();
8052 v8::TryCatch catcher;
8053 x_value = CompileRun("fun('x')");
8054 CHECK(x_value.IsEmpty());
8055 CHECK(catcher.HasCaught());
8056 context1->Exit();
8057
8058 context1.Dispose();
8059 context0.Dispose();
8060}
8061
8062
8063THREADED_TEST(CrossLazyLoad) {
8064 v8::HandleScope scope;
8065 LocalContext other;
8066 LocalContext current;
8067
8068 Local<String> token = v8_str("<security token>");
8069 other->SetSecurityToken(token);
8070 current->SetSecurityToken(token);
8071
Ben Murdochc7cc0282012-03-05 14:35:55 +00008072 // Set up reference from current to other.
Steve Blocka7e24c12009-10-30 11:49:00 +00008073 current->Global()->Set(v8_str("other"), other->Global());
8074
8075 // Trigger lazy loading in other context.
8076 Local<Script> script =
8077 Script::Compile(v8_str("other.eval('new Date(42)')"));
8078 Local<Value> value = script->Run();
8079 CHECK_EQ(42.0, value->NumberValue());
8080}
8081
8082
8083static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
Andrei Popescu402d9372010-02-26 13:31:12 +00008084 ApiTestFuzzer::Fuzz();
Steve Blocka7e24c12009-10-30 11:49:00 +00008085 if (args.IsConstructCall()) {
8086 if (args[0]->IsInt32()) {
8087 return v8_num(-args[0]->Int32Value());
8088 }
8089 }
8090
8091 return args[0];
8092}
8093
8094
8095// Test that a call handler can be set for objects which will allow
8096// non-function objects created through the API to be called as
8097// functions.
8098THREADED_TEST(CallAsFunction) {
8099 v8::HandleScope scope;
8100 LocalContext context;
8101
Ben Murdoch257744e2011-11-30 15:57:28 +00008102 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8103 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
8104 instance_template->SetCallAsFunctionHandler(call_as_function);
8105 Local<v8::Object> instance = t->GetFunction()->NewInstance();
8106 context->Global()->Set(v8_str("obj"), instance);
8107 v8::TryCatch try_catch;
8108 Local<Value> value;
8109 CHECK(!try_catch.HasCaught());
Steve Blocka7e24c12009-10-30 11:49:00 +00008110
Ben Murdoch257744e2011-11-30 15:57:28 +00008111 value = CompileRun("obj(42)");
8112 CHECK(!try_catch.HasCaught());
8113 CHECK_EQ(42, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00008114
Ben Murdoch257744e2011-11-30 15:57:28 +00008115 value = CompileRun("(function(o){return o(49)})(obj)");
8116 CHECK(!try_catch.HasCaught());
8117 CHECK_EQ(49, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00008118
Ben Murdoch257744e2011-11-30 15:57:28 +00008119 // test special case of call as function
8120 value = CompileRun("[obj]['0'](45)");
8121 CHECK(!try_catch.HasCaught());
8122 CHECK_EQ(45, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00008123
Ben Murdoch257744e2011-11-30 15:57:28 +00008124 value = CompileRun("obj.call = Function.prototype.call;"
8125 "obj.call(null, 87)");
8126 CHECK(!try_catch.HasCaught());
8127 CHECK_EQ(87, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00008128
Ben Murdoch257744e2011-11-30 15:57:28 +00008129 // Regression tests for bug #1116356: Calling call through call/apply
8130 // must work for non-function receivers.
8131 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
8132 value = CompileRun(apply_99);
8133 CHECK(!try_catch.HasCaught());
8134 CHECK_EQ(99, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00008135
Ben Murdoch257744e2011-11-30 15:57:28 +00008136 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
8137 value = CompileRun(call_17);
8138 CHECK(!try_catch.HasCaught());
8139 CHECK_EQ(17, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00008140
Ben Murdoch257744e2011-11-30 15:57:28 +00008141 // Check that the call-as-function handler can be called through
8142 // new.
8143 value = CompileRun("new obj(43)");
8144 CHECK(!try_catch.HasCaught());
8145 CHECK_EQ(-43, value->Int32Value());
8146
8147 // Check that the call-as-function handler can be called through
8148 // the API.
8149 v8::Handle<Value> args[] = { v8_num(28) };
8150 value = instance->CallAsFunction(instance, 1, args);
8151 CHECK(!try_catch.HasCaught());
8152 CHECK_EQ(28, value->Int32Value());
8153 }
8154
8155 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008156 Local<ObjectTemplate> instance_template(t->InstanceTemplate());
Ben Murdochc7cc0282012-03-05 14:35:55 +00008157 USE(instance_template);
Ben Murdoch257744e2011-11-30 15:57:28 +00008158 Local<v8::Object> instance = t->GetFunction()->NewInstance();
8159 context->Global()->Set(v8_str("obj2"), instance);
8160 v8::TryCatch try_catch;
8161 Local<Value> value;
8162 CHECK(!try_catch.HasCaught());
8163
8164 // Call an object without call-as-function handler through the JS
8165 value = CompileRun("obj2(28)");
8166 CHECK(value.IsEmpty());
8167 CHECK(try_catch.HasCaught());
8168 String::AsciiValue exception_value1(try_catch.Exception());
8169 CHECK_EQ("TypeError: Property 'obj2' of object #<Object> is not a function",
8170 *exception_value1);
8171 try_catch.Reset();
8172
8173 // Call an object without call-as-function handler through the API
8174 value = CompileRun("obj2(28)");
8175 v8::Handle<Value> args[] = { v8_num(28) };
8176 value = instance->CallAsFunction(instance, 1, args);
8177 CHECK(value.IsEmpty());
8178 CHECK(try_catch.HasCaught());
8179 String::AsciiValue exception_value2(try_catch.Exception());
8180 CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
8181 try_catch.Reset();
8182 }
8183
8184 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8185 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
8186 instance_template->SetCallAsFunctionHandler(ThrowValue);
8187 Local<v8::Object> instance = t->GetFunction()->NewInstance();
8188 context->Global()->Set(v8_str("obj3"), instance);
8189 v8::TryCatch try_catch;
8190 Local<Value> value;
8191 CHECK(!try_catch.HasCaught());
8192
8193 // Catch the exception which is thrown by call-as-function handler
8194 value = CompileRun("obj3(22)");
8195 CHECK(try_catch.HasCaught());
8196 String::AsciiValue exception_value1(try_catch.Exception());
8197 CHECK_EQ("22", *exception_value1);
8198 try_catch.Reset();
8199
8200 v8::Handle<Value> args[] = { v8_num(23) };
8201 value = instance->CallAsFunction(instance, 1, args);
8202 CHECK(try_catch.HasCaught());
8203 String::AsciiValue exception_value2(try_catch.Exception());
8204 CHECK_EQ("23", *exception_value2);
8205 try_catch.Reset();
8206 }
8207}
8208
8209
8210// Check whether a non-function object is callable.
8211THREADED_TEST(CallableObject) {
8212 v8::HandleScope scope;
8213 LocalContext context;
8214
8215 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8216 instance_template->SetCallAsFunctionHandler(call_as_function);
8217 Local<Object> instance = instance_template->NewInstance();
8218 v8::TryCatch try_catch;
8219
8220 CHECK(instance->IsCallable());
8221 CHECK(!try_catch.HasCaught());
8222 }
8223
8224 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8225 Local<Object> instance = instance_template->NewInstance();
8226 v8::TryCatch try_catch;
8227
8228 CHECK(!instance->IsCallable());
8229 CHECK(!try_catch.HasCaught());
8230 }
8231
8232 { Local<FunctionTemplate> function_template =
8233 FunctionTemplate::New(call_as_function);
8234 Local<Function> function = function_template->GetFunction();
8235 Local<Object> instance = function;
8236 v8::TryCatch try_catch;
8237
8238 CHECK(instance->IsCallable());
8239 CHECK(!try_catch.HasCaught());
8240 }
8241
8242 { Local<FunctionTemplate> function_template = FunctionTemplate::New();
8243 Local<Function> function = function_template->GetFunction();
8244 Local<Object> instance = function;
8245 v8::TryCatch try_catch;
8246
8247 CHECK(instance->IsCallable());
8248 CHECK(!try_catch.HasCaught());
8249 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008250}
8251
8252
8253static int CountHandles() {
8254 return v8::HandleScope::NumberOfHandles();
8255}
8256
8257
8258static int Recurse(int depth, int iterations) {
8259 v8::HandleScope scope;
8260 if (depth == 0) return CountHandles();
8261 for (int i = 0; i < iterations; i++) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008262 Local<v8::Number> n(v8::Integer::New(42));
Steve Blocka7e24c12009-10-30 11:49:00 +00008263 }
8264 return Recurse(depth - 1, iterations);
8265}
8266
8267
8268THREADED_TEST(HandleIteration) {
8269 static const int kIterations = 500;
8270 static const int kNesting = 200;
8271 CHECK_EQ(0, CountHandles());
8272 {
8273 v8::HandleScope scope1;
8274 CHECK_EQ(0, CountHandles());
8275 for (int i = 0; i < kIterations; i++) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008276 Local<v8::Number> n(v8::Integer::New(42));
Steve Blocka7e24c12009-10-30 11:49:00 +00008277 CHECK_EQ(i + 1, CountHandles());
8278 }
8279
8280 CHECK_EQ(kIterations, CountHandles());
8281 {
8282 v8::HandleScope scope2;
8283 for (int j = 0; j < kIterations; j++) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008284 Local<v8::Number> n(v8::Integer::New(42));
Steve Blocka7e24c12009-10-30 11:49:00 +00008285 CHECK_EQ(j + 1 + kIterations, CountHandles());
8286 }
8287 }
8288 CHECK_EQ(kIterations, CountHandles());
8289 }
8290 CHECK_EQ(0, CountHandles());
8291 CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
8292}
8293
8294
8295static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
8296 Local<String> name,
8297 const AccessorInfo& info) {
8298 ApiTestFuzzer::Fuzz();
8299 return v8::Handle<Value>();
8300}
8301
8302
8303THREADED_TEST(InterceptorHasOwnProperty) {
8304 v8::HandleScope scope;
8305 LocalContext context;
8306 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8307 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
8308 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
8309 Local<Function> function = fun_templ->GetFunction();
8310 context->Global()->Set(v8_str("constructor"), function);
8311 v8::Handle<Value> value = CompileRun(
8312 "var o = new constructor();"
8313 "o.hasOwnProperty('ostehaps');");
8314 CHECK_EQ(false, value->BooleanValue());
8315 value = CompileRun(
8316 "o.ostehaps = 42;"
8317 "o.hasOwnProperty('ostehaps');");
8318 CHECK_EQ(true, value->BooleanValue());
8319 value = CompileRun(
8320 "var p = new constructor();"
8321 "p.hasOwnProperty('ostehaps');");
8322 CHECK_EQ(false, value->BooleanValue());
8323}
8324
8325
8326static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
8327 Local<String> name,
8328 const AccessorInfo& info) {
8329 ApiTestFuzzer::Fuzz();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008330 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +00008331 return v8::Handle<Value>();
8332}
8333
8334
8335THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
8336 v8::HandleScope scope;
8337 LocalContext context;
8338 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8339 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
8340 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
8341 Local<Function> function = fun_templ->GetFunction();
8342 context->Global()->Set(v8_str("constructor"), function);
8343 // Let's first make some stuff so we can be sure to get a good GC.
8344 CompileRun(
8345 "function makestr(size) {"
8346 " switch (size) {"
8347 " case 1: return 'f';"
8348 " case 2: return 'fo';"
8349 " case 3: return 'foo';"
8350 " }"
8351 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
8352 "}"
8353 "var x = makestr(12345);"
8354 "x = makestr(31415);"
8355 "x = makestr(23456);");
8356 v8::Handle<Value> value = CompileRun(
8357 "var o = new constructor();"
8358 "o.__proto__ = new String(x);"
8359 "o.hasOwnProperty('ostehaps');");
8360 CHECK_EQ(false, value->BooleanValue());
8361}
8362
8363
8364typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
8365 const AccessorInfo& info);
8366
8367
8368static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
8369 const char* source,
8370 int expected) {
8371 v8::HandleScope scope;
8372 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08008373 templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
Steve Blocka7e24c12009-10-30 11:49:00 +00008374 LocalContext context;
8375 context->Global()->Set(v8_str("o"), templ->NewInstance());
8376 v8::Handle<Value> value = CompileRun(source);
8377 CHECK_EQ(expected, value->Int32Value());
8378}
8379
8380
8381static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
8382 const AccessorInfo& info) {
8383 ApiTestFuzzer::Fuzz();
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08008384 CHECK_EQ(v8_str("data"), info.Data());
8385 CHECK_EQ(v8_str("x"), name);
Steve Blocka7e24c12009-10-30 11:49:00 +00008386 return v8::Integer::New(42);
8387}
8388
8389
8390// This test should hit the load IC for the interceptor case.
8391THREADED_TEST(InterceptorLoadIC) {
8392 CheckInterceptorLoadIC(InterceptorLoadICGetter,
8393 "var result = 0;"
8394 "for (var i = 0; i < 1000; i++) {"
8395 " result = o.x;"
8396 "}",
8397 42);
8398}
8399
8400
8401// Below go several tests which verify that JITing for various
8402// configurations of interceptor and explicit fields works fine
8403// (those cases are special cased to get better performance).
8404
8405static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
8406 const AccessorInfo& info) {
8407 ApiTestFuzzer::Fuzz();
8408 return v8_str("x")->Equals(name)
8409 ? v8::Integer::New(42) : v8::Handle<v8::Value>();
8410}
8411
8412
8413THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
8414 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8415 "var result = 0;"
8416 "o.y = 239;"
8417 "for (var i = 0; i < 1000; i++) {"
8418 " result = o.y;"
8419 "}",
8420 239);
8421}
8422
8423
8424THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
8425 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8426 "var result = 0;"
8427 "o.__proto__ = { 'y': 239 };"
8428 "for (var i = 0; i < 1000; i++) {"
8429 " result = o.y + o.x;"
8430 "}",
8431 239 + 42);
8432}
8433
8434
8435THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
8436 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8437 "var result = 0;"
8438 "o.__proto__.y = 239;"
8439 "for (var i = 0; i < 1000; i++) {"
8440 " result = o.y + o.x;"
8441 "}",
8442 239 + 42);
8443}
8444
8445
8446THREADED_TEST(InterceptorLoadICUndefined) {
8447 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8448 "var result = 0;"
8449 "for (var i = 0; i < 1000; i++) {"
8450 " result = (o.y == undefined) ? 239 : 42;"
8451 "}",
8452 239);
8453}
8454
8455
8456THREADED_TEST(InterceptorLoadICWithOverride) {
8457 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8458 "fst = new Object(); fst.__proto__ = o;"
8459 "snd = new Object(); snd.__proto__ = fst;"
8460 "var result1 = 0;"
8461 "for (var i = 0; i < 1000; i++) {"
8462 " result1 = snd.x;"
8463 "}"
8464 "fst.x = 239;"
8465 "var result = 0;"
8466 "for (var i = 0; i < 1000; i++) {"
8467 " result = snd.x;"
8468 "}"
8469 "result + result1",
8470 239 + 42);
8471}
8472
8473
8474// Test the case when we stored field into
8475// a stub, but interceptor produced value on its own.
8476THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
8477 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8478 "proto = new Object();"
8479 "o.__proto__ = proto;"
8480 "proto.x = 239;"
8481 "for (var i = 0; i < 1000; i++) {"
8482 " o.x;"
8483 // Now it should be ICed and keep a reference to x defined on proto
8484 "}"
8485 "var result = 0;"
8486 "for (var i = 0; i < 1000; i++) {"
8487 " result += o.x;"
8488 "}"
8489 "result;",
8490 42 * 1000);
8491}
8492
8493
8494// Test the case when we stored field into
8495// a stub, but it got invalidated later on.
8496THREADED_TEST(InterceptorLoadICInvalidatedField) {
8497 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8498 "proto1 = new Object();"
8499 "proto2 = new Object();"
8500 "o.__proto__ = proto1;"
8501 "proto1.__proto__ = proto2;"
8502 "proto2.y = 239;"
8503 "for (var i = 0; i < 1000; i++) {"
8504 " o.y;"
8505 // Now it should be ICed and keep a reference to y defined on proto2
8506 "}"
8507 "proto1.y = 42;"
8508 "var result = 0;"
8509 "for (var i = 0; i < 1000; i++) {"
8510 " result += o.y;"
8511 "}"
8512 "result;",
8513 42 * 1000);
8514}
8515
8516
Steve Block6ded16b2010-05-10 14:33:55 +01008517static int interceptor_load_not_handled_calls = 0;
8518static v8::Handle<Value> InterceptorLoadNotHandled(Local<String> name,
8519 const AccessorInfo& info) {
8520 ++interceptor_load_not_handled_calls;
8521 return v8::Handle<v8::Value>();
8522}
8523
8524
8525// Test how post-interceptor lookups are done in the non-cacheable
8526// case: the interceptor should not be invoked during this lookup.
8527THREADED_TEST(InterceptorLoadICPostInterceptor) {
8528 interceptor_load_not_handled_calls = 0;
8529 CheckInterceptorLoadIC(InterceptorLoadNotHandled,
8530 "receiver = new Object();"
8531 "receiver.__proto__ = o;"
8532 "proto = new Object();"
8533 "/* Make proto a slow-case object. */"
8534 "for (var i = 0; i < 1000; i++) {"
8535 " proto[\"xxxxxxxx\" + i] = [];"
8536 "}"
8537 "proto.x = 17;"
8538 "o.__proto__ = proto;"
8539 "var result = 0;"
8540 "for (var i = 0; i < 1000; i++) {"
8541 " result += receiver.x;"
8542 "}"
8543 "result;",
8544 17 * 1000);
8545 CHECK_EQ(1000, interceptor_load_not_handled_calls);
8546}
8547
8548
Steve Blocka7e24c12009-10-30 11:49:00 +00008549// Test the case when we stored field into
8550// a stub, but it got invalidated later on due to override on
8551// global object which is between interceptor and fields' holders.
8552THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
8553 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8554 "o.__proto__ = this;" // set a global to be a proto of o.
8555 "this.__proto__.y = 239;"
8556 "for (var i = 0; i < 10; i++) {"
8557 " if (o.y != 239) throw 'oops: ' + o.y;"
8558 // Now it should be ICed and keep a reference to y defined on field_holder.
8559 "}"
8560 "this.y = 42;" // Assign on a global.
8561 "var result = 0;"
8562 "for (var i = 0; i < 10; i++) {"
8563 " result += o.y;"
8564 "}"
8565 "result;",
8566 42 * 10);
8567}
8568
8569
Steve Blocka7e24c12009-10-30 11:49:00 +00008570static void SetOnThis(Local<String> name,
8571 Local<Value> value,
8572 const AccessorInfo& info) {
8573 info.This()->ForceSet(name, value);
8574}
8575
8576
8577THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
8578 v8::HandleScope scope;
8579 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8580 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8581 templ->SetAccessor(v8_str("y"), Return239);
8582 LocalContext context;
8583 context->Global()->Set(v8_str("o"), templ->NewInstance());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008584
8585 // Check the case when receiver and interceptor's holder
8586 // are the same objects.
Steve Blocka7e24c12009-10-30 11:49:00 +00008587 v8::Handle<Value> value = CompileRun(
8588 "var result = 0;"
8589 "for (var i = 0; i < 7; i++) {"
8590 " result = o.y;"
8591 "}");
8592 CHECK_EQ(239, value->Int32Value());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008593
8594 // Check the case when interceptor's holder is in proto chain
8595 // of receiver.
8596 value = CompileRun(
8597 "r = { __proto__: o };"
8598 "var result = 0;"
8599 "for (var i = 0; i < 7; i++) {"
8600 " result = r.y;"
8601 "}");
8602 CHECK_EQ(239, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00008603}
8604
8605
8606THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
8607 v8::HandleScope scope;
8608 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8609 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8610 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8611 templ_p->SetAccessor(v8_str("y"), Return239);
8612
8613 LocalContext context;
8614 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8615 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8616
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008617 // Check the case when receiver and interceptor's holder
8618 // are the same objects.
Steve Blocka7e24c12009-10-30 11:49:00 +00008619 v8::Handle<Value> value = CompileRun(
8620 "o.__proto__ = p;"
8621 "var result = 0;"
8622 "for (var i = 0; i < 7; i++) {"
8623 " result = o.x + o.y;"
8624 "}");
8625 CHECK_EQ(239 + 42, value->Int32Value());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008626
8627 // Check the case when interceptor's holder is in proto chain
8628 // of receiver.
8629 value = CompileRun(
8630 "r = { __proto__: o };"
8631 "var result = 0;"
8632 "for (var i = 0; i < 7; i++) {"
8633 " result = r.x + r.y;"
8634 "}");
8635 CHECK_EQ(239 + 42, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00008636}
8637
8638
8639THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
8640 v8::HandleScope scope;
8641 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8642 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8643 templ->SetAccessor(v8_str("y"), Return239);
8644
8645 LocalContext context;
8646 context->Global()->Set(v8_str("o"), templ->NewInstance());
8647
8648 v8::Handle<Value> value = CompileRun(
8649 "fst = new Object(); fst.__proto__ = o;"
8650 "snd = new Object(); snd.__proto__ = fst;"
8651 "var result1 = 0;"
8652 "for (var i = 0; i < 7; i++) {"
8653 " result1 = snd.x;"
8654 "}"
8655 "fst.x = 239;"
8656 "var result = 0;"
8657 "for (var i = 0; i < 7; i++) {"
8658 " result = snd.x;"
8659 "}"
8660 "result + result1");
8661 CHECK_EQ(239 + 42, value->Int32Value());
8662}
8663
8664
8665// Test the case when we stored callback into
8666// a stub, but interceptor produced value on its own.
8667THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
8668 v8::HandleScope scope;
8669 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8670 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8671 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8672 templ_p->SetAccessor(v8_str("y"), Return239);
8673
8674 LocalContext context;
8675 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8676 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8677
8678 v8::Handle<Value> value = CompileRun(
8679 "o.__proto__ = p;"
8680 "for (var i = 0; i < 7; i++) {"
8681 " o.x;"
8682 // Now it should be ICed and keep a reference to x defined on p
8683 "}"
8684 "var result = 0;"
8685 "for (var i = 0; i < 7; i++) {"
8686 " result += o.x;"
8687 "}"
8688 "result");
8689 CHECK_EQ(42 * 7, value->Int32Value());
8690}
8691
8692
8693// Test the case when we stored callback into
8694// a stub, but it got invalidated later on.
8695THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
8696 v8::HandleScope scope;
8697 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8698 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8699 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8700 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
8701
8702 LocalContext context;
8703 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8704 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8705
8706 v8::Handle<Value> value = CompileRun(
8707 "inbetween = new Object();"
8708 "o.__proto__ = inbetween;"
8709 "inbetween.__proto__ = p;"
8710 "for (var i = 0; i < 10; i++) {"
8711 " o.y;"
8712 // Now it should be ICed and keep a reference to y defined on p
8713 "}"
8714 "inbetween.y = 42;"
8715 "var result = 0;"
8716 "for (var i = 0; i < 10; i++) {"
8717 " result += o.y;"
8718 "}"
8719 "result");
8720 CHECK_EQ(42 * 10, value->Int32Value());
8721}
8722
8723
8724// Test the case when we stored callback into
8725// a stub, but it got invalidated later on due to override on
8726// global object which is between interceptor and callbacks' holders.
8727THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
8728 v8::HandleScope scope;
8729 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8730 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8731 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8732 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
8733
8734 LocalContext context;
8735 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8736 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8737
8738 v8::Handle<Value> value = CompileRun(
8739 "o.__proto__ = this;"
8740 "this.__proto__ = p;"
8741 "for (var i = 0; i < 10; i++) {"
8742 " if (o.y != 239) throw 'oops: ' + o.y;"
8743 // Now it should be ICed and keep a reference to y defined on p
8744 "}"
8745 "this.y = 42;"
8746 "var result = 0;"
8747 "for (var i = 0; i < 10; i++) {"
8748 " result += o.y;"
8749 "}"
8750 "result");
8751 CHECK_EQ(42 * 10, value->Int32Value());
8752}
8753
8754
8755static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
8756 const AccessorInfo& info) {
8757 ApiTestFuzzer::Fuzz();
8758 CHECK(v8_str("x")->Equals(name));
8759 return v8::Integer::New(0);
8760}
8761
8762
8763THREADED_TEST(InterceptorReturningZero) {
8764 CheckInterceptorLoadIC(InterceptorLoadICGetter0,
8765 "o.x == undefined ? 1 : 0",
8766 0);
8767}
8768
8769
8770static v8::Handle<Value> InterceptorStoreICSetter(
8771 Local<String> key, Local<Value> value, const AccessorInfo&) {
8772 CHECK(v8_str("x")->Equals(key));
8773 CHECK_EQ(42, value->Int32Value());
8774 return value;
8775}
8776
8777
8778// This test should hit the store IC for the interceptor case.
8779THREADED_TEST(InterceptorStoreIC) {
8780 v8::HandleScope scope;
8781 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8782 templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08008783 InterceptorStoreICSetter,
8784 0, 0, 0, v8_str("data"));
Steve Blocka7e24c12009-10-30 11:49:00 +00008785 LocalContext context;
8786 context->Global()->Set(v8_str("o"), templ->NewInstance());
Ben Murdochc7cc0282012-03-05 14:35:55 +00008787 CompileRun(
8788 "for (var i = 0; i < 1000; i++) {"
8789 " o.x = 42;"
8790 "}");
Steve Blocka7e24c12009-10-30 11:49:00 +00008791}
8792
8793
8794THREADED_TEST(InterceptorStoreICWithNoSetter) {
8795 v8::HandleScope scope;
8796 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8797 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8798 LocalContext context;
8799 context->Global()->Set(v8_str("o"), templ->NewInstance());
8800 v8::Handle<Value> value = CompileRun(
8801 "for (var i = 0; i < 1000; i++) {"
8802 " o.y = 239;"
8803 "}"
8804 "42 + o.y");
8805 CHECK_EQ(239 + 42, value->Int32Value());
8806}
8807
8808
8809
8810
8811v8::Handle<Value> call_ic_function;
8812v8::Handle<Value> call_ic_function2;
8813v8::Handle<Value> call_ic_function3;
8814
8815static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
8816 const AccessorInfo& info) {
8817 ApiTestFuzzer::Fuzz();
8818 CHECK(v8_str("x")->Equals(name));
8819 return call_ic_function;
8820}
8821
8822
8823// This test should hit the call IC for the interceptor case.
8824THREADED_TEST(InterceptorCallIC) {
8825 v8::HandleScope scope;
8826 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8827 templ->SetNamedPropertyHandler(InterceptorCallICGetter);
8828 LocalContext context;
8829 context->Global()->Set(v8_str("o"), templ->NewInstance());
8830 call_ic_function =
8831 v8_compile("function f(x) { return x + 1; }; f")->Run();
8832 v8::Handle<Value> value = CompileRun(
8833 "var result = 0;"
8834 "for (var i = 0; i < 1000; i++) {"
8835 " result = o.x(41);"
8836 "}");
8837 CHECK_EQ(42, value->Int32Value());
8838}
8839
8840
8841// This test checks that if interceptor doesn't provide
8842// a value, we can fetch regular value.
8843THREADED_TEST(InterceptorCallICSeesOthers) {
8844 v8::HandleScope scope;
8845 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8846 templ->SetNamedPropertyHandler(NoBlockGetterX);
8847 LocalContext context;
8848 context->Global()->Set(v8_str("o"), templ->NewInstance());
8849 v8::Handle<Value> value = CompileRun(
8850 "o.x = function f(x) { return x + 1; };"
8851 "var result = 0;"
8852 "for (var i = 0; i < 7; i++) {"
8853 " result = o.x(41);"
8854 "}");
8855 CHECK_EQ(42, value->Int32Value());
8856}
8857
8858
8859static v8::Handle<Value> call_ic_function4;
8860static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
8861 const AccessorInfo& info) {
8862 ApiTestFuzzer::Fuzz();
8863 CHECK(v8_str("x")->Equals(name));
8864 return call_ic_function4;
8865}
8866
8867
8868// This test checks that if interceptor provides a function,
8869// even if we cached shadowed variant, interceptor's function
8870// is invoked
8871THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
8872 v8::HandleScope scope;
8873 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8874 templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
8875 LocalContext context;
8876 context->Global()->Set(v8_str("o"), templ->NewInstance());
8877 call_ic_function4 =
8878 v8_compile("function f(x) { return x - 1; }; f")->Run();
8879 v8::Handle<Value> value = CompileRun(
8880 "o.__proto__.x = function(x) { return x + 1; };"
8881 "var result = 0;"
8882 "for (var i = 0; i < 1000; i++) {"
8883 " result = o.x(42);"
8884 "}");
8885 CHECK_EQ(41, value->Int32Value());
8886}
8887
8888
8889// Test the case when we stored cacheable lookup into
8890// a stub, but it got invalidated later on
8891THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
8892 v8::HandleScope scope;
8893 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8894 templ->SetNamedPropertyHandler(NoBlockGetterX);
8895 LocalContext context;
8896 context->Global()->Set(v8_str("o"), templ->NewInstance());
8897 v8::Handle<Value> value = CompileRun(
8898 "proto1 = new Object();"
8899 "proto2 = new Object();"
8900 "o.__proto__ = proto1;"
8901 "proto1.__proto__ = proto2;"
8902 "proto2.y = function(x) { return x + 1; };"
8903 // Invoke it many times to compile a stub
8904 "for (var i = 0; i < 7; i++) {"
8905 " o.y(42);"
8906 "}"
8907 "proto1.y = function(x) { return x - 1; };"
8908 "var result = 0;"
8909 "for (var i = 0; i < 7; i++) {"
8910 " result += o.y(42);"
8911 "}");
8912 CHECK_EQ(41 * 7, value->Int32Value());
8913}
8914
8915
Steve Blocka7e24c12009-10-30 11:49:00 +00008916// This test checks that if interceptor doesn't provide a function,
8917// cached constant function is used
8918THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
8919 v8::HandleScope scope;
8920 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8921 templ->SetNamedPropertyHandler(NoBlockGetterX);
8922 LocalContext context;
8923 context->Global()->Set(v8_str("o"), templ->NewInstance());
8924 v8::Handle<Value> value = CompileRun(
8925 "function inc(x) { return x + 1; };"
8926 "inc(1);"
8927 "o.x = inc;"
8928 "var result = 0;"
8929 "for (var i = 0; i < 1000; i++) {"
8930 " result = o.x(42);"
8931 "}");
8932 CHECK_EQ(43, value->Int32Value());
8933}
8934
8935
Ben Murdochc7cc0282012-03-05 14:35:55 +00008936static v8::Handle<Value> call_ic_function5;
8937static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
8938 const AccessorInfo& info) {
8939 ApiTestFuzzer::Fuzz();
8940 if (v8_str("x")->Equals(name))
8941 return call_ic_function5;
8942 else
8943 return Local<Value>();
8944}
8945
8946
Steve Blocka7e24c12009-10-30 11:49:00 +00008947// This test checks that if interceptor provides a function,
8948// even if we cached constant function, interceptor's function
8949// is invoked
8950THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
8951 v8::HandleScope scope;
8952 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8953 templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
8954 LocalContext context;
8955 context->Global()->Set(v8_str("o"), templ->NewInstance());
8956 call_ic_function5 =
8957 v8_compile("function f(x) { return x - 1; }; f")->Run();
8958 v8::Handle<Value> value = CompileRun(
8959 "function inc(x) { return x + 1; };"
8960 "inc(1);"
8961 "o.x = inc;"
8962 "var result = 0;"
8963 "for (var i = 0; i < 1000; i++) {"
8964 " result = o.x(42);"
8965 "}");
8966 CHECK_EQ(41, value->Int32Value());
8967}
8968
8969
Ben Murdochc7cc0282012-03-05 14:35:55 +00008970static v8::Handle<Value> call_ic_function6;
8971static v8::Handle<Value> InterceptorCallICGetter6(Local<String> name,
8972 const AccessorInfo& info) {
8973 ApiTestFuzzer::Fuzz();
8974 if (v8_str("x")->Equals(name))
8975 return call_ic_function6;
8976 else
8977 return Local<Value>();
8978}
8979
8980
8981// Same test as above, except the code is wrapped in a function
8982// to test the optimized compiler.
8983THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
8984 i::FLAG_allow_natives_syntax = true;
8985 v8::HandleScope scope;
8986 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8987 templ->SetNamedPropertyHandler(InterceptorCallICGetter6);
8988 LocalContext context;
8989 context->Global()->Set(v8_str("o"), templ->NewInstance());
8990 call_ic_function6 =
8991 v8_compile("function f(x) { return x - 1; }; f")->Run();
8992 v8::Handle<Value> value = CompileRun(
8993 "function inc(x) { return x + 1; };"
8994 "inc(1);"
8995 "o.x = inc;"
8996 "function test() {"
8997 " var result = 0;"
8998 " for (var i = 0; i < 1000; i++) {"
8999 " result = o.x(42);"
9000 " }"
9001 " return result;"
9002 "};"
9003 "test();"
9004 "test();"
9005 "test();"
9006 "%OptimizeFunctionOnNextCall(test);"
9007 "test()");
9008 CHECK_EQ(41, value->Int32Value());
9009}
9010
9011
Steve Blocka7e24c12009-10-30 11:49:00 +00009012// Test the case when we stored constant function into
9013// a stub, but it got invalidated later on
9014THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
9015 v8::HandleScope scope;
9016 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9017 templ->SetNamedPropertyHandler(NoBlockGetterX);
9018 LocalContext context;
9019 context->Global()->Set(v8_str("o"), templ->NewInstance());
9020 v8::Handle<Value> value = CompileRun(
9021 "function inc(x) { return x + 1; };"
9022 "inc(1);"
9023 "proto1 = new Object();"
9024 "proto2 = new Object();"
9025 "o.__proto__ = proto1;"
9026 "proto1.__proto__ = proto2;"
9027 "proto2.y = inc;"
9028 // Invoke it many times to compile a stub
9029 "for (var i = 0; i < 7; i++) {"
9030 " o.y(42);"
9031 "}"
9032 "proto1.y = function(x) { return x - 1; };"
9033 "var result = 0;"
9034 "for (var i = 0; i < 7; i++) {"
9035 " result += o.y(42);"
9036 "}");
9037 CHECK_EQ(41 * 7, value->Int32Value());
9038}
9039
9040
9041// Test the case when we stored constant function into
9042// a stub, but it got invalidated later on due to override on
9043// global object which is between interceptor and constant function' holders.
9044THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
9045 v8::HandleScope scope;
9046 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9047 templ->SetNamedPropertyHandler(NoBlockGetterX);
9048 LocalContext context;
9049 context->Global()->Set(v8_str("o"), templ->NewInstance());
9050 v8::Handle<Value> value = CompileRun(
9051 "function inc(x) { return x + 1; };"
9052 "inc(1);"
9053 "o.__proto__ = this;"
9054 "this.__proto__.y = inc;"
9055 // Invoke it many times to compile a stub
9056 "for (var i = 0; i < 7; i++) {"
9057 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
9058 "}"
9059 "this.y = function(x) { return x - 1; };"
9060 "var result = 0;"
9061 "for (var i = 0; i < 7; i++) {"
9062 " result += o.y(42);"
9063 "}");
9064 CHECK_EQ(41 * 7, value->Int32Value());
9065}
9066
9067
Leon Clarke4515c472010-02-03 11:58:03 +00009068// Test the case when actual function to call sits on global object.
9069THREADED_TEST(InterceptorCallICCachedFromGlobal) {
9070 v8::HandleScope scope;
9071 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9072 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9073
9074 LocalContext context;
9075 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9076
9077 v8::Handle<Value> value = CompileRun(
9078 "try {"
9079 " o.__proto__ = this;"
9080 " for (var i = 0; i < 10; i++) {"
9081 " var v = o.parseFloat('239');"
9082 " if (v != 239) throw v;"
9083 // Now it should be ICed and keep a reference to parseFloat.
9084 " }"
9085 " var result = 0;"
9086 " for (var i = 0; i < 10; i++) {"
9087 " result += o.parseFloat('239');"
9088 " }"
9089 " result"
9090 "} catch(e) {"
9091 " e"
9092 "};");
9093 CHECK_EQ(239 * 10, value->Int32Value());
9094}
9095
Andrei Popescu402d9372010-02-26 13:31:12 +00009096static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
9097 const AccessorInfo& info) {
9098 ApiTestFuzzer::Fuzz();
9099 int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data()));
9100 ++(*call_count);
9101 if ((*call_count) % 20 == 0) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009102 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Andrei Popescu402d9372010-02-26 13:31:12 +00009103 }
9104 return v8::Handle<Value>();
9105}
9106
9107static v8::Handle<Value> FastApiCallback_TrivialSignature(
9108 const v8::Arguments& args) {
9109 ApiTestFuzzer::Fuzz();
9110 CHECK_EQ(args.This(), args.Holder());
9111 CHECK(args.Data()->Equals(v8_str("method_data")));
9112 return v8::Integer::New(args[0]->Int32Value() + 1);
9113}
9114
9115static v8::Handle<Value> FastApiCallback_SimpleSignature(
9116 const v8::Arguments& args) {
9117 ApiTestFuzzer::Fuzz();
9118 CHECK_EQ(args.This()->GetPrototype(), args.Holder());
9119 CHECK(args.Data()->Equals(v8_str("method_data")));
9120 // Note, we're using HasRealNamedProperty instead of Has to avoid
9121 // invoking the interceptor again.
9122 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
9123 return v8::Integer::New(args[0]->Int32Value() + 1);
9124}
9125
9126// Helper to maximize the odds of object moving.
9127static void GenerateSomeGarbage() {
9128 CompileRun(
9129 "var garbage;"
9130 "for (var i = 0; i < 1000; i++) {"
9131 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
9132 "}"
9133 "garbage = undefined;");
9134}
9135
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009136
Steve Block1e0659c2011-05-24 12:43:12 +01009137v8::Handle<v8::Value> DirectApiCallback(const v8::Arguments& args) {
9138 static int count = 0;
9139 if (count++ % 3 == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01009140 HEAP-> CollectAllGarbage(true); // This should move the stub
Steve Block1e0659c2011-05-24 12:43:12 +01009141 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
9142 }
9143 return v8::Handle<v8::Value>();
9144}
9145
9146
9147THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
9148 v8::HandleScope scope;
9149 LocalContext context;
9150 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
9151 nativeobject_templ->Set("callback",
9152 v8::FunctionTemplate::New(DirectApiCallback));
9153 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
9154 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
9155 // call the api function multiple times to ensure direct call stub creation.
9156 CompileRun(
9157 "function f() {"
9158 " for (var i = 1; i <= 30; i++) {"
9159 " nativeobject.callback();"
9160 " }"
9161 "}"
9162 "f();");
9163}
9164
9165
9166v8::Handle<v8::Value> ThrowingDirectApiCallback(const v8::Arguments& args) {
9167 return v8::ThrowException(v8_str("g"));
9168}
9169
9170
9171THREADED_TEST(CallICFastApi_DirectCall_Throw) {
9172 v8::HandleScope scope;
9173 LocalContext context;
9174 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
9175 nativeobject_templ->Set("callback",
9176 v8::FunctionTemplate::New(ThrowingDirectApiCallback));
9177 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
9178 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
9179 // call the api function multiple times to ensure direct call stub creation.
9180 v8::Handle<Value> result = CompileRun(
9181 "var result = '';"
9182 "function f() {"
9183 " for (var i = 1; i <= 5; i++) {"
9184 " try { nativeobject.callback(); } catch (e) { result += e; }"
9185 " }"
9186 "}"
9187 "f(); result;");
9188 CHECK_EQ(v8_str("ggggg"), result);
9189}
9190
9191
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009192v8::Handle<v8::Value> DirectGetterCallback(Local<String> name,
9193 const v8::AccessorInfo& info) {
9194 if (++p_getter_count % 3 == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01009195 HEAP->CollectAllGarbage(true);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009196 GenerateSomeGarbage();
9197 }
9198 return v8::Handle<v8::Value>();
9199}
9200
9201
9202THREADED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
9203 v8::HandleScope scope;
9204 LocalContext context;
9205 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
9206 obj->SetAccessor(v8_str("p1"), DirectGetterCallback);
9207 context->Global()->Set(v8_str("o1"), obj->NewInstance());
9208 p_getter_count = 0;
9209 CompileRun(
9210 "function f() {"
9211 " for (var i = 0; i < 30; i++) o1.p1;"
9212 "}"
9213 "f();");
9214 CHECK_EQ(30, p_getter_count);
9215}
9216
9217
9218v8::Handle<v8::Value> ThrowingDirectGetterCallback(
9219 Local<String> name, const v8::AccessorInfo& info) {
9220 return v8::ThrowException(v8_str("g"));
9221}
9222
9223
9224THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
9225 v8::HandleScope scope;
9226 LocalContext context;
9227 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
9228 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
9229 context->Global()->Set(v8_str("o1"), obj->NewInstance());
9230 v8::Handle<Value> result = CompileRun(
9231 "var result = '';"
9232 "for (var i = 0; i < 5; i++) {"
9233 " try { o1.p1; } catch (e) { result += e; }"
9234 "}"
9235 "result;");
9236 CHECK_EQ(v8_str("ggggg"), result);
9237}
9238
9239
Andrei Popescu402d9372010-02-26 13:31:12 +00009240THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
9241 int interceptor_call_count = 0;
9242 v8::HandleScope scope;
9243 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9244 v8::Handle<v8::FunctionTemplate> method_templ =
9245 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
9246 v8_str("method_data"),
9247 v8::Handle<v8::Signature>());
9248 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9249 proto_templ->Set(v8_str("method"), method_templ);
9250 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9251 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9252 NULL, NULL, NULL, NULL,
9253 v8::External::Wrap(&interceptor_call_count));
9254 LocalContext context;
9255 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9256 GenerateSomeGarbage();
9257 context->Global()->Set(v8_str("o"), fun->NewInstance());
Ben Murdochc7cc0282012-03-05 14:35:55 +00009258 CompileRun(
Andrei Popescu402d9372010-02-26 13:31:12 +00009259 "var result = 0;"
9260 "for (var i = 0; i < 100; i++) {"
9261 " result = o.method(41);"
Ben Murdochc7cc0282012-03-05 14:35:55 +00009262 "}");
Andrei Popescu402d9372010-02-26 13:31:12 +00009263 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9264 CHECK_EQ(100, interceptor_call_count);
9265}
9266
9267THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
9268 int interceptor_call_count = 0;
9269 v8::HandleScope scope;
9270 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9271 v8::Handle<v8::FunctionTemplate> method_templ =
9272 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9273 v8_str("method_data"),
9274 v8::Signature::New(fun_templ));
9275 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9276 proto_templ->Set(v8_str("method"), method_templ);
9277 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9278 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9279 NULL, NULL, NULL, NULL,
9280 v8::External::Wrap(&interceptor_call_count));
9281 LocalContext context;
9282 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9283 GenerateSomeGarbage();
9284 context->Global()->Set(v8_str("o"), fun->NewInstance());
Ben Murdochc7cc0282012-03-05 14:35:55 +00009285 CompileRun(
Andrei Popescu402d9372010-02-26 13:31:12 +00009286 "o.foo = 17;"
9287 "var receiver = {};"
9288 "receiver.__proto__ = o;"
9289 "var result = 0;"
9290 "for (var i = 0; i < 100; i++) {"
9291 " result = receiver.method(41);"
Ben Murdochc7cc0282012-03-05 14:35:55 +00009292 "}");
Andrei Popescu402d9372010-02-26 13:31:12 +00009293 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9294 CHECK_EQ(100, interceptor_call_count);
9295}
9296
9297THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
9298 int interceptor_call_count = 0;
9299 v8::HandleScope scope;
9300 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9301 v8::Handle<v8::FunctionTemplate> method_templ =
9302 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9303 v8_str("method_data"),
9304 v8::Signature::New(fun_templ));
9305 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9306 proto_templ->Set(v8_str("method"), method_templ);
9307 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9308 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9309 NULL, NULL, NULL, NULL,
9310 v8::External::Wrap(&interceptor_call_count));
9311 LocalContext context;
9312 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9313 GenerateSomeGarbage();
9314 context->Global()->Set(v8_str("o"), fun->NewInstance());
Ben Murdochc7cc0282012-03-05 14:35:55 +00009315 CompileRun(
Andrei Popescu402d9372010-02-26 13:31:12 +00009316 "o.foo = 17;"
9317 "var receiver = {};"
9318 "receiver.__proto__ = o;"
9319 "var result = 0;"
9320 "var saved_result = 0;"
9321 "for (var i = 0; i < 100; i++) {"
9322 " result = receiver.method(41);"
9323 " if (i == 50) {"
9324 " saved_result = result;"
9325 " receiver = {method: function(x) { return x - 1 }};"
9326 " }"
Ben Murdochc7cc0282012-03-05 14:35:55 +00009327 "}");
Andrei Popescu402d9372010-02-26 13:31:12 +00009328 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
9329 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9330 CHECK_GE(interceptor_call_count, 50);
9331}
9332
9333THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
9334 int interceptor_call_count = 0;
9335 v8::HandleScope scope;
9336 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9337 v8::Handle<v8::FunctionTemplate> method_templ =
9338 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9339 v8_str("method_data"),
9340 v8::Signature::New(fun_templ));
9341 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9342 proto_templ->Set(v8_str("method"), method_templ);
9343 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9344 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9345 NULL, NULL, NULL, NULL,
9346 v8::External::Wrap(&interceptor_call_count));
9347 LocalContext context;
9348 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9349 GenerateSomeGarbage();
9350 context->Global()->Set(v8_str("o"), fun->NewInstance());
Ben Murdochc7cc0282012-03-05 14:35:55 +00009351 CompileRun(
Andrei Popescu402d9372010-02-26 13:31:12 +00009352 "o.foo = 17;"
9353 "var receiver = {};"
9354 "receiver.__proto__ = o;"
9355 "var result = 0;"
9356 "var saved_result = 0;"
9357 "for (var i = 0; i < 100; i++) {"
9358 " result = receiver.method(41);"
9359 " if (i == 50) {"
9360 " saved_result = result;"
9361 " o.method = function(x) { return x - 1 };"
9362 " }"
Ben Murdochc7cc0282012-03-05 14:35:55 +00009363 "}");
Andrei Popescu402d9372010-02-26 13:31:12 +00009364 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
9365 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9366 CHECK_GE(interceptor_call_count, 50);
9367}
9368
Steve Block6ded16b2010-05-10 14:33:55 +01009369THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
9370 int interceptor_call_count = 0;
9371 v8::HandleScope scope;
9372 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9373 v8::Handle<v8::FunctionTemplate> method_templ =
9374 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9375 v8_str("method_data"),
9376 v8::Signature::New(fun_templ));
9377 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9378 proto_templ->Set(v8_str("method"), method_templ);
9379 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9380 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9381 NULL, NULL, NULL, NULL,
9382 v8::External::Wrap(&interceptor_call_count));
9383 LocalContext context;
9384 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9385 GenerateSomeGarbage();
9386 context->Global()->Set(v8_str("o"), fun->NewInstance());
9387 v8::TryCatch try_catch;
Ben Murdochc7cc0282012-03-05 14:35:55 +00009388 CompileRun(
Steve Block6ded16b2010-05-10 14:33:55 +01009389 "o.foo = 17;"
9390 "var receiver = {};"
9391 "receiver.__proto__ = o;"
9392 "var result = 0;"
9393 "var saved_result = 0;"
9394 "for (var i = 0; i < 100; i++) {"
9395 " result = receiver.method(41);"
9396 " if (i == 50) {"
9397 " saved_result = result;"
9398 " receiver = 333;"
9399 " }"
Ben Murdochc7cc0282012-03-05 14:35:55 +00009400 "}");
Steve Block6ded16b2010-05-10 14:33:55 +01009401 CHECK(try_catch.HasCaught());
9402 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
9403 try_catch.Exception()->ToString());
9404 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9405 CHECK_GE(interceptor_call_count, 50);
9406}
9407
Andrei Popescu402d9372010-02-26 13:31:12 +00009408THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
9409 int interceptor_call_count = 0;
9410 v8::HandleScope scope;
9411 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9412 v8::Handle<v8::FunctionTemplate> method_templ =
9413 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9414 v8_str("method_data"),
9415 v8::Signature::New(fun_templ));
9416 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9417 proto_templ->Set(v8_str("method"), method_templ);
9418 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9419 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9420 NULL, NULL, NULL, NULL,
9421 v8::External::Wrap(&interceptor_call_count));
9422 LocalContext context;
9423 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9424 GenerateSomeGarbage();
9425 context->Global()->Set(v8_str("o"), fun->NewInstance());
9426 v8::TryCatch try_catch;
Ben Murdochc7cc0282012-03-05 14:35:55 +00009427 CompileRun(
Andrei Popescu402d9372010-02-26 13:31:12 +00009428 "o.foo = 17;"
9429 "var receiver = {};"
9430 "receiver.__proto__ = o;"
9431 "var result = 0;"
9432 "var saved_result = 0;"
9433 "for (var i = 0; i < 100; i++) {"
9434 " result = receiver.method(41);"
9435 " if (i == 50) {"
9436 " saved_result = result;"
9437 " receiver = {method: receiver.method};"
9438 " }"
Ben Murdochc7cc0282012-03-05 14:35:55 +00009439 "}");
Andrei Popescu402d9372010-02-26 13:31:12 +00009440 CHECK(try_catch.HasCaught());
9441 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
9442 try_catch.Exception()->ToString());
9443 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9444 CHECK_GE(interceptor_call_count, 50);
9445}
9446
9447THREADED_TEST(CallICFastApi_TrivialSignature) {
9448 v8::HandleScope scope;
9449 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9450 v8::Handle<v8::FunctionTemplate> method_templ =
9451 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
9452 v8_str("method_data"),
9453 v8::Handle<v8::Signature>());
9454 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9455 proto_templ->Set(v8_str("method"), method_templ);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009456 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
Ben Murdochc7cc0282012-03-05 14:35:55 +00009457 USE(templ);
Andrei Popescu402d9372010-02-26 13:31:12 +00009458 LocalContext context;
9459 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9460 GenerateSomeGarbage();
9461 context->Global()->Set(v8_str("o"), fun->NewInstance());
Ben Murdochc7cc0282012-03-05 14:35:55 +00009462 CompileRun(
Andrei Popescu402d9372010-02-26 13:31:12 +00009463 "var result = 0;"
9464 "for (var i = 0; i < 100; i++) {"
9465 " result = o.method(41);"
Ben Murdochc7cc0282012-03-05 14:35:55 +00009466 "}");
Andrei Popescu402d9372010-02-26 13:31:12 +00009467
9468 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9469}
9470
9471THREADED_TEST(CallICFastApi_SimpleSignature) {
9472 v8::HandleScope scope;
9473 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9474 v8::Handle<v8::FunctionTemplate> method_templ =
9475 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9476 v8_str("method_data"),
9477 v8::Signature::New(fun_templ));
9478 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9479 proto_templ->Set(v8_str("method"), method_templ);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009480 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
Ben Murdochc7cc0282012-03-05 14:35:55 +00009481 CHECK(!templ.IsEmpty());
Andrei Popescu402d9372010-02-26 13:31:12 +00009482 LocalContext context;
9483 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9484 GenerateSomeGarbage();
9485 context->Global()->Set(v8_str("o"), fun->NewInstance());
Ben Murdochc7cc0282012-03-05 14:35:55 +00009486 CompileRun(
Andrei Popescu402d9372010-02-26 13:31:12 +00009487 "o.foo = 17;"
9488 "var receiver = {};"
9489 "receiver.__proto__ = o;"
9490 "var result = 0;"
9491 "for (var i = 0; i < 100; i++) {"
9492 " result = receiver.method(41);"
Ben Murdochc7cc0282012-03-05 14:35:55 +00009493 "}");
Andrei Popescu402d9372010-02-26 13:31:12 +00009494
9495 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9496}
9497
Steve Block6ded16b2010-05-10 14:33:55 +01009498THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) {
Andrei Popescu402d9372010-02-26 13:31:12 +00009499 v8::HandleScope scope;
9500 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9501 v8::Handle<v8::FunctionTemplate> method_templ =
9502 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9503 v8_str("method_data"),
9504 v8::Signature::New(fun_templ));
9505 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9506 proto_templ->Set(v8_str("method"), method_templ);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009507 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
Ben Murdochc7cc0282012-03-05 14:35:55 +00009508 CHECK(!templ.IsEmpty());
Andrei Popescu402d9372010-02-26 13:31:12 +00009509 LocalContext context;
9510 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9511 GenerateSomeGarbage();
9512 context->Global()->Set(v8_str("o"), fun->NewInstance());
Ben Murdochc7cc0282012-03-05 14:35:55 +00009513 CompileRun(
Andrei Popescu402d9372010-02-26 13:31:12 +00009514 "o.foo = 17;"
9515 "var receiver = {};"
9516 "receiver.__proto__ = o;"
9517 "var result = 0;"
9518 "var saved_result = 0;"
9519 "for (var i = 0; i < 100; i++) {"
9520 " result = receiver.method(41);"
9521 " if (i == 50) {"
9522 " saved_result = result;"
9523 " receiver = {method: function(x) { return x - 1 }};"
9524 " }"
Ben Murdochc7cc0282012-03-05 14:35:55 +00009525 "}");
Andrei Popescu402d9372010-02-26 13:31:12 +00009526 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
9527 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9528}
9529
Steve Block6ded16b2010-05-10 14:33:55 +01009530THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) {
9531 v8::HandleScope scope;
9532 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9533 v8::Handle<v8::FunctionTemplate> method_templ =
9534 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9535 v8_str("method_data"),
9536 v8::Signature::New(fun_templ));
9537 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9538 proto_templ->Set(v8_str("method"), method_templ);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009539 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
Ben Murdochc7cc0282012-03-05 14:35:55 +00009540 CHECK(!templ.IsEmpty());
Steve Block6ded16b2010-05-10 14:33:55 +01009541 LocalContext context;
9542 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9543 GenerateSomeGarbage();
9544 context->Global()->Set(v8_str("o"), fun->NewInstance());
9545 v8::TryCatch try_catch;
Ben Murdochc7cc0282012-03-05 14:35:55 +00009546 CompileRun(
Steve Block6ded16b2010-05-10 14:33:55 +01009547 "o.foo = 17;"
9548 "var receiver = {};"
9549 "receiver.__proto__ = o;"
9550 "var result = 0;"
9551 "var saved_result = 0;"
9552 "for (var i = 0; i < 100; i++) {"
9553 " result = receiver.method(41);"
9554 " if (i == 50) {"
9555 " saved_result = result;"
9556 " receiver = 333;"
9557 " }"
Ben Murdochc7cc0282012-03-05 14:35:55 +00009558 "}");
Steve Block6ded16b2010-05-10 14:33:55 +01009559 CHECK(try_catch.HasCaught());
9560 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
9561 try_catch.Exception()->ToString());
9562 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9563}
9564
Leon Clarke4515c472010-02-03 11:58:03 +00009565
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009566v8::Handle<Value> keyed_call_ic_function;
9567
9568static v8::Handle<Value> InterceptorKeyedCallICGetter(
9569 Local<String> name, const AccessorInfo& info) {
9570 ApiTestFuzzer::Fuzz();
9571 if (v8_str("x")->Equals(name)) {
9572 return keyed_call_ic_function;
9573 }
9574 return v8::Handle<Value>();
9575}
9576
9577
9578// Test the case when we stored cacheable lookup into
9579// a stub, but the function name changed (to another cacheable function).
9580THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
9581 v8::HandleScope scope;
9582 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9583 templ->SetNamedPropertyHandler(NoBlockGetterX);
9584 LocalContext context;
9585 context->Global()->Set(v8_str("o"), templ->NewInstance());
Ben Murdochc7cc0282012-03-05 14:35:55 +00009586 CompileRun(
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009587 "proto = new Object();"
9588 "proto.y = function(x) { return x + 1; };"
9589 "proto.z = function(x) { return x - 1; };"
9590 "o.__proto__ = proto;"
9591 "var result = 0;"
9592 "var method = 'y';"
9593 "for (var i = 0; i < 10; i++) {"
9594 " if (i == 5) { method = 'z'; };"
9595 " result += o[method](41);"
Ben Murdochc7cc0282012-03-05 14:35:55 +00009596 "}");
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009597 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9598}
9599
9600
9601// Test the case when we stored cacheable lookup into
9602// a stub, but the function name changed (and the new function is present
9603// both before and after the interceptor in the prototype chain).
9604THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
9605 v8::HandleScope scope;
9606 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9607 templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
9608 LocalContext context;
9609 context->Global()->Set(v8_str("proto1"), templ->NewInstance());
9610 keyed_call_ic_function =
9611 v8_compile("function f(x) { return x - 1; }; f")->Run();
Ben Murdochc7cc0282012-03-05 14:35:55 +00009612 CompileRun(
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009613 "o = new Object();"
9614 "proto2 = new Object();"
9615 "o.y = function(x) { return x + 1; };"
9616 "proto2.y = function(x) { return x + 2; };"
9617 "o.__proto__ = proto1;"
9618 "proto1.__proto__ = proto2;"
9619 "var result = 0;"
9620 "var method = 'x';"
9621 "for (var i = 0; i < 10; i++) {"
9622 " if (i == 5) { method = 'y'; };"
9623 " result += o[method](41);"
Ben Murdochc7cc0282012-03-05 14:35:55 +00009624 "}");
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009625 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9626}
9627
9628
9629// Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
9630// on the global object.
9631THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
9632 v8::HandleScope scope;
9633 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9634 templ->SetNamedPropertyHandler(NoBlockGetterX);
9635 LocalContext context;
9636 context->Global()->Set(v8_str("o"), templ->NewInstance());
Ben Murdochc7cc0282012-03-05 14:35:55 +00009637 CompileRun(
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009638 "function inc(x) { return x + 1; };"
9639 "inc(1);"
9640 "function dec(x) { return x - 1; };"
9641 "dec(1);"
9642 "o.__proto__ = this;"
9643 "this.__proto__.x = inc;"
9644 "this.__proto__.y = dec;"
9645 "var result = 0;"
9646 "var method = 'x';"
9647 "for (var i = 0; i < 10; i++) {"
9648 " if (i == 5) { method = 'y'; };"
9649 " result += o[method](41);"
Ben Murdochc7cc0282012-03-05 14:35:55 +00009650 "}");
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009651 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9652}
9653
9654
9655// Test the case when actual function to call sits on global object.
9656THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
9657 v8::HandleScope scope;
9658 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9659 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9660 LocalContext context;
9661 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9662
Ben Murdochc7cc0282012-03-05 14:35:55 +00009663 CompileRun(
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009664 "function len(x) { return x.length; };"
9665 "o.__proto__ = this;"
9666 "var m = 'parseFloat';"
9667 "var result = 0;"
9668 "for (var i = 0; i < 10; i++) {"
9669 " if (i == 5) {"
9670 " m = 'len';"
9671 " saved_result = result;"
9672 " };"
9673 " result = o[m]('239');"
Ben Murdochc7cc0282012-03-05 14:35:55 +00009674 "}");
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009675 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
9676 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9677}
9678
9679// Test the map transition before the interceptor.
9680THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
9681 v8::HandleScope scope;
9682 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9683 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9684 LocalContext context;
9685 context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
9686
Ben Murdochc7cc0282012-03-05 14:35:55 +00009687 CompileRun(
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009688 "var o = new Object();"
9689 "o.__proto__ = proto;"
9690 "o.method = function(x) { return x + 1; };"
9691 "var m = 'method';"
9692 "var result = 0;"
9693 "for (var i = 0; i < 10; i++) {"
9694 " if (i == 5) { o.method = function(x) { return x - 1; }; };"
9695 " result += o[m](41);"
Ben Murdochc7cc0282012-03-05 14:35:55 +00009696 "}");
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009697 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9698}
9699
9700
9701// Test the map transition after the interceptor.
9702THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
9703 v8::HandleScope scope;
9704 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9705 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9706 LocalContext context;
9707 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9708
Ben Murdochc7cc0282012-03-05 14:35:55 +00009709 CompileRun(
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009710 "var proto = new Object();"
9711 "o.__proto__ = proto;"
9712 "proto.method = function(x) { return x + 1; };"
9713 "var m = 'method';"
9714 "var result = 0;"
9715 "for (var i = 0; i < 10; i++) {"
9716 " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
9717 " result += o[m](41);"
Ben Murdochc7cc0282012-03-05 14:35:55 +00009718 "}");
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009719 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9720}
9721
9722
Steve Blocka7e24c12009-10-30 11:49:00 +00009723static int interceptor_call_count = 0;
9724
9725static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
9726 const AccessorInfo& info) {
9727 ApiTestFuzzer::Fuzz();
9728 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
9729 return call_ic_function2;
9730 }
9731 return v8::Handle<Value>();
9732}
9733
9734
9735// This test should hit load and call ICs for the interceptor case.
9736// Once in a while, the interceptor will reply that a property was not
9737// found in which case we should get a reference error.
9738THREADED_TEST(InterceptorICReferenceErrors) {
9739 v8::HandleScope scope;
9740 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9741 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
9742 LocalContext context(0, templ, v8::Handle<Value>());
9743 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
9744 v8::Handle<Value> value = CompileRun(
9745 "function f() {"
9746 " for (var i = 0; i < 1000; i++) {"
9747 " try { x; } catch(e) { return true; }"
9748 " }"
9749 " return false;"
9750 "};"
9751 "f();");
9752 CHECK_EQ(true, value->BooleanValue());
9753 interceptor_call_count = 0;
9754 value = CompileRun(
9755 "function g() {"
9756 " for (var i = 0; i < 1000; i++) {"
9757 " try { x(42); } catch(e) { return true; }"
9758 " }"
9759 " return false;"
9760 "};"
9761 "g();");
9762 CHECK_EQ(true, value->BooleanValue());
9763}
9764
9765
9766static int interceptor_ic_exception_get_count = 0;
9767
9768static v8::Handle<Value> InterceptorICExceptionGetter(
9769 Local<String> name,
9770 const AccessorInfo& info) {
9771 ApiTestFuzzer::Fuzz();
9772 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
9773 return call_ic_function3;
9774 }
9775 if (interceptor_ic_exception_get_count == 20) {
9776 return v8::ThrowException(v8_num(42));
9777 }
9778 // Do not handle get for properties other than x.
9779 return v8::Handle<Value>();
9780}
9781
9782// Test interceptor load/call IC where the interceptor throws an
9783// exception once in a while.
9784THREADED_TEST(InterceptorICGetterExceptions) {
9785 interceptor_ic_exception_get_count = 0;
9786 v8::HandleScope scope;
9787 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9788 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
9789 LocalContext context(0, templ, v8::Handle<Value>());
9790 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
9791 v8::Handle<Value> value = CompileRun(
9792 "function f() {"
9793 " for (var i = 0; i < 100; i++) {"
9794 " try { x; } catch(e) { return true; }"
9795 " }"
9796 " return false;"
9797 "};"
9798 "f();");
9799 CHECK_EQ(true, value->BooleanValue());
9800 interceptor_ic_exception_get_count = 0;
9801 value = CompileRun(
9802 "function f() {"
9803 " for (var i = 0; i < 100; i++) {"
9804 " try { x(42); } catch(e) { return true; }"
9805 " }"
9806 " return false;"
9807 "};"
9808 "f();");
9809 CHECK_EQ(true, value->BooleanValue());
9810}
9811
9812
9813static int interceptor_ic_exception_set_count = 0;
9814
9815static v8::Handle<Value> InterceptorICExceptionSetter(
9816 Local<String> key, Local<Value> value, const AccessorInfo&) {
9817 ApiTestFuzzer::Fuzz();
9818 if (++interceptor_ic_exception_set_count > 20) {
9819 return v8::ThrowException(v8_num(42));
9820 }
9821 // Do not actually handle setting.
9822 return v8::Handle<Value>();
9823}
9824
9825// Test interceptor store IC where the interceptor throws an exception
9826// once in a while.
9827THREADED_TEST(InterceptorICSetterExceptions) {
9828 interceptor_ic_exception_set_count = 0;
9829 v8::HandleScope scope;
9830 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9831 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
9832 LocalContext context(0, templ, v8::Handle<Value>());
9833 v8::Handle<Value> value = CompileRun(
9834 "function f() {"
9835 " for (var i = 0; i < 100; i++) {"
9836 " try { x = 42; } catch(e) { return true; }"
9837 " }"
9838 " return false;"
9839 "};"
9840 "f();");
9841 CHECK_EQ(true, value->BooleanValue());
9842}
9843
9844
9845// Test that we ignore null interceptors.
9846THREADED_TEST(NullNamedInterceptor) {
9847 v8::HandleScope scope;
9848 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9849 templ->SetNamedPropertyHandler(0);
9850 LocalContext context;
9851 templ->Set("x", v8_num(42));
9852 v8::Handle<v8::Object> obj = templ->NewInstance();
9853 context->Global()->Set(v8_str("obj"), obj);
9854 v8::Handle<Value> value = CompileRun("obj.x");
9855 CHECK(value->IsInt32());
9856 CHECK_EQ(42, value->Int32Value());
9857}
9858
9859
9860// Test that we ignore null interceptors.
9861THREADED_TEST(NullIndexedInterceptor) {
9862 v8::HandleScope scope;
9863 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9864 templ->SetIndexedPropertyHandler(0);
9865 LocalContext context;
9866 templ->Set("42", v8_num(42));
9867 v8::Handle<v8::Object> obj = templ->NewInstance();
9868 context->Global()->Set(v8_str("obj"), obj);
9869 v8::Handle<Value> value = CompileRun("obj[42]");
9870 CHECK(value->IsInt32());
9871 CHECK_EQ(42, value->Int32Value());
9872}
9873
9874
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009875THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
9876 v8::HandleScope scope;
9877 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9878 templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9879 LocalContext env;
9880 env->Global()->Set(v8_str("obj"),
9881 templ->GetFunction()->NewInstance());
9882 ExpectTrue("obj.x === 42");
9883 ExpectTrue("!obj.propertyIsEnumerable('x')");
9884}
9885
9886
Ben Murdoch8b112d22011-06-08 16:22:53 +01009887static Handle<Value> ThrowingGetter(Local<String> name,
9888 const AccessorInfo& info) {
9889 ApiTestFuzzer::Fuzz();
9890 ThrowException(Handle<Value>());
9891 return Undefined();
9892}
9893
9894
9895THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
9896 HandleScope scope;
9897 LocalContext context;
9898
9899 Local<FunctionTemplate> templ = FunctionTemplate::New();
9900 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
9901 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
9902
9903 Local<Object> instance = templ->GetFunction()->NewInstance();
9904
9905 Local<Object> another = Object::New();
9906 another->SetPrototype(instance);
9907
9908 Local<Object> with_js_getter = CompileRun(
9909 "o = {};\n"
9910 "o.__defineGetter__('f', function() { throw undefined; });\n"
9911 "o\n").As<Object>();
9912 CHECK(!with_js_getter.IsEmpty());
9913
9914 TryCatch try_catch;
9915
9916 Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
9917 CHECK(try_catch.HasCaught());
9918 try_catch.Reset();
9919 CHECK(result.IsEmpty());
9920
9921 result = another->GetRealNamedProperty(v8_str("f"));
9922 CHECK(try_catch.HasCaught());
9923 try_catch.Reset();
9924 CHECK(result.IsEmpty());
9925
9926 result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
9927 CHECK(try_catch.HasCaught());
9928 try_catch.Reset();
9929 CHECK(result.IsEmpty());
9930
9931 result = another->Get(v8_str("f"));
9932 CHECK(try_catch.HasCaught());
9933 try_catch.Reset();
9934 CHECK(result.IsEmpty());
9935
9936 result = with_js_getter->GetRealNamedProperty(v8_str("f"));
9937 CHECK(try_catch.HasCaught());
9938 try_catch.Reset();
9939 CHECK(result.IsEmpty());
9940
9941 result = with_js_getter->Get(v8_str("f"));
9942 CHECK(try_catch.HasCaught());
9943 try_catch.Reset();
9944 CHECK(result.IsEmpty());
9945}
9946
9947
9948static Handle<Value> ThrowingCallbackWithTryCatch(const Arguments& args) {
9949 TryCatch try_catch;
9950 // Verboseness is important: it triggers message delivery which can call into
9951 // external code.
9952 try_catch.SetVerbose(true);
9953 CompileRun("throw 'from JS';");
9954 CHECK(try_catch.HasCaught());
9955 CHECK(!i::Isolate::Current()->has_pending_exception());
9956 CHECK(!i::Isolate::Current()->has_scheduled_exception());
9957 return Undefined();
9958}
9959
9960
9961static int call_depth;
9962
9963
9964static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
9965 TryCatch try_catch;
9966}
9967
9968
9969static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
9970 if (--call_depth) CompileRun("throw 'ThrowInJS';");
9971}
9972
9973
9974static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
9975 if (--call_depth) ThrowException(v8_str("ThrowViaApi"));
9976}
9977
9978
9979static void WebKitLike(Handle<Message> message, Handle<Value> data) {
9980 Handle<String> errorMessageString = message->Get();
9981 CHECK(!errorMessageString.IsEmpty());
9982 message->GetStackTrace();
9983 message->GetScriptResourceName();
9984}
9985
9986THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
9987 HandleScope scope;
9988 LocalContext context;
9989
9990 Local<Function> func =
9991 FunctionTemplate::New(ThrowingCallbackWithTryCatch)->GetFunction();
9992 context->Global()->Set(v8_str("func"), func);
9993
9994 MessageCallback callbacks[] =
9995 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
9996 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
9997 MessageCallback callback = callbacks[i];
9998 if (callback != NULL) {
9999 V8::AddMessageListener(callback);
10000 }
Ben Murdoch257744e2011-11-30 15:57:28 +000010001 // Some small number to control number of times message handler should
10002 // throw an exception.
Ben Murdoch8b112d22011-06-08 16:22:53 +010010003 call_depth = 5;
10004 ExpectFalse(
10005 "var thrown = false;\n"
10006 "try { func(); } catch(e) { thrown = true; }\n"
10007 "thrown\n");
10008 if (callback != NULL) {
10009 V8::RemoveMessageListeners(callback);
10010 }
10011 }
10012}
10013
10014
Steve Blocka7e24c12009-10-30 11:49:00 +000010015static v8::Handle<Value> ParentGetter(Local<String> name,
10016 const AccessorInfo& info) {
10017 ApiTestFuzzer::Fuzz();
10018 return v8_num(1);
10019}
10020
10021
10022static v8::Handle<Value> ChildGetter(Local<String> name,
10023 const AccessorInfo& info) {
10024 ApiTestFuzzer::Fuzz();
10025 return v8_num(42);
10026}
10027
10028
10029THREADED_TEST(Overriding) {
10030 v8::HandleScope scope;
10031 LocalContext context;
10032
10033 // Parent template.
10034 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
10035 Local<ObjectTemplate> parent_instance_templ =
10036 parent_templ->InstanceTemplate();
10037 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
10038
10039 // Template that inherits from the parent template.
10040 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
10041 Local<ObjectTemplate> child_instance_templ =
10042 child_templ->InstanceTemplate();
10043 child_templ->Inherit(parent_templ);
10044 // Override 'f'. The child version of 'f' should get called for child
10045 // instances.
10046 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
10047 // Add 'g' twice. The 'g' added last should get called for instances.
10048 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
10049 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
10050
10051 // Add 'h' as an accessor to the proto template with ReadOnly attributes
10052 // so 'h' can be shadowed on the instance object.
10053 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
10054 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
10055 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
10056
10057 // Add 'i' as an accessor to the instance template with ReadOnly attributes
10058 // but the attribute does not have effect because it is duplicated with
10059 // NULL setter.
10060 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
10061 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
10062
10063
10064
10065 // Instantiate the child template.
10066 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
10067
10068 // Check that the child function overrides the parent one.
10069 context->Global()->Set(v8_str("o"), instance);
10070 Local<Value> value = v8_compile("o.f")->Run();
10071 // Check that the 'g' that was added last is hit.
10072 CHECK_EQ(42, value->Int32Value());
10073 value = v8_compile("o.g")->Run();
10074 CHECK_EQ(42, value->Int32Value());
10075
10076 // Check 'h' can be shadowed.
10077 value = v8_compile("o.h = 3; o.h")->Run();
10078 CHECK_EQ(3, value->Int32Value());
10079
10080 // Check 'i' is cannot be shadowed or changed.
10081 value = v8_compile("o.i = 3; o.i")->Run();
10082 CHECK_EQ(42, value->Int32Value());
10083}
10084
10085
10086static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
10087 ApiTestFuzzer::Fuzz();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010088 return v8::Boolean::New(args.IsConstructCall());
Steve Blocka7e24c12009-10-30 11:49:00 +000010089}
10090
10091
10092THREADED_TEST(IsConstructCall) {
10093 v8::HandleScope scope;
10094
10095 // Function template with call handler.
10096 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
10097 templ->SetCallHandler(IsConstructHandler);
10098
10099 LocalContext context;
10100
10101 context->Global()->Set(v8_str("f"), templ->GetFunction());
10102 Local<Value> value = v8_compile("f()")->Run();
10103 CHECK(!value->BooleanValue());
10104 value = v8_compile("new f()")->Run();
10105 CHECK(value->BooleanValue());
10106}
10107
10108
10109THREADED_TEST(ObjectProtoToString) {
10110 v8::HandleScope scope;
10111 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
10112 templ->SetClassName(v8_str("MyClass"));
10113
10114 LocalContext context;
10115
10116 Local<String> customized_tostring = v8_str("customized toString");
10117
10118 // Replace Object.prototype.toString
10119 v8_compile("Object.prototype.toString = function() {"
10120 " return 'customized toString';"
10121 "}")->Run();
10122
10123 // Normal ToString call should call replaced Object.prototype.toString
10124 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
10125 Local<String> value = instance->ToString();
10126 CHECK(value->IsString() && value->Equals(customized_tostring));
10127
10128 // ObjectProtoToString should not call replace toString function.
10129 value = instance->ObjectProtoToString();
10130 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
10131
10132 // Check global
10133 value = context->Global()->ObjectProtoToString();
10134 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
10135
10136 // Check ordinary object
10137 Local<Value> object = v8_compile("new Object()")->Run();
Steve Block6ded16b2010-05-10 14:33:55 +010010138 value = object.As<v8::Object>()->ObjectProtoToString();
Steve Blocka7e24c12009-10-30 11:49:00 +000010139 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
10140}
10141
10142
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -080010143THREADED_TEST(ObjectGetConstructorName) {
10144 v8::HandleScope scope;
10145 LocalContext context;
10146 v8_compile("function Parent() {};"
10147 "function Child() {};"
10148 "Child.prototype = new Parent();"
10149 "var outer = { inner: function() { } };"
10150 "var p = new Parent();"
10151 "var c = new Child();"
10152 "var x = new outer.inner();")->Run();
10153
10154 Local<v8::Value> p = context->Global()->Get(v8_str("p"));
10155 CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
10156 v8_str("Parent")));
10157
10158 Local<v8::Value> c = context->Global()->Get(v8_str("c"));
10159 CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
10160 v8_str("Child")));
10161
10162 Local<v8::Value> x = context->Global()->Get(v8_str("x"));
10163 CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
10164 v8_str("outer.inner")));
10165}
10166
10167
Steve Blocka7e24c12009-10-30 11:49:00 +000010168bool ApiTestFuzzer::fuzzing_ = false;
Steve Block8defd9f2010-07-08 12:39:36 +010010169i::Semaphore* ApiTestFuzzer::all_tests_done_=
10170 i::OS::CreateSemaphore(0);
Steve Blocka7e24c12009-10-30 11:49:00 +000010171int ApiTestFuzzer::active_tests_;
10172int ApiTestFuzzer::tests_being_run_;
10173int ApiTestFuzzer::current_;
10174
10175
10176// We are in a callback and want to switch to another thread (if we
10177// are currently running the thread fuzzing test).
10178void ApiTestFuzzer::Fuzz() {
10179 if (!fuzzing_) return;
10180 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
10181 test->ContextSwitch();
10182}
10183
10184
10185// Let the next thread go. Since it is also waiting on the V8 lock it may
10186// not start immediately.
10187bool ApiTestFuzzer::NextThread() {
10188 int test_position = GetNextTestNumber();
Steve Blockd0582a62009-12-15 09:54:21 +000010189 const char* test_name = RegisterThreadedTest::nth(current_)->name();
Steve Blocka7e24c12009-10-30 11:49:00 +000010190 if (test_position == current_) {
Steve Blockd0582a62009-12-15 09:54:21 +000010191 if (kLogThreading)
10192 printf("Stay with %s\n", test_name);
Steve Blocka7e24c12009-10-30 11:49:00 +000010193 return false;
10194 }
Steve Blockd0582a62009-12-15 09:54:21 +000010195 if (kLogThreading) {
10196 printf("Switch from %s to %s\n",
10197 test_name,
10198 RegisterThreadedTest::nth(test_position)->name());
10199 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010200 current_ = test_position;
10201 RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
10202 return true;
10203}
10204
10205
10206void ApiTestFuzzer::Run() {
10207 // When it is our turn...
10208 gate_->Wait();
10209 {
10210 // ... get the V8 lock and start running the test.
10211 v8::Locker locker;
10212 CallTest();
10213 }
10214 // This test finished.
10215 active_ = false;
10216 active_tests_--;
10217 // If it was the last then signal that fact.
10218 if (active_tests_ == 0) {
10219 all_tests_done_->Signal();
10220 } else {
10221 // Otherwise select a new test and start that.
10222 NextThread();
10223 }
10224}
10225
10226
10227static unsigned linear_congruential_generator;
10228
10229
Ben Murdochc7cc0282012-03-05 14:35:55 +000010230void ApiTestFuzzer::SetUp(PartOfTest part) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010231 linear_congruential_generator = i::FLAG_testing_prng_seed;
10232 fuzzing_ = true;
Ben Murdoch257744e2011-11-30 15:57:28 +000010233 int count = RegisterThreadedTest::count();
10234 int start = count * part / (LAST_PART + 1);
10235 int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
10236 active_tests_ = tests_being_run_ = end - start + 1;
Steve Blocka7e24c12009-10-30 11:49:00 +000010237 for (int i = 0; i < tests_being_run_; i++) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010238 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
Steve Blocka7e24c12009-10-30 11:49:00 +000010239 }
10240 for (int i = 0; i < active_tests_; i++) {
10241 RegisterThreadedTest::nth(i)->fuzzer_->Start();
10242 }
10243}
10244
10245
10246static void CallTestNumber(int test_number) {
10247 (RegisterThreadedTest::nth(test_number)->callback())();
10248}
10249
10250
10251void ApiTestFuzzer::RunAllTests() {
10252 // Set off the first test.
10253 current_ = -1;
10254 NextThread();
10255 // Wait till they are all done.
10256 all_tests_done_->Wait();
10257}
10258
10259
10260int ApiTestFuzzer::GetNextTestNumber() {
10261 int next_test;
10262 do {
10263 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
10264 linear_congruential_generator *= 1664525u;
10265 linear_congruential_generator += 1013904223u;
10266 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
10267 return next_test;
10268}
10269
10270
10271void ApiTestFuzzer::ContextSwitch() {
10272 // If the new thread is the same as the current thread there is nothing to do.
10273 if (NextThread()) {
10274 // Now it can start.
10275 v8::Unlocker unlocker;
10276 // Wait till someone starts us again.
10277 gate_->Wait();
10278 // And we're off.
10279 }
10280}
10281
10282
10283void ApiTestFuzzer::TearDown() {
10284 fuzzing_ = false;
10285 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
10286 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
10287 if (fuzzer != NULL) fuzzer->Join();
10288 }
10289}
10290
10291
10292// Lets not be needlessly self-referential.
10293TEST(Threading) {
Ben Murdochc7cc0282012-03-05 14:35:55 +000010294 ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
Steve Blocka7e24c12009-10-30 11:49:00 +000010295 ApiTestFuzzer::RunAllTests();
10296 ApiTestFuzzer::TearDown();
10297}
10298
10299TEST(Threading2) {
Ben Murdochc7cc0282012-03-05 14:35:55 +000010300 ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
Steve Blocka7e24c12009-10-30 11:49:00 +000010301 ApiTestFuzzer::RunAllTests();
10302 ApiTestFuzzer::TearDown();
10303}
10304
Ben Murdoch257744e2011-11-30 15:57:28 +000010305TEST(Threading3) {
Ben Murdochc7cc0282012-03-05 14:35:55 +000010306 ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
Ben Murdoch257744e2011-11-30 15:57:28 +000010307 ApiTestFuzzer::RunAllTests();
10308 ApiTestFuzzer::TearDown();
10309}
10310
10311TEST(Threading4) {
Ben Murdochc7cc0282012-03-05 14:35:55 +000010312 ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
Ben Murdoch257744e2011-11-30 15:57:28 +000010313 ApiTestFuzzer::RunAllTests();
10314 ApiTestFuzzer::TearDown();
10315}
Steve Blocka7e24c12009-10-30 11:49:00 +000010316
10317void ApiTestFuzzer::CallTest() {
Steve Blockd0582a62009-12-15 09:54:21 +000010318 if (kLogThreading)
10319 printf("Start test %d\n", test_number_);
Steve Blocka7e24c12009-10-30 11:49:00 +000010320 CallTestNumber(test_number_);
Steve Blockd0582a62009-12-15 09:54:21 +000010321 if (kLogThreading)
10322 printf("End test %d\n", test_number_);
Steve Blocka7e24c12009-10-30 11:49:00 +000010323}
10324
10325
10326static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
10327 CHECK(v8::Locker::IsLocked());
10328 ApiTestFuzzer::Fuzz();
10329 v8::Unlocker unlocker;
10330 const char* code = "throw 7;";
10331 {
10332 v8::Locker nested_locker;
10333 v8::HandleScope scope;
10334 v8::Handle<Value> exception;
10335 { v8::TryCatch try_catch;
10336 v8::Handle<Value> value = CompileRun(code);
10337 CHECK(value.IsEmpty());
10338 CHECK(try_catch.HasCaught());
10339 // Make sure to wrap the exception in a new handle because
10340 // the handle returned from the TryCatch is destroyed
10341 // when the TryCatch is destroyed.
10342 exception = Local<Value>::New(try_catch.Exception());
10343 }
10344 return v8::ThrowException(exception);
10345 }
10346}
10347
10348
10349static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
10350 CHECK(v8::Locker::IsLocked());
10351 ApiTestFuzzer::Fuzz();
10352 v8::Unlocker unlocker;
10353 const char* code = "throw 7;";
10354 {
10355 v8::Locker nested_locker;
10356 v8::HandleScope scope;
10357 v8::Handle<Value> value = CompileRun(code);
10358 CHECK(value.IsEmpty());
10359 return v8_str("foo");
10360 }
10361}
10362
10363
10364// These are locking tests that don't need to be run again
10365// as part of the locking aggregation tests.
10366TEST(NestedLockers) {
10367 v8::Locker locker;
10368 CHECK(v8::Locker::IsLocked());
10369 v8::HandleScope scope;
10370 LocalContext env;
10371 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
10372 Local<Function> fun = fun_templ->GetFunction();
10373 env->Global()->Set(v8_str("throw_in_js"), fun);
10374 Local<Script> script = v8_compile("(function () {"
10375 " try {"
10376 " throw_in_js();"
10377 " return 42;"
10378 " } catch (e) {"
10379 " return e * 13;"
10380 " }"
10381 "})();");
10382 CHECK_EQ(91, script->Run()->Int32Value());
10383}
10384
10385
10386// These are locking tests that don't need to be run again
10387// as part of the locking aggregation tests.
10388TEST(NestedLockersNoTryCatch) {
10389 v8::Locker locker;
10390 v8::HandleScope scope;
10391 LocalContext env;
10392 Local<v8::FunctionTemplate> fun_templ =
10393 v8::FunctionTemplate::New(ThrowInJSNoCatch);
10394 Local<Function> fun = fun_templ->GetFunction();
10395 env->Global()->Set(v8_str("throw_in_js"), fun);
10396 Local<Script> script = v8_compile("(function () {"
10397 " try {"
10398 " throw_in_js();"
10399 " return 42;"
10400 " } catch (e) {"
10401 " return e * 13;"
10402 " }"
10403 "})();");
10404 CHECK_EQ(91, script->Run()->Int32Value());
10405}
10406
10407
10408THREADED_TEST(RecursiveLocking) {
10409 v8::Locker locker;
10410 {
10411 v8::Locker locker2;
10412 CHECK(v8::Locker::IsLocked());
10413 }
10414}
10415
10416
10417static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
10418 ApiTestFuzzer::Fuzz();
10419 v8::Unlocker unlocker;
10420 return v8::Undefined();
10421}
10422
10423
10424THREADED_TEST(LockUnlockLock) {
10425 {
10426 v8::Locker locker;
10427 v8::HandleScope scope;
10428 LocalContext env;
10429 Local<v8::FunctionTemplate> fun_templ =
10430 v8::FunctionTemplate::New(UnlockForAMoment);
10431 Local<Function> fun = fun_templ->GetFunction();
10432 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
10433 Local<Script> script = v8_compile("(function () {"
10434 " unlock_for_a_moment();"
10435 " return 42;"
10436 "})();");
10437 CHECK_EQ(42, script->Run()->Int32Value());
10438 }
10439 {
10440 v8::Locker locker;
10441 v8::HandleScope scope;
10442 LocalContext env;
10443 Local<v8::FunctionTemplate> fun_templ =
10444 v8::FunctionTemplate::New(UnlockForAMoment);
10445 Local<Function> fun = fun_templ->GetFunction();
10446 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
10447 Local<Script> script = v8_compile("(function () {"
10448 " unlock_for_a_moment();"
10449 " return 42;"
10450 "})();");
10451 CHECK_EQ(42, script->Run()->Int32Value());
10452 }
10453}
10454
10455
Leon Clarked91b9f72010-01-27 17:25:45 +000010456static int GetGlobalObjectsCount() {
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010457 i::Isolate::Current()->heap()->EnsureHeapIsIterable();
Leon Clarkeeab96aa2010-01-27 16:31:12 +000010458 int count = 0;
Steve Block8defd9f2010-07-08 12:39:36 +010010459 i::HeapIterator it;
Leon Clarked91b9f72010-01-27 17:25:45 +000010460 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
10461 if (object->IsJSGlobalObject()) count++;
10462 return count;
10463}
10464
10465
Ben Murdochf87a2032010-10-22 12:50:53 +010010466static void CheckSurvivingGlobalObjectsCount(int expected) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010467 // We need to collect all garbage twice to be sure that everything
10468 // has been collected. This is because inline caches are cleared in
10469 // the first garbage collection but some of the maps have already
10470 // been marked at that point. Therefore some of the maps are not
10471 // collected until the second garbage collection.
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010472 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
10473 HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
Leon Clarked91b9f72010-01-27 17:25:45 +000010474 int count = GetGlobalObjectsCount();
Steve Blocka7e24c12009-10-30 11:49:00 +000010475#ifdef DEBUG
Steve Block44f0eee2011-05-26 01:26:41 +010010476 if (count != expected) HEAP->TracePathToGlobal();
Steve Blocka7e24c12009-10-30 11:49:00 +000010477#endif
Ben Murdochf87a2032010-10-22 12:50:53 +010010478 CHECK_EQ(expected, count);
Steve Blocka7e24c12009-10-30 11:49:00 +000010479}
10480
10481
10482TEST(DontLeakGlobalObjects) {
10483 // Regression test for issues 1139850 and 1174891.
10484
10485 v8::V8::Initialize();
10486
Steve Blocka7e24c12009-10-30 11:49:00 +000010487 for (int i = 0; i < 5; i++) {
10488 { v8::HandleScope scope;
10489 LocalContext context;
10490 }
Ben Murdochf87a2032010-10-22 12:50:53 +010010491 CheckSurvivingGlobalObjectsCount(0);
Steve Blocka7e24c12009-10-30 11:49:00 +000010492
10493 { v8::HandleScope scope;
10494 LocalContext context;
10495 v8_compile("Date")->Run();
10496 }
Ben Murdochf87a2032010-10-22 12:50:53 +010010497 CheckSurvivingGlobalObjectsCount(0);
Steve Blocka7e24c12009-10-30 11:49:00 +000010498
10499 { v8::HandleScope scope;
10500 LocalContext context;
10501 v8_compile("/aaa/")->Run();
10502 }
Ben Murdochf87a2032010-10-22 12:50:53 +010010503 CheckSurvivingGlobalObjectsCount(0);
Steve Blocka7e24c12009-10-30 11:49:00 +000010504
10505 { v8::HandleScope scope;
10506 const char* extension_list[] = { "v8/gc" };
10507 v8::ExtensionConfiguration extensions(1, extension_list);
10508 LocalContext context(&extensions);
10509 v8_compile("gc();")->Run();
10510 }
Ben Murdochf87a2032010-10-22 12:50:53 +010010511 CheckSurvivingGlobalObjectsCount(0);
Steve Blocka7e24c12009-10-30 11:49:00 +000010512 }
10513}
10514
10515
10516v8::Persistent<v8::Object> some_object;
10517v8::Persistent<v8::Object> bad_handle;
10518
Kristian Monsen50ef84f2010-07-29 15:18:00 +010010519void NewPersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010520 v8::HandleScope scope;
10521 bad_handle = v8::Persistent<v8::Object>::New(some_object);
Kristian Monsen50ef84f2010-07-29 15:18:00 +010010522 handle.Dispose();
Steve Blocka7e24c12009-10-30 11:49:00 +000010523}
10524
10525
10526THREADED_TEST(NewPersistentHandleFromWeakCallback) {
10527 LocalContext context;
10528
10529 v8::Persistent<v8::Object> handle1, handle2;
10530 {
10531 v8::HandleScope scope;
10532 some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
10533 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
10534 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
10535 }
10536 // Note: order is implementation dependent alas: currently
10537 // global handle nodes are processed by PostGarbageCollectionProcessing
10538 // in reverse allocation order, so if second allocated handle is deleted,
10539 // weak callback of the first handle would be able to 'reallocate' it.
10540 handle1.MakeWeak(NULL, NewPersistentHandleCallback);
10541 handle2.Dispose();
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010542 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +000010543}
10544
10545
10546v8::Persistent<v8::Object> to_be_disposed;
10547
10548void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
10549 to_be_disposed.Dispose();
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010550 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Kristian Monsen50ef84f2010-07-29 15:18:00 +010010551 handle.Dispose();
Steve Blocka7e24c12009-10-30 11:49:00 +000010552}
10553
10554
10555THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
10556 LocalContext context;
10557
10558 v8::Persistent<v8::Object> handle1, handle2;
10559 {
10560 v8::HandleScope scope;
10561 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
10562 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
10563 }
10564 handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
10565 to_be_disposed = handle2;
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010566 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +000010567}
10568
Steve Blockd0582a62009-12-15 09:54:21 +000010569void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
10570 handle.Dispose();
10571}
10572
10573void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
10574 v8::HandleScope scope;
10575 v8::Persistent<v8::Object>::New(v8::Object::New());
Kristian Monsen50ef84f2010-07-29 15:18:00 +010010576 handle.Dispose();
Steve Blockd0582a62009-12-15 09:54:21 +000010577}
10578
10579
10580THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
10581 LocalContext context;
10582
10583 v8::Persistent<v8::Object> handle1, handle2, handle3;
10584 {
10585 v8::HandleScope scope;
10586 handle3 = v8::Persistent<v8::Object>::New(v8::Object::New());
10587 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
10588 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
10589 }
10590 handle2.MakeWeak(NULL, DisposingCallback);
10591 handle3.MakeWeak(NULL, HandleCreatingCallback);
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010592 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blockd0582a62009-12-15 09:54:21 +000010593}
10594
Steve Blocka7e24c12009-10-30 11:49:00 +000010595
10596THREADED_TEST(CheckForCrossContextObjectLiterals) {
10597 v8::V8::Initialize();
10598
10599 const int nof = 2;
10600 const char* sources[nof] = {
10601 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
10602 "Object()"
10603 };
10604
10605 for (int i = 0; i < nof; i++) {
10606 const char* source = sources[i];
10607 { v8::HandleScope scope;
10608 LocalContext context;
10609 CompileRun(source);
10610 }
10611 { v8::HandleScope scope;
10612 LocalContext context;
10613 CompileRun(source);
10614 }
10615 }
10616}
10617
10618
10619static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
10620 v8::HandleScope inner;
10621 env->Enter();
10622 v8::Handle<Value> three = v8_num(3);
10623 v8::Handle<Value> value = inner.Close(three);
10624 env->Exit();
10625 return value;
10626}
10627
10628
10629THREADED_TEST(NestedHandleScopeAndContexts) {
10630 v8::HandleScope outer;
10631 v8::Persistent<Context> env = Context::New();
10632 env->Enter();
10633 v8::Handle<Value> value = NestedScope(env);
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010634 v8::Handle<String> str(value->ToString());
Ben Murdochc7cc0282012-03-05 14:35:55 +000010635 CHECK(!str.IsEmpty());
Steve Blocka7e24c12009-10-30 11:49:00 +000010636 env->Exit();
10637 env.Dispose();
10638}
10639
10640
10641THREADED_TEST(ExternalAllocatedMemory) {
10642 v8::HandleScope outer;
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010643 v8::Persistent<Context> env(Context::New());
Ben Murdochc7cc0282012-03-05 14:35:55 +000010644 CHECK(!env.IsEmpty());
Steve Blocka7e24c12009-10-30 11:49:00 +000010645 const int kSize = 1024*1024;
10646 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
10647 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
10648}
10649
10650
10651THREADED_TEST(DisposeEnteredContext) {
10652 v8::HandleScope scope;
10653 LocalContext outer;
10654 { v8::Persistent<v8::Context> inner = v8::Context::New();
10655 inner->Enter();
10656 inner.Dispose();
10657 inner.Clear();
10658 inner->Exit();
10659 }
10660}
10661
10662
10663// Regression test for issue 54, object templates with internal fields
10664// but no accessors or interceptors did not get their internal field
10665// count set on instances.
10666THREADED_TEST(Regress54) {
10667 v8::HandleScope outer;
10668 LocalContext context;
10669 static v8::Persistent<v8::ObjectTemplate> templ;
10670 if (templ.IsEmpty()) {
10671 v8::HandleScope inner;
10672 v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
10673 local->SetInternalFieldCount(1);
10674 templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
10675 }
10676 v8::Handle<v8::Object> result = templ->NewInstance();
10677 CHECK_EQ(1, result->InternalFieldCount());
10678}
10679
10680
10681// If part of the threaded tests, this test makes ThreadingTest fail
10682// on mac.
10683TEST(CatchStackOverflow) {
10684 v8::HandleScope scope;
10685 LocalContext context;
10686 v8::TryCatch try_catch;
10687 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
10688 "function f() {"
10689 " return f();"
10690 "}"
10691 ""
10692 "f();"));
10693 v8::Handle<v8::Value> result = script->Run();
10694 CHECK(result.IsEmpty());
10695}
10696
10697
10698static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
10699 const char* resource_name,
10700 int line_offset) {
10701 v8::HandleScope scope;
10702 v8::TryCatch try_catch;
10703 v8::Handle<v8::Value> result = script->Run();
10704 CHECK(result.IsEmpty());
10705 CHECK(try_catch.HasCaught());
10706 v8::Handle<v8::Message> message = try_catch.Message();
10707 CHECK(!message.IsEmpty());
10708 CHECK_EQ(10 + line_offset, message->GetLineNumber());
10709 CHECK_EQ(91, message->GetStartPosition());
10710 CHECK_EQ(92, message->GetEndPosition());
10711 CHECK_EQ(2, message->GetStartColumn());
10712 CHECK_EQ(3, message->GetEndColumn());
10713 v8::String::AsciiValue line(message->GetSourceLine());
10714 CHECK_EQ(" throw 'nirk';", *line);
10715 v8::String::AsciiValue name(message->GetScriptResourceName());
10716 CHECK_EQ(resource_name, *name);
10717}
10718
10719
10720THREADED_TEST(TryCatchSourceInfo) {
10721 v8::HandleScope scope;
10722 LocalContext context;
10723 v8::Handle<v8::String> source = v8::String::New(
10724 "function Foo() {\n"
10725 " return Bar();\n"
10726 "}\n"
10727 "\n"
10728 "function Bar() {\n"
10729 " return Baz();\n"
10730 "}\n"
10731 "\n"
10732 "function Baz() {\n"
10733 " throw 'nirk';\n"
10734 "}\n"
10735 "\n"
10736 "Foo();\n");
10737
10738 const char* resource_name;
10739 v8::Handle<v8::Script> script;
10740 resource_name = "test.js";
10741 script = v8::Script::Compile(source, v8::String::New(resource_name));
10742 CheckTryCatchSourceInfo(script, resource_name, 0);
10743
10744 resource_name = "test1.js";
10745 v8::ScriptOrigin origin1(v8::String::New(resource_name));
10746 script = v8::Script::Compile(source, &origin1);
10747 CheckTryCatchSourceInfo(script, resource_name, 0);
10748
10749 resource_name = "test2.js";
10750 v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
10751 script = v8::Script::Compile(source, &origin2);
10752 CheckTryCatchSourceInfo(script, resource_name, 7);
10753}
10754
10755
10756THREADED_TEST(CompilationCache) {
10757 v8::HandleScope scope;
10758 LocalContext context;
10759 v8::Handle<v8::String> source0 = v8::String::New("1234");
10760 v8::Handle<v8::String> source1 = v8::String::New("1234");
10761 v8::Handle<v8::Script> script0 =
10762 v8::Script::Compile(source0, v8::String::New("test.js"));
10763 v8::Handle<v8::Script> script1 =
10764 v8::Script::Compile(source1, v8::String::New("test.js"));
10765 v8::Handle<v8::Script> script2 =
10766 v8::Script::Compile(source0); // different origin
10767 CHECK_EQ(1234, script0->Run()->Int32Value());
10768 CHECK_EQ(1234, script1->Run()->Int32Value());
10769 CHECK_EQ(1234, script2->Run()->Int32Value());
10770}
10771
10772
10773static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
10774 ApiTestFuzzer::Fuzz();
10775 return v8_num(42);
10776}
10777
10778
10779THREADED_TEST(CallbackFunctionName) {
10780 v8::HandleScope scope;
10781 LocalContext context;
10782 Local<ObjectTemplate> t = ObjectTemplate::New();
10783 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
10784 context->Global()->Set(v8_str("obj"), t->NewInstance());
10785 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
10786 CHECK(value->IsString());
10787 v8::String::AsciiValue name(value);
10788 CHECK_EQ("asdf", *name);
10789}
10790
10791
10792THREADED_TEST(DateAccess) {
10793 v8::HandleScope scope;
10794 LocalContext context;
10795 v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
10796 CHECK(date->IsDate());
Steve Block6ded16b2010-05-10 14:33:55 +010010797 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue());
Steve Blocka7e24c12009-10-30 11:49:00 +000010798}
10799
10800
10801void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
Steve Block6ded16b2010-05-10 14:33:55 +010010802 v8::Handle<v8::Object> obj = val.As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +000010803 v8::Handle<v8::Array> props = obj->GetPropertyNames();
10804 CHECK_EQ(elmc, props->Length());
10805 for (int i = 0; i < elmc; i++) {
10806 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
10807 CHECK_EQ(elmv[i], *elm);
10808 }
10809}
10810
10811
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010812void CheckOwnProperties(v8::Handle<v8::Value> val,
10813 int elmc,
10814 const char* elmv[]) {
10815 v8::Handle<v8::Object> obj = val.As<v8::Object>();
10816 v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
10817 CHECK_EQ(elmc, props->Length());
10818 for (int i = 0; i < elmc; i++) {
10819 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
10820 CHECK_EQ(elmv[i], *elm);
10821 }
10822}
10823
10824
Steve Blocka7e24c12009-10-30 11:49:00 +000010825THREADED_TEST(PropertyEnumeration) {
10826 v8::HandleScope scope;
10827 LocalContext context;
10828 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
10829 "var result = [];"
10830 "result[0] = {};"
10831 "result[1] = {a: 1, b: 2};"
10832 "result[2] = [1, 2, 3];"
10833 "var proto = {x: 1, y: 2, z: 3};"
10834 "var x = { __proto__: proto, w: 0, z: 1 };"
10835 "result[3] = x;"
10836 "result;"))->Run();
Steve Block6ded16b2010-05-10 14:33:55 +010010837 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +000010838 CHECK_EQ(4, elms->Length());
10839 int elmc0 = 0;
10840 const char** elmv0 = NULL;
10841 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010842 CheckOwnProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
Steve Blocka7e24c12009-10-30 11:49:00 +000010843 int elmc1 = 2;
10844 const char* elmv1[] = {"a", "b"};
10845 CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010846 CheckOwnProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
Steve Blocka7e24c12009-10-30 11:49:00 +000010847 int elmc2 = 3;
10848 const char* elmv2[] = {"0", "1", "2"};
10849 CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010850 CheckOwnProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
Steve Blocka7e24c12009-10-30 11:49:00 +000010851 int elmc3 = 4;
10852 const char* elmv3[] = {"w", "z", "x", "y"};
10853 CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010854 int elmc4 = 2;
10855 const char* elmv4[] = {"w", "z"};
10856 CheckOwnProperties(elms->Get(v8::Integer::New(3)), elmc4, elmv4);
Steve Blocka7e24c12009-10-30 11:49:00 +000010857}
10858
Steve Block44f0eee2011-05-26 01:26:41 +010010859THREADED_TEST(PropertyEnumeration2) {
10860 v8::HandleScope scope;
10861 LocalContext context;
10862 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
10863 "var result = [];"
10864 "result[0] = {};"
10865 "result[1] = {a: 1, b: 2};"
10866 "result[2] = [1, 2, 3];"
10867 "var proto = {x: 1, y: 2, z: 3};"
10868 "var x = { __proto__: proto, w: 0, z: 1 };"
10869 "result[3] = x;"
10870 "result;"))->Run();
10871 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
10872 CHECK_EQ(4, elms->Length());
10873 int elmc0 = 0;
10874 const char** elmv0 = NULL;
10875 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
10876
10877 v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(0));
10878 v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
10879 CHECK_EQ(0, props->Length());
10880 for (uint32_t i = 0; i < props->Length(); i++) {
10881 printf("p[%d]\n", i);
10882 }
10883}
Steve Blocka7e24c12009-10-30 11:49:00 +000010884
Steve Blocka7e24c12009-10-30 11:49:00 +000010885static bool NamedSetAccessBlocker(Local<v8::Object> obj,
10886 Local<Value> name,
10887 v8::AccessType type,
10888 Local<Value> data) {
10889 return type != v8::ACCESS_SET;
10890}
10891
10892
10893static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
10894 uint32_t key,
10895 v8::AccessType type,
10896 Local<Value> data) {
10897 return type != v8::ACCESS_SET;
10898}
10899
10900
10901THREADED_TEST(DisableAccessChecksWhileConfiguring) {
10902 v8::HandleScope scope;
10903 LocalContext context;
10904 Local<ObjectTemplate> templ = ObjectTemplate::New();
10905 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
10906 IndexedSetAccessBlocker);
10907 templ->Set(v8_str("x"), v8::True());
10908 Local<v8::Object> instance = templ->NewInstance();
10909 context->Global()->Set(v8_str("obj"), instance);
10910 Local<Value> value = CompileRun("obj.x");
10911 CHECK(value->BooleanValue());
10912}
10913
10914
10915static bool NamedGetAccessBlocker(Local<v8::Object> obj,
10916 Local<Value> name,
10917 v8::AccessType type,
10918 Local<Value> data) {
10919 return false;
10920}
10921
10922
10923static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
10924 uint32_t key,
10925 v8::AccessType type,
10926 Local<Value> data) {
10927 return false;
10928}
10929
10930
10931
10932THREADED_TEST(AccessChecksReenabledCorrectly) {
10933 v8::HandleScope scope;
10934 LocalContext context;
10935 Local<ObjectTemplate> templ = ObjectTemplate::New();
10936 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
10937 IndexedGetAccessBlocker);
10938 templ->Set(v8_str("a"), v8_str("a"));
10939 // Add more than 8 (see kMaxFastProperties) properties
10940 // so that the constructor will force copying map.
10941 // Cannot sprintf, gcc complains unsafety.
10942 char buf[4];
10943 for (char i = '0'; i <= '9' ; i++) {
10944 buf[0] = i;
10945 for (char j = '0'; j <= '9'; j++) {
10946 buf[1] = j;
10947 for (char k = '0'; k <= '9'; k++) {
10948 buf[2] = k;
10949 buf[3] = 0;
10950 templ->Set(v8_str(buf), v8::Number::New(k));
10951 }
10952 }
10953 }
10954
10955 Local<v8::Object> instance_1 = templ->NewInstance();
10956 context->Global()->Set(v8_str("obj_1"), instance_1);
10957
10958 Local<Value> value_1 = CompileRun("obj_1.a");
10959 CHECK(value_1->IsUndefined());
10960
10961 Local<v8::Object> instance_2 = templ->NewInstance();
10962 context->Global()->Set(v8_str("obj_2"), instance_2);
10963
10964 Local<Value> value_2 = CompileRun("obj_2.a");
10965 CHECK(value_2->IsUndefined());
10966}
10967
10968
10969// This tests that access check information remains on the global
10970// object template when creating contexts.
10971THREADED_TEST(AccessControlRepeatedContextCreation) {
10972 v8::HandleScope handle_scope;
10973 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
10974 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
10975 IndexedSetAccessBlocker);
10976 i::Handle<i::ObjectTemplateInfo> internal_template =
10977 v8::Utils::OpenHandle(*global_template);
10978 CHECK(!internal_template->constructor()->IsUndefined());
10979 i::Handle<i::FunctionTemplateInfo> constructor(
10980 i::FunctionTemplateInfo::cast(internal_template->constructor()));
10981 CHECK(!constructor->access_check_info()->IsUndefined());
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010982 v8::Persistent<Context> context0(Context::New(NULL, global_template));
Ben Murdochc7cc0282012-03-05 14:35:55 +000010983 CHECK(!context0.IsEmpty());
Steve Blocka7e24c12009-10-30 11:49:00 +000010984 CHECK(!constructor->access_check_info()->IsUndefined());
10985}
10986
10987
10988THREADED_TEST(TurnOnAccessCheck) {
10989 v8::HandleScope handle_scope;
10990
10991 // Create an environment with access check to the global object disabled by
10992 // default.
10993 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
10994 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
10995 IndexedGetAccessBlocker,
10996 v8::Handle<v8::Value>(),
10997 false);
10998 v8::Persistent<Context> context = Context::New(NULL, global_template);
10999 Context::Scope context_scope(context);
11000
11001 // Set up a property and a number of functions.
11002 context->Global()->Set(v8_str("a"), v8_num(1));
11003 CompileRun("function f1() {return a;}"
11004 "function f2() {return a;}"
11005 "function g1() {return h();}"
11006 "function g2() {return h();}"
11007 "function h() {return 1;}");
11008 Local<Function> f1 =
11009 Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
11010 Local<Function> f2 =
11011 Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
11012 Local<Function> g1 =
11013 Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
11014 Local<Function> g2 =
11015 Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
11016 Local<Function> h =
11017 Local<Function>::Cast(context->Global()->Get(v8_str("h")));
11018
11019 // Get the global object.
11020 v8::Handle<v8::Object> global = context->Global();
11021
11022 // Call f1 one time and f2 a number of times. This will ensure that f1 still
11023 // uses the runtime system to retreive property a whereas f2 uses global load
11024 // inline cache.
11025 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
11026 for (int i = 0; i < 4; i++) {
11027 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
11028 }
11029
11030 // Same for g1 and g2.
11031 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
11032 for (int i = 0; i < 4; i++) {
11033 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
11034 }
11035
11036 // Detach the global and turn on access check.
11037 context->DetachGlobal();
11038 context->Global()->TurnOnAccessCheck();
11039
11040 // Failing access check to property get results in undefined.
11041 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
11042 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
11043
11044 // Failing access check to function call results in exception.
11045 CHECK(g1->Call(global, 0, NULL).IsEmpty());
11046 CHECK(g2->Call(global, 0, NULL).IsEmpty());
11047
11048 // No failing access check when just returning a constant.
11049 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
11050}
11051
11052
Ben Murdochb0fe1622011-05-05 13:52:32 +010011053v8::Handle<v8::String> a;
11054v8::Handle<v8::String> h;
11055
11056static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
11057 Local<Value> name,
11058 v8::AccessType type,
11059 Local<Value> data) {
11060 return !(name->Equals(a) || name->Equals(h));
11061}
11062
11063
11064THREADED_TEST(TurnOnAccessCheckAndRecompile) {
11065 v8::HandleScope handle_scope;
11066
11067 // Create an environment with access check to the global object disabled by
11068 // default. When the registered access checker will block access to properties
11069 // a and h
11070 a = v8_str("a");
11071 h = v8_str("h");
11072 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
11073 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
11074 IndexedGetAccessBlocker,
11075 v8::Handle<v8::Value>(),
11076 false);
11077 v8::Persistent<Context> context = Context::New(NULL, global_template);
11078 Context::Scope context_scope(context);
11079
11080 // Set up a property and a number of functions.
11081 context->Global()->Set(v8_str("a"), v8_num(1));
11082 static const char* source = "function f1() {return a;}"
11083 "function f2() {return a;}"
11084 "function g1() {return h();}"
11085 "function g2() {return h();}"
11086 "function h() {return 1;}";
11087
11088 CompileRun(source);
11089 Local<Function> f1;
11090 Local<Function> f2;
11091 Local<Function> g1;
11092 Local<Function> g2;
11093 Local<Function> h;
11094 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
11095 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
11096 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
11097 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
11098 h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
11099
11100 // Get the global object.
11101 v8::Handle<v8::Object> global = context->Global();
11102
11103 // Call f1 one time and f2 a number of times. This will ensure that f1 still
11104 // uses the runtime system to retreive property a whereas f2 uses global load
11105 // inline cache.
11106 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
11107 for (int i = 0; i < 4; i++) {
11108 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
11109 }
11110
11111 // Same for g1 and g2.
11112 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
11113 for (int i = 0; i < 4; i++) {
11114 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
11115 }
11116
11117 // Detach the global and turn on access check now blocking access to property
11118 // a and function h.
11119 context->DetachGlobal();
11120 context->Global()->TurnOnAccessCheck();
11121
11122 // Failing access check to property get results in undefined.
11123 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
11124 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
11125
11126 // Failing access check to function call results in exception.
11127 CHECK(g1->Call(global, 0, NULL).IsEmpty());
11128 CHECK(g2->Call(global, 0, NULL).IsEmpty());
11129
11130 // No failing access check when just returning a constant.
11131 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
11132
11133 // Now compile the source again. And get the newly compiled functions, except
11134 // for h for which access is blocked.
11135 CompileRun(source);
11136 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
11137 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
11138 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
11139 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
11140 CHECK(context->Global()->Get(v8_str("h"))->IsUndefined());
11141
11142 // Failing access check to property get results in undefined.
11143 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
11144 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
11145
11146 // Failing access check to function call results in exception.
11147 CHECK(g1->Call(global, 0, NULL).IsEmpty());
11148 CHECK(g2->Call(global, 0, NULL).IsEmpty());
11149}
11150
11151
Steve Blocka7e24c12009-10-30 11:49:00 +000011152// This test verifies that pre-compilation (aka preparsing) can be called
11153// without initializing the whole VM. Thus we cannot run this test in a
11154// multi-threaded setup.
11155TEST(PreCompile) {
11156 // TODO(155): This test would break without the initialization of V8. This is
11157 // a workaround for now to make this test not fail.
11158 v8::V8::Initialize();
Leon Clarkef7060e22010-06-03 12:02:55 +010011159 const char* script = "function foo(a) { return a+1; }";
11160 v8::ScriptData* sd =
Steve Blockd0582a62009-12-15 09:54:21 +000011161 v8::ScriptData::PreCompile(script, i::StrLength(script));
Steve Blocka7e24c12009-10-30 11:49:00 +000011162 CHECK_NE(sd->Length(), 0);
11163 CHECK_NE(sd->Data(), NULL);
Leon Clarkee46be812010-01-19 14:06:41 +000011164 CHECK(!sd->HasError());
11165 delete sd;
11166}
11167
11168
11169TEST(PreCompileWithError) {
11170 v8::V8::Initialize();
Leon Clarkef7060e22010-06-03 12:02:55 +010011171 const char* script = "function foo(a) { return 1 * * 2; }";
11172 v8::ScriptData* sd =
Leon Clarkee46be812010-01-19 14:06:41 +000011173 v8::ScriptData::PreCompile(script, i::StrLength(script));
11174 CHECK(sd->HasError());
11175 delete sd;
11176}
11177
11178
11179TEST(Regress31661) {
11180 v8::V8::Initialize();
Leon Clarkef7060e22010-06-03 12:02:55 +010011181 const char* script = " The Definintive Guide";
11182 v8::ScriptData* sd =
Leon Clarkee46be812010-01-19 14:06:41 +000011183 v8::ScriptData::PreCompile(script, i::StrLength(script));
11184 CHECK(sd->HasError());
Steve Blocka7e24c12009-10-30 11:49:00 +000011185 delete sd;
11186}
11187
11188
Leon Clarkef7060e22010-06-03 12:02:55 +010011189// Tests that ScriptData can be serialized and deserialized.
11190TEST(PreCompileSerialization) {
11191 v8::V8::Initialize();
11192 const char* script = "function foo(a) { return a+1; }";
11193 v8::ScriptData* sd =
11194 v8::ScriptData::PreCompile(script, i::StrLength(script));
11195
11196 // Serialize.
11197 int serialized_data_length = sd->Length();
11198 char* serialized_data = i::NewArray<char>(serialized_data_length);
11199 memcpy(serialized_data, sd->Data(), serialized_data_length);
11200
11201 // Deserialize.
11202 v8::ScriptData* deserialized_sd =
11203 v8::ScriptData::New(serialized_data, serialized_data_length);
11204
11205 // Verify that the original is the same as the deserialized.
11206 CHECK_EQ(sd->Length(), deserialized_sd->Length());
11207 CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
11208 CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
11209
11210 delete sd;
11211 delete deserialized_sd;
11212}
11213
11214
11215// Attempts to deserialize bad data.
11216TEST(PreCompileDeserializationError) {
11217 v8::V8::Initialize();
11218 const char* data = "DONT CARE";
11219 int invalid_size = 3;
11220 v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
11221
11222 CHECK_EQ(0, sd->Length());
11223
11224 delete sd;
11225}
11226
11227
Leon Clarkeac952652010-07-15 11:15:24 +010011228// Attempts to deserialize bad data.
11229TEST(PreCompileInvalidPreparseDataError) {
11230 v8::V8::Initialize();
11231 v8::HandleScope scope;
11232 LocalContext context;
11233
11234 const char* script = "function foo(){ return 5;}\n"
11235 "function bar(){ return 6 + 7;} foo();";
11236 v8::ScriptData* sd =
11237 v8::ScriptData::PreCompile(script, i::StrLength(script));
11238 CHECK(!sd->HasError());
11239 // ScriptDataImpl private implementation details
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -080011240 const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
Iain Merrick9ac36c92010-09-13 15:29:50 +010011241 const int kFunctionEntrySize = i::FunctionEntry::kSize;
Leon Clarkeac952652010-07-15 11:15:24 +010011242 const int kFunctionEntryStartOffset = 0;
11243 const int kFunctionEntryEndOffset = 1;
11244 unsigned* sd_data =
11245 reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
Leon Clarkeac952652010-07-15 11:15:24 +010011246
11247 // Overwrite function bar's end position with 0.
11248 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
11249 v8::TryCatch try_catch;
11250
11251 Local<String> source = String::New(script);
11252 Local<Script> compiled_script = Script::New(source, NULL, sd);
11253 CHECK(try_catch.HasCaught());
11254 String::AsciiValue exception_value(try_catch.Message()->Get());
11255 CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
11256 *exception_value);
11257
11258 try_catch.Reset();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011259
Leon Clarkeac952652010-07-15 11:15:24 +010011260 // Overwrite function bar's start position with 200. The function entry
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011261 // will not be found when searching for it by position and we should fall
11262 // back on eager compilation.
Kristian Monsen80d68ea2010-09-08 11:05:35 +010011263 sd = v8::ScriptData::PreCompile(script, i::StrLength(script));
11264 sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
Leon Clarkeac952652010-07-15 11:15:24 +010011265 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
11266 200;
11267 compiled_script = Script::New(source, NULL, sd);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011268 CHECK(!try_catch.HasCaught());
Leon Clarkeac952652010-07-15 11:15:24 +010011269
11270 delete sd;
11271}
11272
11273
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010011274// Verifies that the Handle<String> and const char* versions of the API produce
11275// the same results (at least for one trivial case).
11276TEST(PreCompileAPIVariationsAreSame) {
11277 v8::V8::Initialize();
11278 v8::HandleScope scope;
11279
11280 const char* cstring = "function foo(a) { return a+1; }";
Ben Murdoch3bec4d22010-07-22 14:51:16 +010011281
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010011282 v8::ScriptData* sd_from_cstring =
11283 v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
11284
11285 TestAsciiResource* resource = new TestAsciiResource(cstring);
Ben Murdoch3bec4d22010-07-22 14:51:16 +010011286 v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile(
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010011287 v8::String::NewExternal(resource));
11288
Ben Murdoch3bec4d22010-07-22 14:51:16 +010011289 v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile(
11290 v8::String::New(cstring));
11291
11292 CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010011293 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
Ben Murdoch3bec4d22010-07-22 14:51:16 +010011294 sd_from_external_string->Data(),
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010011295 sd_from_cstring->Length()));
11296
Ben Murdoch3bec4d22010-07-22 14:51:16 +010011297 CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length());
11298 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
11299 sd_from_string->Data(),
11300 sd_from_cstring->Length()));
11301
11302
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010011303 delete sd_from_cstring;
Ben Murdoch3bec4d22010-07-22 14:51:16 +010011304 delete sd_from_external_string;
11305 delete sd_from_string;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010011306}
11307
11308
Steve Blocka7e24c12009-10-30 11:49:00 +000011309// This tests that we do not allow dictionary load/call inline caches
11310// to use functions that have not yet been compiled. The potential
11311// problem of loading a function that has not yet been compiled can
11312// arise because we share code between contexts via the compilation
11313// cache.
11314THREADED_TEST(DictionaryICLoadedFunction) {
11315 v8::HandleScope scope;
11316 // Test LoadIC.
11317 for (int i = 0; i < 2; i++) {
11318 LocalContext context;
11319 context->Global()->Set(v8_str("tmp"), v8::True());
11320 context->Global()->Delete(v8_str("tmp"));
11321 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
11322 }
11323 // Test CallIC.
11324 for (int i = 0; i < 2; i++) {
11325 LocalContext context;
11326 context->Global()->Set(v8_str("tmp"), v8::True());
11327 context->Global()->Delete(v8_str("tmp"));
11328 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
11329 }
11330}
11331
11332
11333// Test that cross-context new calls use the context of the callee to
11334// create the new JavaScript object.
11335THREADED_TEST(CrossContextNew) {
11336 v8::HandleScope scope;
11337 v8::Persistent<Context> context0 = Context::New();
11338 v8::Persistent<Context> context1 = Context::New();
11339
11340 // Allow cross-domain access.
11341 Local<String> token = v8_str("<security token>");
11342 context0->SetSecurityToken(token);
11343 context1->SetSecurityToken(token);
11344
11345 // Set an 'x' property on the Object prototype and define a
11346 // constructor function in context0.
11347 context0->Enter();
11348 CompileRun("Object.prototype.x = 42; function C() {};");
11349 context0->Exit();
11350
11351 // Call the constructor function from context0 and check that the
11352 // result has the 'x' property.
11353 context1->Enter();
11354 context1->Global()->Set(v8_str("other"), context0->Global());
11355 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
11356 CHECK(value->IsInt32());
11357 CHECK_EQ(42, value->Int32Value());
11358 context1->Exit();
11359
11360 // Dispose the contexts to allow them to be garbage collected.
11361 context0.Dispose();
11362 context1.Dispose();
11363}
11364
11365
11366class RegExpInterruptTest {
11367 public:
11368 RegExpInterruptTest() : block_(NULL) {}
11369 ~RegExpInterruptTest() { delete block_; }
11370 void RunTest() {
11371 block_ = i::OS::CreateSemaphore(0);
11372 gc_count_ = 0;
11373 gc_during_regexp_ = 0;
11374 regexp_success_ = false;
11375 gc_success_ = false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011376 GCThread gc_thread(this);
Steve Blocka7e24c12009-10-30 11:49:00 +000011377 gc_thread.Start();
11378 v8::Locker::StartPreemption(1);
11379
11380 LongRunningRegExp();
11381 {
11382 v8::Unlocker unlock;
11383 gc_thread.Join();
11384 }
11385 v8::Locker::StopPreemption();
11386 CHECK(regexp_success_);
11387 CHECK(gc_success_);
11388 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011389
Steve Blocka7e24c12009-10-30 11:49:00 +000011390 private:
11391 // Number of garbage collections required.
11392 static const int kRequiredGCs = 5;
11393
11394 class GCThread : public i::Thread {
11395 public:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011396 explicit GCThread(RegExpInterruptTest* test)
11397 : Thread("GCThread"), test_(test) {}
Steve Blocka7e24c12009-10-30 11:49:00 +000011398 virtual void Run() {
11399 test_->CollectGarbage();
11400 }
11401 private:
11402 RegExpInterruptTest* test_;
11403 };
11404
11405 void CollectGarbage() {
11406 block_->Wait();
11407 while (gc_during_regexp_ < kRequiredGCs) {
11408 {
11409 v8::Locker lock;
11410 // TODO(lrn): Perhaps create some garbage before collecting.
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011411 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +000011412 gc_count_++;
11413 }
11414 i::OS::Sleep(1);
11415 }
11416 gc_success_ = true;
11417 }
11418
11419 void LongRunningRegExp() {
11420 block_->Signal(); // Enable garbage collection thread on next preemption.
11421 int rounds = 0;
11422 while (gc_during_regexp_ < kRequiredGCs) {
11423 int gc_before = gc_count_;
11424 {
11425 // Match 15-30 "a"'s against 14 and a "b".
11426 const char* c_source =
11427 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
11428 ".exec('aaaaaaaaaaaaaaab') === null";
11429 Local<String> source = String::New(c_source);
11430 Local<Script> script = Script::Compile(source);
11431 Local<Value> result = script->Run();
11432 if (!result->BooleanValue()) {
11433 gc_during_regexp_ = kRequiredGCs; // Allow gc thread to exit.
11434 return;
11435 }
11436 }
11437 {
11438 // Match 15-30 "a"'s against 15 and a "b".
11439 const char* c_source =
11440 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
11441 ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
11442 Local<String> source = String::New(c_source);
11443 Local<Script> script = Script::Compile(source);
11444 Local<Value> result = script->Run();
11445 if (!result->BooleanValue()) {
11446 gc_during_regexp_ = kRequiredGCs;
11447 return;
11448 }
11449 }
11450 int gc_after = gc_count_;
11451 gc_during_regexp_ += gc_after - gc_before;
11452 rounds++;
11453 i::OS::Sleep(1);
11454 }
11455 regexp_success_ = true;
11456 }
11457
11458 i::Semaphore* block_;
11459 int gc_count_;
11460 int gc_during_regexp_;
11461 bool regexp_success_;
11462 bool gc_success_;
11463};
11464
11465
11466// Test that a regular expression execution can be interrupted and
11467// survive a garbage collection.
11468TEST(RegExpInterruption) {
11469 v8::Locker lock;
11470 v8::V8::Initialize();
11471 v8::HandleScope scope;
11472 Local<Context> local_env;
11473 {
11474 LocalContext env;
11475 local_env = env.local();
11476 }
11477
11478 // Local context should still be live.
11479 CHECK(!local_env.IsEmpty());
11480 local_env->Enter();
11481
11482 // Should complete without problems.
11483 RegExpInterruptTest().RunTest();
11484
11485 local_env->Exit();
11486}
11487
11488
11489class ApplyInterruptTest {
11490 public:
11491 ApplyInterruptTest() : block_(NULL) {}
11492 ~ApplyInterruptTest() { delete block_; }
11493 void RunTest() {
11494 block_ = i::OS::CreateSemaphore(0);
11495 gc_count_ = 0;
11496 gc_during_apply_ = 0;
11497 apply_success_ = false;
11498 gc_success_ = false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011499 GCThread gc_thread(this);
Steve Blocka7e24c12009-10-30 11:49:00 +000011500 gc_thread.Start();
11501 v8::Locker::StartPreemption(1);
11502
11503 LongRunningApply();
11504 {
11505 v8::Unlocker unlock;
11506 gc_thread.Join();
11507 }
11508 v8::Locker::StopPreemption();
11509 CHECK(apply_success_);
11510 CHECK(gc_success_);
11511 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011512
Steve Blocka7e24c12009-10-30 11:49:00 +000011513 private:
11514 // Number of garbage collections required.
11515 static const int kRequiredGCs = 2;
11516
11517 class GCThread : public i::Thread {
11518 public:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011519 explicit GCThread(ApplyInterruptTest* test)
11520 : Thread("GCThread"), test_(test) {}
Steve Blocka7e24c12009-10-30 11:49:00 +000011521 virtual void Run() {
11522 test_->CollectGarbage();
11523 }
11524 private:
11525 ApplyInterruptTest* test_;
11526 };
11527
11528 void CollectGarbage() {
11529 block_->Wait();
11530 while (gc_during_apply_ < kRequiredGCs) {
11531 {
11532 v8::Locker lock;
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011533 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +000011534 gc_count_++;
11535 }
11536 i::OS::Sleep(1);
11537 }
11538 gc_success_ = true;
11539 }
11540
11541 void LongRunningApply() {
11542 block_->Signal();
11543 int rounds = 0;
11544 while (gc_during_apply_ < kRequiredGCs) {
11545 int gc_before = gc_count_;
11546 {
11547 const char* c_source =
11548 "function do_very_little(bar) {"
11549 " this.foo = bar;"
11550 "}"
11551 "for (var i = 0; i < 100000; i++) {"
11552 " do_very_little.apply(this, ['bar']);"
11553 "}";
11554 Local<String> source = String::New(c_source);
11555 Local<Script> script = Script::Compile(source);
11556 Local<Value> result = script->Run();
11557 // Check that no exception was thrown.
11558 CHECK(!result.IsEmpty());
11559 }
11560 int gc_after = gc_count_;
11561 gc_during_apply_ += gc_after - gc_before;
11562 rounds++;
11563 }
11564 apply_success_ = true;
11565 }
11566
11567 i::Semaphore* block_;
11568 int gc_count_;
11569 int gc_during_apply_;
11570 bool apply_success_;
11571 bool gc_success_;
11572};
11573
11574
11575// Test that nothing bad happens if we get a preemption just when we were
11576// about to do an apply().
11577TEST(ApplyInterruption) {
11578 v8::Locker lock;
11579 v8::V8::Initialize();
11580 v8::HandleScope scope;
11581 Local<Context> local_env;
11582 {
11583 LocalContext env;
11584 local_env = env.local();
11585 }
11586
11587 // Local context should still be live.
11588 CHECK(!local_env.IsEmpty());
11589 local_env->Enter();
11590
11591 // Should complete without problems.
11592 ApplyInterruptTest().RunTest();
11593
11594 local_env->Exit();
11595}
11596
11597
11598// Verify that we can clone an object
11599TEST(ObjectClone) {
11600 v8::HandleScope scope;
11601 LocalContext env;
11602
11603 const char* sample =
11604 "var rv = {};" \
11605 "rv.alpha = 'hello';" \
11606 "rv.beta = 123;" \
11607 "rv;";
11608
11609 // Create an object, verify basics.
11610 Local<Value> val = CompileRun(sample);
11611 CHECK(val->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +010011612 Local<v8::Object> obj = val.As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +000011613 obj->Set(v8_str("gamma"), v8_str("cloneme"));
11614
11615 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
11616 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
11617 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
11618
11619 // Clone it.
11620 Local<v8::Object> clone = obj->Clone();
11621 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
11622 CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
11623 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
11624
11625 // Set a property on the clone, verify each object.
11626 clone->Set(v8_str("beta"), v8::Integer::New(456));
11627 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
11628 CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
11629}
11630
11631
11632class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
11633 public:
11634 explicit AsciiVectorResource(i::Vector<const char> vector)
11635 : data_(vector) {}
11636 virtual ~AsciiVectorResource() {}
11637 virtual size_t length() const { return data_.length(); }
11638 virtual const char* data() const { return data_.start(); }
11639 private:
11640 i::Vector<const char> data_;
11641};
11642
11643
11644class UC16VectorResource : public v8::String::ExternalStringResource {
11645 public:
11646 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
11647 : data_(vector) {}
11648 virtual ~UC16VectorResource() {}
11649 virtual size_t length() const { return data_.length(); }
11650 virtual const i::uc16* data() const { return data_.start(); }
11651 private:
11652 i::Vector<const i::uc16> data_;
11653};
11654
11655
11656static void MorphAString(i::String* string,
11657 AsciiVectorResource* ascii_resource,
11658 UC16VectorResource* uc16_resource) {
11659 CHECK(i::StringShape(string).IsExternal());
11660 if (string->IsAsciiRepresentation()) {
11661 // Check old map is not symbol or long.
Steve Block44f0eee2011-05-26 01:26:41 +010011662 CHECK(string->map() == HEAP->external_ascii_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +000011663 // Morph external string to be TwoByte string.
Steve Block44f0eee2011-05-26 01:26:41 +010011664 string->set_map(HEAP->external_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +000011665 i::ExternalTwoByteString* morphed =
11666 i::ExternalTwoByteString::cast(string);
11667 morphed->set_resource(uc16_resource);
11668 } else {
11669 // Check old map is not symbol or long.
Steve Block44f0eee2011-05-26 01:26:41 +010011670 CHECK(string->map() == HEAP->external_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +000011671 // Morph external string to be ASCII string.
Steve Block44f0eee2011-05-26 01:26:41 +010011672 string->set_map(HEAP->external_ascii_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +000011673 i::ExternalAsciiString* morphed =
11674 i::ExternalAsciiString::cast(string);
11675 morphed->set_resource(ascii_resource);
11676 }
11677}
11678
11679
11680// Test that we can still flatten a string if the components it is built up
11681// from have been turned into 16 bit strings in the mean time.
11682THREADED_TEST(MorphCompositeStringTest) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011683 char utf_buffer[129];
Steve Blocka7e24c12009-10-30 11:49:00 +000011684 const char* c_string = "Now is the time for all good men"
11685 " to come to the aid of the party";
11686 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
11687 {
11688 v8::HandleScope scope;
11689 LocalContext env;
11690 AsciiVectorResource ascii_resource(
Steve Blockd0582a62009-12-15 09:54:21 +000011691 i::Vector<const char>(c_string, i::StrLength(c_string)));
Steve Blocka7e24c12009-10-30 11:49:00 +000011692 UC16VectorResource uc16_resource(
Steve Blockd0582a62009-12-15 09:54:21 +000011693 i::Vector<const uint16_t>(two_byte_string,
11694 i::StrLength(c_string)));
Steve Blocka7e24c12009-10-30 11:49:00 +000011695
11696 Local<String> lhs(v8::Utils::ToLocal(
Steve Block44f0eee2011-05-26 01:26:41 +010011697 FACTORY->NewExternalStringFromAscii(&ascii_resource)));
Steve Blocka7e24c12009-10-30 11:49:00 +000011698 Local<String> rhs(v8::Utils::ToLocal(
Steve Block44f0eee2011-05-26 01:26:41 +010011699 FACTORY->NewExternalStringFromAscii(&ascii_resource)));
Steve Blocka7e24c12009-10-30 11:49:00 +000011700
11701 env->Global()->Set(v8_str("lhs"), lhs);
11702 env->Global()->Set(v8_str("rhs"), rhs);
11703
11704 CompileRun(
11705 "var cons = lhs + rhs;"
11706 "var slice = lhs.substring(1, lhs.length - 1);"
11707 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
11708
11709 MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
11710 MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
11711
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011712 // This should UTF-8 without flattening, since everything is ASCII.
11713 Handle<String> cons = v8_compile("cons")->Run().As<String>();
11714 CHECK_EQ(128, cons->Utf8Length());
11715 int nchars = -1;
11716 CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
11717 CHECK_EQ(128, nchars);
11718 CHECK_EQ(0, strcmp(
11719 utf_buffer,
11720 "Now is the time for all good men to come to the aid of the party"
11721 "Now is the time for all good men to come to the aid of the party"));
11722
Steve Blocka7e24c12009-10-30 11:49:00 +000011723 // Now do some stuff to make sure the strings are flattened, etc.
11724 CompileRun(
11725 "/[^a-z]/.test(cons);"
11726 "/[^a-z]/.test(slice);"
11727 "/[^a-z]/.test(slice_on_cons);");
11728 const char* expected_cons =
11729 "Now is the time for all good men to come to the aid of the party"
11730 "Now is the time for all good men to come to the aid of the party";
11731 const char* expected_slice =
11732 "ow is the time for all good men to come to the aid of the part";
11733 const char* expected_slice_on_cons =
11734 "ow is the time for all good men to come to the aid of the party"
11735 "Now is the time for all good men to come to the aid of the part";
11736 CHECK_EQ(String::New(expected_cons),
11737 env->Global()->Get(v8_str("cons")));
11738 CHECK_EQ(String::New(expected_slice),
11739 env->Global()->Get(v8_str("slice")));
11740 CHECK_EQ(String::New(expected_slice_on_cons),
11741 env->Global()->Get(v8_str("slice_on_cons")));
11742 }
Ben Murdoch3bec4d22010-07-22 14:51:16 +010011743 i::DeleteArray(two_byte_string);
Steve Blocka7e24c12009-10-30 11:49:00 +000011744}
11745
11746
11747TEST(CompileExternalTwoByteSource) {
11748 v8::HandleScope scope;
11749 LocalContext context;
11750
11751 // This is a very short list of sources, which currently is to check for a
11752 // regression caused by r2703.
11753 const char* ascii_sources[] = {
11754 "0.5",
11755 "-0.5", // This mainly testes PushBack in the Scanner.
11756 "--0.5", // This mainly testes PushBack in the Scanner.
11757 NULL
11758 };
11759
11760 // Compile the sources as external two byte strings.
11761 for (int i = 0; ascii_sources[i] != NULL; i++) {
11762 uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
11763 UC16VectorResource uc16_resource(
Steve Blockd0582a62009-12-15 09:54:21 +000011764 i::Vector<const uint16_t>(two_byte_string,
11765 i::StrLength(ascii_sources[i])));
Steve Blocka7e24c12009-10-30 11:49:00 +000011766 v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
11767 v8::Script::Compile(source);
Ben Murdoch3bec4d22010-07-22 14:51:16 +010011768 i::DeleteArray(two_byte_string);
Steve Blocka7e24c12009-10-30 11:49:00 +000011769 }
11770}
11771
11772
11773class RegExpStringModificationTest {
11774 public:
11775 RegExpStringModificationTest()
11776 : block_(i::OS::CreateSemaphore(0)),
11777 morphs_(0),
11778 morphs_during_regexp_(0),
11779 ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
11780 uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
11781 ~RegExpStringModificationTest() { delete block_; }
11782 void RunTest() {
11783 regexp_success_ = false;
11784 morph_success_ = false;
11785
11786 // Initialize the contents of two_byte_content_ to be a uc16 representation
11787 // of "aaaaaaaaaaaaaab".
11788 for (int i = 0; i < 14; i++) {
11789 two_byte_content_[i] = 'a';
11790 }
11791 two_byte_content_[14] = 'b';
11792
11793 // Create the input string for the regexp - the one we are going to change
11794 // properties of.
Steve Block44f0eee2011-05-26 01:26:41 +010011795 input_ = FACTORY->NewExternalStringFromAscii(&ascii_resource_);
Steve Blocka7e24c12009-10-30 11:49:00 +000011796
11797 // Inject the input as a global variable.
11798 i::Handle<i::String> input_name =
Steve Block44f0eee2011-05-26 01:26:41 +010011799 FACTORY->NewStringFromAscii(i::Vector<const char>("input", 5));
11800 i::Isolate::Current()->global_context()->global()->SetProperty(
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011801 *input_name,
11802 *input_,
11803 NONE,
11804 i::kNonStrictMode)->ToObjectChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +000011805
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011806 MorphThread morph_thread(this);
Steve Blocka7e24c12009-10-30 11:49:00 +000011807 morph_thread.Start();
11808 v8::Locker::StartPreemption(1);
11809 LongRunningRegExp();
11810 {
11811 v8::Unlocker unlock;
11812 morph_thread.Join();
11813 }
11814 v8::Locker::StopPreemption();
11815 CHECK(regexp_success_);
11816 CHECK(morph_success_);
11817 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011818
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011819 private:
Steve Blocka7e24c12009-10-30 11:49:00 +000011820 // Number of string modifications required.
11821 static const int kRequiredModifications = 5;
11822 static const int kMaxModifications = 100;
11823
11824 class MorphThread : public i::Thread {
11825 public:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011826 explicit MorphThread(RegExpStringModificationTest* test)
11827 : Thread("MorphThread"), test_(test) {}
Steve Blocka7e24c12009-10-30 11:49:00 +000011828 virtual void Run() {
11829 test_->MorphString();
11830 }
11831 private:
11832 RegExpStringModificationTest* test_;
11833 };
11834
11835 void MorphString() {
11836 block_->Wait();
11837 while (morphs_during_regexp_ < kRequiredModifications &&
11838 morphs_ < kMaxModifications) {
11839 {
11840 v8::Locker lock;
11841 // Swap string between ascii and two-byte representation.
11842 i::String* string = *input_;
11843 MorphAString(string, &ascii_resource_, &uc16_resource_);
11844 morphs_++;
11845 }
11846 i::OS::Sleep(1);
11847 }
11848 morph_success_ = true;
11849 }
11850
11851 void LongRunningRegExp() {
11852 block_->Signal(); // Enable morphing thread on next preemption.
11853 while (morphs_during_regexp_ < kRequiredModifications &&
11854 morphs_ < kMaxModifications) {
11855 int morphs_before = morphs_;
11856 {
Steve Block791712a2010-08-27 10:21:07 +010011857 v8::HandleScope scope;
Steve Blocka7e24c12009-10-30 11:49:00 +000011858 // Match 15-30 "a"'s against 14 and a "b".
11859 const char* c_source =
11860 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
11861 ".exec(input) === null";
11862 Local<String> source = String::New(c_source);
11863 Local<Script> script = Script::Compile(source);
11864 Local<Value> result = script->Run();
11865 CHECK(result->IsTrue());
11866 }
11867 int morphs_after = morphs_;
11868 morphs_during_regexp_ += morphs_after - morphs_before;
11869 }
11870 regexp_success_ = true;
11871 }
11872
11873 i::uc16 two_byte_content_[15];
11874 i::Semaphore* block_;
11875 int morphs_;
11876 int morphs_during_regexp_;
11877 bool regexp_success_;
11878 bool morph_success_;
11879 i::Handle<i::String> input_;
11880 AsciiVectorResource ascii_resource_;
11881 UC16VectorResource uc16_resource_;
11882};
11883
11884
11885// Test that a regular expression execution can be interrupted and
11886// the string changed without failing.
11887TEST(RegExpStringModification) {
11888 v8::Locker lock;
11889 v8::V8::Initialize();
11890 v8::HandleScope scope;
11891 Local<Context> local_env;
11892 {
11893 LocalContext env;
11894 local_env = env.local();
11895 }
11896
11897 // Local context should still be live.
11898 CHECK(!local_env.IsEmpty());
11899 local_env->Enter();
11900
11901 // Should complete without problems.
11902 RegExpStringModificationTest().RunTest();
11903
11904 local_env->Exit();
11905}
11906
11907
11908// Test that we can set a property on the global object even if there
11909// is a read-only property in the prototype chain.
11910TEST(ReadOnlyPropertyInGlobalProto) {
11911 v8::HandleScope scope;
11912 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11913 LocalContext context(0, templ);
11914 v8::Handle<v8::Object> global = context->Global();
11915 v8::Handle<v8::Object> global_proto =
11916 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
11917 global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
11918 global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
11919 // Check without 'eval' or 'with'.
11920 v8::Handle<v8::Value> res =
11921 CompileRun("function f() { x = 42; return x; }; f()");
11922 // Check with 'eval'.
11923 res = CompileRun("function f() { eval('1'); y = 42; return y; }; f()");
11924 CHECK_EQ(v8::Integer::New(42), res);
11925 // Check with 'with'.
11926 res = CompileRun("function f() { with (this) { y = 42 }; return y; }; f()");
11927 CHECK_EQ(v8::Integer::New(42), res);
11928}
11929
11930static int force_set_set_count = 0;
11931static int force_set_get_count = 0;
11932bool pass_on_get = false;
11933
11934static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
11935 const v8::AccessorInfo& info) {
11936 force_set_get_count++;
11937 if (pass_on_get) {
11938 return v8::Handle<v8::Value>();
11939 } else {
11940 return v8::Int32::New(3);
11941 }
11942}
11943
11944static void ForceSetSetter(v8::Local<v8::String> name,
11945 v8::Local<v8::Value> value,
11946 const v8::AccessorInfo& info) {
11947 force_set_set_count++;
11948}
11949
11950static v8::Handle<v8::Value> ForceSetInterceptSetter(
11951 v8::Local<v8::String> name,
11952 v8::Local<v8::Value> value,
11953 const v8::AccessorInfo& info) {
11954 force_set_set_count++;
11955 return v8::Undefined();
11956}
11957
11958TEST(ForceSet) {
11959 force_set_get_count = 0;
11960 force_set_set_count = 0;
11961 pass_on_get = false;
11962
11963 v8::HandleScope scope;
11964 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11965 v8::Handle<v8::String> access_property = v8::String::New("a");
11966 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
11967 LocalContext context(NULL, templ);
11968 v8::Handle<v8::Object> global = context->Global();
11969
11970 // Ordinary properties
11971 v8::Handle<v8::String> simple_property = v8::String::New("p");
11972 global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
11973 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11974 // This should fail because the property is read-only
11975 global->Set(simple_property, v8::Int32::New(5));
11976 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11977 // This should succeed even though the property is read-only
11978 global->ForceSet(simple_property, v8::Int32::New(6));
11979 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
11980
11981 // Accessors
11982 CHECK_EQ(0, force_set_set_count);
11983 CHECK_EQ(0, force_set_get_count);
11984 CHECK_EQ(3, global->Get(access_property)->Int32Value());
11985 // CHECK_EQ the property shouldn't override it, just call the setter
11986 // which in this case does nothing.
11987 global->Set(access_property, v8::Int32::New(7));
11988 CHECK_EQ(3, global->Get(access_property)->Int32Value());
11989 CHECK_EQ(1, force_set_set_count);
11990 CHECK_EQ(2, force_set_get_count);
11991 // Forcing the property to be set should override the accessor without
11992 // calling it
11993 global->ForceSet(access_property, v8::Int32::New(8));
11994 CHECK_EQ(8, global->Get(access_property)->Int32Value());
11995 CHECK_EQ(1, force_set_set_count);
11996 CHECK_EQ(2, force_set_get_count);
11997}
11998
11999TEST(ForceSetWithInterceptor) {
12000 force_set_get_count = 0;
12001 force_set_set_count = 0;
12002 pass_on_get = false;
12003
12004 v8::HandleScope scope;
12005 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12006 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
12007 LocalContext context(NULL, templ);
12008 v8::Handle<v8::Object> global = context->Global();
12009
12010 v8::Handle<v8::String> some_property = v8::String::New("a");
12011 CHECK_EQ(0, force_set_set_count);
12012 CHECK_EQ(0, force_set_get_count);
12013 CHECK_EQ(3, global->Get(some_property)->Int32Value());
12014 // Setting the property shouldn't override it, just call the setter
12015 // which in this case does nothing.
12016 global->Set(some_property, v8::Int32::New(7));
12017 CHECK_EQ(3, global->Get(some_property)->Int32Value());
12018 CHECK_EQ(1, force_set_set_count);
12019 CHECK_EQ(2, force_set_get_count);
12020 // Getting the property when the interceptor returns an empty handle
12021 // should yield undefined, since the property isn't present on the
12022 // object itself yet.
12023 pass_on_get = true;
12024 CHECK(global->Get(some_property)->IsUndefined());
12025 CHECK_EQ(1, force_set_set_count);
12026 CHECK_EQ(3, force_set_get_count);
12027 // Forcing the property to be set should cause the value to be
12028 // set locally without calling the interceptor.
12029 global->ForceSet(some_property, v8::Int32::New(8));
12030 CHECK_EQ(8, global->Get(some_property)->Int32Value());
12031 CHECK_EQ(1, force_set_set_count);
12032 CHECK_EQ(4, force_set_get_count);
12033 // Reenabling the interceptor should cause it to take precedence over
12034 // the property
12035 pass_on_get = false;
12036 CHECK_EQ(3, global->Get(some_property)->Int32Value());
12037 CHECK_EQ(1, force_set_set_count);
12038 CHECK_EQ(5, force_set_get_count);
12039 // The interceptor should also work for other properties
12040 CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
12041 CHECK_EQ(1, force_set_set_count);
12042 CHECK_EQ(6, force_set_get_count);
12043}
12044
12045
12046THREADED_TEST(ForceDelete) {
12047 v8::HandleScope scope;
12048 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12049 LocalContext context(NULL, templ);
12050 v8::Handle<v8::Object> global = context->Global();
12051
12052 // Ordinary properties
12053 v8::Handle<v8::String> simple_property = v8::String::New("p");
12054 global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
12055 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
12056 // This should fail because the property is dont-delete.
12057 CHECK(!global->Delete(simple_property));
12058 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
12059 // This should succeed even though the property is dont-delete.
12060 CHECK(global->ForceDelete(simple_property));
12061 CHECK(global->Get(simple_property)->IsUndefined());
12062}
12063
12064
12065static int force_delete_interceptor_count = 0;
12066static bool pass_on_delete = false;
12067
12068
12069static v8::Handle<v8::Boolean> ForceDeleteDeleter(
12070 v8::Local<v8::String> name,
12071 const v8::AccessorInfo& info) {
12072 force_delete_interceptor_count++;
12073 if (pass_on_delete) {
12074 return v8::Handle<v8::Boolean>();
12075 } else {
12076 return v8::True();
12077 }
12078}
12079
12080
12081THREADED_TEST(ForceDeleteWithInterceptor) {
12082 force_delete_interceptor_count = 0;
12083 pass_on_delete = false;
12084
12085 v8::HandleScope scope;
12086 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12087 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
12088 LocalContext context(NULL, templ);
12089 v8::Handle<v8::Object> global = context->Global();
12090
12091 v8::Handle<v8::String> some_property = v8::String::New("a");
12092 global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
12093
12094 // Deleting a property should get intercepted and nothing should
12095 // happen.
12096 CHECK_EQ(0, force_delete_interceptor_count);
12097 CHECK(global->Delete(some_property));
12098 CHECK_EQ(1, force_delete_interceptor_count);
12099 CHECK_EQ(42, global->Get(some_property)->Int32Value());
12100 // Deleting the property when the interceptor returns an empty
12101 // handle should not delete the property since it is DontDelete.
12102 pass_on_delete = true;
12103 CHECK(!global->Delete(some_property));
12104 CHECK_EQ(2, force_delete_interceptor_count);
12105 CHECK_EQ(42, global->Get(some_property)->Int32Value());
12106 // Forcing the property to be deleted should delete the value
12107 // without calling the interceptor.
12108 CHECK(global->ForceDelete(some_property));
12109 CHECK(global->Get(some_property)->IsUndefined());
12110 CHECK_EQ(2, force_delete_interceptor_count);
12111}
12112
12113
12114// Make sure that forcing a delete invalidates any IC stubs, so we
12115// don't read the hole value.
12116THREADED_TEST(ForceDeleteIC) {
12117 v8::HandleScope scope;
12118 LocalContext context;
12119 // Create a DontDelete variable on the global object.
12120 CompileRun("this.__proto__ = { foo: 'horse' };"
12121 "var foo = 'fish';"
12122 "function f() { return foo.length; }");
12123 // Initialize the IC for foo in f.
12124 CompileRun("for (var i = 0; i < 4; i++) f();");
12125 // Make sure the value of foo is correct before the deletion.
12126 CHECK_EQ(4, CompileRun("f()")->Int32Value());
12127 // Force the deletion of foo.
12128 CHECK(context->Global()->ForceDelete(v8_str("foo")));
12129 // Make sure the value for foo is read from the prototype, and that
12130 // we don't get in trouble with reading the deleted cell value
12131 // sentinel.
12132 CHECK_EQ(5, CompileRun("f()")->Int32Value());
12133}
12134
12135
12136v8::Persistent<Context> calling_context0;
12137v8::Persistent<Context> calling_context1;
12138v8::Persistent<Context> calling_context2;
12139
12140
12141// Check that the call to the callback is initiated in
12142// calling_context2, the directly calling context is calling_context1
12143// and the callback itself is in calling_context0.
12144static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
12145 ApiTestFuzzer::Fuzz();
12146 CHECK(Context::GetCurrent() == calling_context0);
12147 CHECK(Context::GetCalling() == calling_context1);
12148 CHECK(Context::GetEntered() == calling_context2);
12149 return v8::Integer::New(42);
12150}
12151
12152
12153THREADED_TEST(GetCallingContext) {
12154 v8::HandleScope scope;
12155
12156 calling_context0 = Context::New();
12157 calling_context1 = Context::New();
12158 calling_context2 = Context::New();
12159
12160 // Allow cross-domain access.
12161 Local<String> token = v8_str("<security token>");
12162 calling_context0->SetSecurityToken(token);
12163 calling_context1->SetSecurityToken(token);
12164 calling_context2->SetSecurityToken(token);
12165
12166 // Create an object with a C++ callback in context0.
12167 calling_context0->Enter();
12168 Local<v8::FunctionTemplate> callback_templ =
12169 v8::FunctionTemplate::New(GetCallingContextCallback);
12170 calling_context0->Global()->Set(v8_str("callback"),
12171 callback_templ->GetFunction());
12172 calling_context0->Exit();
12173
Ben Murdochc7cc0282012-03-05 14:35:55 +000012174 // Expose context0 in context1 and set up a function that calls the
Steve Blocka7e24c12009-10-30 11:49:00 +000012175 // callback function.
12176 calling_context1->Enter();
12177 calling_context1->Global()->Set(v8_str("context0"),
12178 calling_context0->Global());
12179 CompileRun("function f() { context0.callback() }");
12180 calling_context1->Exit();
12181
12182 // Expose context1 in context2 and call the callback function in
12183 // context0 indirectly through f in context1.
12184 calling_context2->Enter();
12185 calling_context2->Global()->Set(v8_str("context1"),
12186 calling_context1->Global());
12187 CompileRun("context1.f()");
12188 calling_context2->Exit();
12189
12190 // Dispose the contexts to allow them to be garbage collected.
12191 calling_context0.Dispose();
12192 calling_context1.Dispose();
12193 calling_context2.Dispose();
12194 calling_context0.Clear();
12195 calling_context1.Clear();
12196 calling_context2.Clear();
12197}
12198
12199
12200// Check that a variable declaration with no explicit initialization
12201// value does not shadow an existing property in the prototype chain.
12202//
12203// This is consistent with Firefox and Safari.
12204//
12205// See http://crbug.com/12548.
12206THREADED_TEST(InitGlobalVarInProtoChain) {
12207 v8::HandleScope scope;
12208 LocalContext context;
12209 // Introduce a variable in the prototype chain.
12210 CompileRun("__proto__.x = 42");
12211 v8::Handle<v8::Value> result = CompileRun("var x; x");
12212 CHECK(!result->IsUndefined());
12213 CHECK_EQ(42, result->Int32Value());
12214}
12215
12216
12217// Regression test for issue 398.
12218// If a function is added to an object, creating a constant function
12219// field, and the result is cloned, replacing the constant function on the
12220// original should not affect the clone.
12221// See http://code.google.com/p/v8/issues/detail?id=398
12222THREADED_TEST(ReplaceConstantFunction) {
12223 v8::HandleScope scope;
12224 LocalContext context;
12225 v8::Handle<v8::Object> obj = v8::Object::New();
12226 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
12227 v8::Handle<v8::String> foo_string = v8::String::New("foo");
12228 obj->Set(foo_string, func_templ->GetFunction());
12229 v8::Handle<v8::Object> obj_clone = obj->Clone();
12230 obj_clone->Set(foo_string, v8::String::New("Hello"));
12231 CHECK(!obj->Get(foo_string)->IsUndefined());
12232}
12233
12234
12235// Regression test for http://crbug.com/16276.
12236THREADED_TEST(Regress16276) {
12237 v8::HandleScope scope;
12238 LocalContext context;
12239 // Force the IC in f to be a dictionary load IC.
12240 CompileRun("function f(obj) { return obj.x; }\n"
12241 "var obj = { x: { foo: 42 }, y: 87 };\n"
12242 "var x = obj.x;\n"
12243 "delete obj.y;\n"
12244 "for (var i = 0; i < 5; i++) f(obj);");
12245 // Detach the global object to make 'this' refer directly to the
12246 // global object (not the proxy), and make sure that the dictionary
12247 // load IC doesn't mess up loading directly from the global object.
12248 context->DetachGlobal();
12249 CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
12250}
12251
12252
12253THREADED_TEST(PixelArray) {
12254 v8::HandleScope scope;
12255 LocalContext context;
Steve Blockd0582a62009-12-15 09:54:21 +000012256 const int kElementCount = 260;
Steve Blocka7e24c12009-10-30 11:49:00 +000012257 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
Steve Block44f0eee2011-05-26 01:26:41 +010012258 i::Handle<i::ExternalPixelArray> pixels =
12259 i::Handle<i::ExternalPixelArray>::cast(
12260 FACTORY->NewExternalArray(kElementCount,
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012261 v8::kExternalPixelArray,
12262 pixel_data));
12263 // Force GC to trigger verification.
12264 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +000012265 for (int i = 0; i < kElementCount; i++) {
Steve Blockd0582a62009-12-15 09:54:21 +000012266 pixels->set(i, i % 256);
Steve Blocka7e24c12009-10-30 11:49:00 +000012267 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012268 // Force GC to trigger verification.
12269 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +000012270 for (int i = 0; i < kElementCount; i++) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012271 CHECK_EQ(i % 256, pixels->get_scalar(i));
Steve Blockd0582a62009-12-15 09:54:21 +000012272 CHECK_EQ(i % 256, pixel_data[i]);
Steve Blocka7e24c12009-10-30 11:49:00 +000012273 }
12274
12275 v8::Handle<v8::Object> obj = v8::Object::New();
12276 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
12277 // Set the elements to be the pixels.
12278 // jsobj->set_elements(*pixels);
12279 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
John Reck59135872010-11-02 12:39:01 -070012280 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000012281 obj->Set(v8_str("field"), v8::Int32::New(1503));
12282 context->Global()->Set(v8_str("pixels"), obj);
12283 v8::Handle<v8::Value> result = CompileRun("pixels.field");
12284 CHECK_EQ(1503, result->Int32Value());
12285 result = CompileRun("pixels[1]");
12286 CHECK_EQ(1, result->Int32Value());
12287
12288 result = CompileRun("var sum = 0;"
12289 "for (var i = 0; i < 8; i++) {"
12290 " sum += pixels[i] = pixels[i] = -i;"
12291 "}"
12292 "sum;");
12293 CHECK_EQ(-28, result->Int32Value());
12294
12295 result = CompileRun("var sum = 0;"
12296 "for (var i = 0; i < 8; i++) {"
12297 " sum += pixels[i] = pixels[i] = 0;"
12298 "}"
12299 "sum;");
12300 CHECK_EQ(0, result->Int32Value());
12301
12302 result = CompileRun("var sum = 0;"
12303 "for (var i = 0; i < 8; i++) {"
12304 " sum += pixels[i] = pixels[i] = 255;"
12305 "}"
12306 "sum;");
12307 CHECK_EQ(8 * 255, result->Int32Value());
12308
12309 result = CompileRun("var sum = 0;"
12310 "for (var i = 0; i < 8; i++) {"
12311 " sum += pixels[i] = pixels[i] = 256 + i;"
12312 "}"
12313 "sum;");
12314 CHECK_EQ(2076, result->Int32Value());
12315
12316 result = CompileRun("var sum = 0;"
12317 "for (var i = 0; i < 8; i++) {"
12318 " sum += pixels[i] = pixels[i] = i;"
12319 "}"
12320 "sum;");
12321 CHECK_EQ(28, result->Int32Value());
12322
12323 result = CompileRun("var sum = 0;"
12324 "for (var i = 0; i < 8; i++) {"
12325 " sum += pixels[i];"
12326 "}"
12327 "sum;");
12328 CHECK_EQ(28, result->Int32Value());
12329
12330 i::Handle<i::Smi> value(i::Smi::FromInt(2));
Ben Murdoch589d6972011-11-30 16:04:58 +000012331 i::Handle<i::Object> no_failure;
Ben Murdochc7cc0282012-03-05 14:35:55 +000012332 no_failure = i::JSObject::SetElement(jsobj, 1, value, i::kNonStrictMode);
Ben Murdoch589d6972011-11-30 16:04:58 +000012333 ASSERT(!no_failure.is_null());
12334 i::USE(no_failure);
John Reck59135872010-11-02 12:39:01 -070012335 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000012336 *value.location() = i::Smi::FromInt(256);
Ben Murdochc7cc0282012-03-05 14:35:55 +000012337 no_failure = i::JSObject::SetElement(jsobj, 1, value, i::kNonStrictMode);
Ben Murdoch589d6972011-11-30 16:04:58 +000012338 ASSERT(!no_failure.is_null());
12339 i::USE(no_failure);
John Reck59135872010-11-02 12:39:01 -070012340 CHECK_EQ(255,
12341 i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000012342 *value.location() = i::Smi::FromInt(-1);
Ben Murdochc7cc0282012-03-05 14:35:55 +000012343 no_failure = i::JSObject::SetElement(jsobj, 1, value, i::kNonStrictMode);
Ben Murdoch589d6972011-11-30 16:04:58 +000012344 ASSERT(!no_failure.is_null());
12345 i::USE(no_failure);
John Reck59135872010-11-02 12:39:01 -070012346 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000012347
12348 result = CompileRun("for (var i = 0; i < 8; i++) {"
12349 " pixels[i] = (i * 65) - 109;"
12350 "}"
12351 "pixels[1] + pixels[6];");
12352 CHECK_EQ(255, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070012353 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
12354 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
12355 CHECK_EQ(21,
12356 i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
12357 CHECK_EQ(86,
12358 i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
12359 CHECK_EQ(151,
12360 i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
12361 CHECK_EQ(216,
12362 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
12363 CHECK_EQ(255,
12364 i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
12365 CHECK_EQ(255,
12366 i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000012367 result = CompileRun("var sum = 0;"
12368 "for (var i = 0; i < 8; i++) {"
12369 " sum += pixels[i];"
12370 "}"
12371 "sum;");
12372 CHECK_EQ(984, result->Int32Value());
12373
12374 result = CompileRun("for (var i = 0; i < 8; i++) {"
12375 " pixels[i] = (i * 1.1);"
12376 "}"
12377 "pixels[1] + pixels[6];");
12378 CHECK_EQ(8, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070012379 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
12380 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
12381 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
12382 CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
12383 CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
12384 CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
12385 CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
12386 CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000012387
12388 result = CompileRun("for (var i = 0; i < 8; i++) {"
12389 " pixels[7] = undefined;"
12390 "}"
12391 "pixels[7];");
12392 CHECK_EQ(0, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070012393 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000012394
12395 result = CompileRun("for (var i = 0; i < 8; i++) {"
12396 " pixels[6] = '2.3';"
12397 "}"
12398 "pixels[6];");
12399 CHECK_EQ(2, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070012400 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000012401
12402 result = CompileRun("for (var i = 0; i < 8; i++) {"
12403 " pixels[5] = NaN;"
12404 "}"
12405 "pixels[5];");
12406 CHECK_EQ(0, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070012407 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000012408
12409 result = CompileRun("for (var i = 0; i < 8; i++) {"
12410 " pixels[8] = Infinity;"
12411 "}"
12412 "pixels[8];");
12413 CHECK_EQ(255, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070012414 CHECK_EQ(255,
12415 i::Smi::cast(jsobj->GetElement(8)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000012416
12417 result = CompileRun("for (var i = 0; i < 8; i++) {"
12418 " pixels[9] = -Infinity;"
12419 "}"
12420 "pixels[9];");
12421 CHECK_EQ(0, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070012422 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000012423
12424 result = CompileRun("pixels[3] = 33;"
12425 "delete pixels[3];"
12426 "pixels[3];");
12427 CHECK_EQ(33, result->Int32Value());
12428
12429 result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
12430 "pixels[2] = 12; pixels[3] = 13;"
12431 "pixels.__defineGetter__('2',"
12432 "function() { return 120; });"
12433 "pixels[2];");
12434 CHECK_EQ(12, result->Int32Value());
12435
12436 result = CompileRun("var js_array = new Array(40);"
12437 "js_array[0] = 77;"
12438 "js_array;");
12439 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
12440
12441 result = CompileRun("pixels[1] = 23;"
12442 "pixels.__proto__ = [];"
12443 "js_array.__proto__ = pixels;"
12444 "js_array.concat(pixels);");
12445 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
12446 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
12447
12448 result = CompileRun("pixels[1] = 23;");
12449 CHECK_EQ(23, result->Int32Value());
12450
Steve Blockd0582a62009-12-15 09:54:21 +000012451 // Test for index greater than 255. Regression test for:
12452 // http://code.google.com/p/chromium/issues/detail?id=26337.
12453 result = CompileRun("pixels[256] = 255;");
12454 CHECK_EQ(255, result->Int32Value());
12455 result = CompileRun("var i = 0;"
12456 "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
12457 "i");
12458 CHECK_EQ(255, result->Int32Value());
12459
Steve Block1e0659c2011-05-24 12:43:12 +010012460 // Make sure that pixel array ICs recognize when a non-pixel array
12461 // is passed to it.
12462 result = CompileRun("function pa_load(p) {"
12463 " var sum = 0;"
12464 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
12465 " return sum;"
12466 "}"
12467 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12468 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
12469 "just_ints = new Object();"
12470 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12471 "for (var i = 0; i < 10; ++i) {"
12472 " result = pa_load(just_ints);"
12473 "}"
12474 "result");
12475 CHECK_EQ(32640, result->Int32Value());
12476
12477 // Make sure that pixel array ICs recognize out-of-bound accesses.
12478 result = CompileRun("function pa_load(p, start) {"
12479 " var sum = 0;"
12480 " for (var j = start; j < 256; j++) { sum += p[j]; }"
12481 " return sum;"
12482 "}"
12483 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12484 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
12485 "for (var i = 0; i < 10; ++i) {"
12486 " result = pa_load(pixels,-10);"
12487 "}"
12488 "result");
12489 CHECK_EQ(0, result->Int32Value());
12490
12491 // Make sure that generic ICs properly handles a pixel array.
12492 result = CompileRun("function pa_load(p) {"
12493 " var sum = 0;"
12494 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
12495 " return sum;"
12496 "}"
12497 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12498 "just_ints = new Object();"
12499 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12500 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
12501 "for (var i = 0; i < 10; ++i) {"
12502 " result = pa_load(pixels);"
12503 "}"
12504 "result");
12505 CHECK_EQ(32640, result->Int32Value());
12506
12507 // Make sure that generic load ICs recognize out-of-bound accesses in
12508 // pixel arrays.
12509 result = CompileRun("function pa_load(p, start) {"
12510 " var sum = 0;"
12511 " for (var j = start; j < 256; j++) { sum += p[j]; }"
12512 " return sum;"
12513 "}"
12514 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12515 "just_ints = new Object();"
12516 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12517 "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
12518 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
12519 "for (var i = 0; i < 10; ++i) {"
12520 " result = pa_load(pixels,-10);"
12521 "}"
12522 "result");
12523 CHECK_EQ(0, result->Int32Value());
12524
12525 // Make sure that generic ICs properly handles other types than pixel
12526 // arrays (that the inlined fast pixel array test leaves the right information
12527 // in the right registers).
12528 result = CompileRun("function pa_load(p) {"
12529 " var sum = 0;"
12530 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
12531 " return sum;"
12532 "}"
12533 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12534 "just_ints = new Object();"
12535 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12536 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
12537 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
12538 "sparse_array = new Object();"
12539 "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
12540 "sparse_array[1000000] = 3;"
12541 "for (var i = 0; i < 10; ++i) {"
12542 " result = pa_load(sparse_array);"
12543 "}"
12544 "result");
12545 CHECK_EQ(32640, result->Int32Value());
12546
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012547 // Make sure that pixel array store ICs clamp values correctly.
12548 result = CompileRun("function pa_store(p) {"
12549 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
12550 "}"
12551 "pa_store(pixels);"
12552 "var sum = 0;"
12553 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
12554 "sum");
12555 CHECK_EQ(48896, result->Int32Value());
12556
12557 // Make sure that pixel array stores correctly handle accesses outside
12558 // of the pixel array..
12559 result = CompileRun("function pa_store(p,start) {"
12560 " for (var j = 0; j < 256; j++) {"
12561 " p[j+start] = j * 2;"
12562 " }"
12563 "}"
12564 "pa_store(pixels,0);"
12565 "pa_store(pixels,-128);"
12566 "var sum = 0;"
12567 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
12568 "sum");
12569 CHECK_EQ(65280, result->Int32Value());
12570
12571 // Make sure that the generic store stub correctly handle accesses outside
12572 // of the pixel array..
12573 result = CompileRun("function pa_store(p,start) {"
12574 " for (var j = 0; j < 256; j++) {"
12575 " p[j+start] = j * 2;"
12576 " }"
12577 "}"
12578 "pa_store(pixels,0);"
12579 "just_ints = new Object();"
12580 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12581 "pa_store(just_ints, 0);"
12582 "pa_store(pixels,-128);"
12583 "var sum = 0;"
12584 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
12585 "sum");
12586 CHECK_EQ(65280, result->Int32Value());
12587
12588 // Make sure that the generic keyed store stub clamps pixel array values
12589 // correctly.
12590 result = CompileRun("function pa_store(p) {"
12591 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
12592 "}"
12593 "pa_store(pixels);"
12594 "just_ints = new Object();"
12595 "pa_store(just_ints);"
12596 "pa_store(pixels);"
12597 "var sum = 0;"
12598 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
12599 "sum");
12600 CHECK_EQ(48896, result->Int32Value());
12601
12602 // Make sure that pixel array loads are optimized by crankshaft.
Steve Block1e0659c2011-05-24 12:43:12 +010012603 result = CompileRun("function pa_load(p) {"
12604 " var sum = 0;"
12605 " for (var i=0; i<256; ++i) {"
12606 " sum += p[i];"
12607 " }"
12608 " return sum; "
12609 "}"
12610 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
Steve Block44f0eee2011-05-26 01:26:41 +010012611 "for (var i = 0; i < 5000; ++i) {"
Steve Block1e0659c2011-05-24 12:43:12 +010012612 " result = pa_load(pixels);"
12613 "}"
12614 "result");
12615 CHECK_EQ(32640, result->Int32Value());
12616
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012617 // Make sure that pixel array stores are optimized by crankshaft.
12618 result = CompileRun("function pa_init(p) {"
12619 "for (var i = 0; i < 256; ++i) { p[i] = i; }"
12620 "}"
12621 "function pa_load(p) {"
12622 " var sum = 0;"
12623 " for (var i=0; i<256; ++i) {"
12624 " sum += p[i];"
12625 " }"
12626 " return sum; "
12627 "}"
Steve Block44f0eee2011-05-26 01:26:41 +010012628 "for (var i = 0; i < 5000; ++i) {"
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012629 " pa_init(pixels);"
12630 "}"
12631 "result = pa_load(pixels);"
12632 "result");
12633 CHECK_EQ(32640, result->Int32Value());
12634
Steve Blocka7e24c12009-10-30 11:49:00 +000012635 free(pixel_data);
12636}
12637
12638
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010012639THREADED_TEST(PixelArrayInfo) {
12640 v8::HandleScope scope;
12641 LocalContext context;
12642 for (int size = 0; size < 100; size += 10) {
12643 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
12644 v8::Handle<v8::Object> obj = v8::Object::New();
12645 obj->SetIndexedPropertiesToPixelData(pixel_data, size);
12646 CHECK(obj->HasIndexedPropertiesInPixelData());
12647 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
12648 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
12649 free(pixel_data);
12650 }
12651}
12652
12653
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012654static v8::Handle<Value> NotHandledIndexedPropertyGetter(
12655 uint32_t index,
12656 const AccessorInfo& info) {
12657 ApiTestFuzzer::Fuzz();
12658 return v8::Handle<Value>();
12659}
12660
12661
12662static v8::Handle<Value> NotHandledIndexedPropertySetter(
12663 uint32_t index,
12664 Local<Value> value,
12665 const AccessorInfo& info) {
12666 ApiTestFuzzer::Fuzz();
12667 return v8::Handle<Value>();
12668}
12669
12670
12671THREADED_TEST(PixelArrayWithInterceptor) {
12672 v8::HandleScope scope;
12673 LocalContext context;
12674 const int kElementCount = 260;
12675 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
Steve Block44f0eee2011-05-26 01:26:41 +010012676 i::Handle<i::ExternalPixelArray> pixels =
12677 i::Handle<i::ExternalPixelArray>::cast(
12678 FACTORY->NewExternalArray(kElementCount,
12679 v8::kExternalPixelArray,
12680 pixel_data));
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012681 for (int i = 0; i < kElementCount; i++) {
12682 pixels->set(i, i % 256);
12683 }
12684 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12685 templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
12686 NotHandledIndexedPropertySetter);
12687 v8::Handle<v8::Object> obj = templ->NewInstance();
12688 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
12689 context->Global()->Set(v8_str("pixels"), obj);
12690 v8::Handle<v8::Value> result = CompileRun("pixels[1]");
12691 CHECK_EQ(1, result->Int32Value());
12692 result = CompileRun("var sum = 0;"
12693 "for (var i = 0; i < 8; i++) {"
12694 " sum += pixels[i] = pixels[i] = -i;"
12695 "}"
12696 "sum;");
12697 CHECK_EQ(-28, result->Int32Value());
12698 result = CompileRun("pixels.hasOwnProperty('1')");
12699 CHECK(result->BooleanValue());
12700 free(pixel_data);
12701}
12702
12703
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010012704static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
12705 switch (array_type) {
12706 case v8::kExternalByteArray:
12707 case v8::kExternalUnsignedByteArray:
Steve Block44f0eee2011-05-26 01:26:41 +010012708 case v8::kExternalPixelArray:
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010012709 return 1;
12710 break;
12711 case v8::kExternalShortArray:
12712 case v8::kExternalUnsignedShortArray:
12713 return 2;
12714 break;
12715 case v8::kExternalIntArray:
12716 case v8::kExternalUnsignedIntArray:
12717 case v8::kExternalFloatArray:
12718 return 4;
12719 break;
Ben Murdoch257744e2011-11-30 15:57:28 +000012720 case v8::kExternalDoubleArray:
12721 return 8;
12722 break;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010012723 default:
12724 UNREACHABLE();
12725 return -1;
12726 }
12727 UNREACHABLE();
12728 return -1;
12729}
12730
12731
Steve Block3ce2e202009-11-05 08:53:23 +000012732template <class ExternalArrayClass, class ElementType>
12733static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
12734 int64_t low,
12735 int64_t high) {
12736 v8::HandleScope scope;
12737 LocalContext context;
12738 const int kElementCount = 40;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010012739 int element_size = ExternalArrayElementSize(array_type);
Steve Block3ce2e202009-11-05 08:53:23 +000012740 ElementType* array_data =
12741 static_cast<ElementType*>(malloc(kElementCount * element_size));
12742 i::Handle<ExternalArrayClass> array =
12743 i::Handle<ExternalArrayClass>::cast(
Steve Block44f0eee2011-05-26 01:26:41 +010012744 FACTORY->NewExternalArray(kElementCount, array_type, array_data));
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012745 // Force GC to trigger verification.
12746 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Block3ce2e202009-11-05 08:53:23 +000012747 for (int i = 0; i < kElementCount; i++) {
12748 array->set(i, static_cast<ElementType>(i));
12749 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012750 // Force GC to trigger verification.
12751 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Block3ce2e202009-11-05 08:53:23 +000012752 for (int i = 0; i < kElementCount; i++) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012753 CHECK_EQ(static_cast<int64_t>(i),
12754 static_cast<int64_t>(array->get_scalar(i)));
Steve Block3ce2e202009-11-05 08:53:23 +000012755 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
12756 }
12757
12758 v8::Handle<v8::Object> obj = v8::Object::New();
12759 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
12760 // Set the elements to be the external array.
12761 obj->SetIndexedPropertiesToExternalArrayData(array_data,
12762 array_type,
12763 kElementCount);
John Reck59135872010-11-02 12:39:01 -070012764 CHECK_EQ(
12765 1, static_cast<int>(jsobj->GetElement(1)->ToObjectChecked()->Number()));
Steve Block3ce2e202009-11-05 08:53:23 +000012766 obj->Set(v8_str("field"), v8::Int32::New(1503));
12767 context->Global()->Set(v8_str("ext_array"), obj);
12768 v8::Handle<v8::Value> result = CompileRun("ext_array.field");
12769 CHECK_EQ(1503, result->Int32Value());
12770 result = CompileRun("ext_array[1]");
12771 CHECK_EQ(1, result->Int32Value());
12772
12773 // Check pass through of assigned smis
12774 result = CompileRun("var sum = 0;"
12775 "for (var i = 0; i < 8; i++) {"
12776 " sum += ext_array[i] = ext_array[i] = -i;"
12777 "}"
12778 "sum;");
12779 CHECK_EQ(-28, result->Int32Value());
12780
12781 // Check assigned smis
12782 result = CompileRun("for (var i = 0; i < 8; i++) {"
12783 " ext_array[i] = i;"
12784 "}"
12785 "var sum = 0;"
12786 "for (var i = 0; i < 8; i++) {"
12787 " sum += ext_array[i];"
12788 "}"
12789 "sum;");
12790 CHECK_EQ(28, result->Int32Value());
12791
12792 // Check assigned smis in reverse order
12793 result = CompileRun("for (var i = 8; --i >= 0; ) {"
12794 " ext_array[i] = i;"
12795 "}"
12796 "var sum = 0;"
12797 "for (var i = 0; i < 8; i++) {"
12798 " sum += ext_array[i];"
12799 "}"
12800 "sum;");
12801 CHECK_EQ(28, result->Int32Value());
12802
12803 // Check pass through of assigned HeapNumbers
12804 result = CompileRun("var sum = 0;"
12805 "for (var i = 0; i < 16; i+=2) {"
12806 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
12807 "}"
12808 "sum;");
12809 CHECK_EQ(-28, result->Int32Value());
12810
12811 // Check assigned HeapNumbers
12812 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
12813 " ext_array[i] = (i * 0.5);"
12814 "}"
12815 "var sum = 0;"
12816 "for (var i = 0; i < 16; i+=2) {"
12817 " sum += ext_array[i];"
12818 "}"
12819 "sum;");
12820 CHECK_EQ(28, result->Int32Value());
12821
12822 // Check assigned HeapNumbers in reverse order
12823 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
12824 " ext_array[i] = (i * 0.5);"
12825 "}"
12826 "var sum = 0;"
12827 "for (var i = 0; i < 16; i+=2) {"
12828 " sum += ext_array[i];"
12829 "}"
12830 "sum;");
12831 CHECK_EQ(28, result->Int32Value());
12832
12833 i::ScopedVector<char> test_buf(1024);
12834
12835 // Check legal boundary conditions.
12836 // The repeated loads and stores ensure the ICs are exercised.
12837 const char* boundary_program =
12838 "var res = 0;"
12839 "for (var i = 0; i < 16; i++) {"
12840 " ext_array[i] = %lld;"
12841 " if (i > 8) {"
12842 " res = ext_array[i];"
12843 " }"
12844 "}"
12845 "res;";
12846 i::OS::SNPrintF(test_buf,
12847 boundary_program,
12848 low);
12849 result = CompileRun(test_buf.start());
12850 CHECK_EQ(low, result->IntegerValue());
12851
12852 i::OS::SNPrintF(test_buf,
12853 boundary_program,
12854 high);
12855 result = CompileRun(test_buf.start());
12856 CHECK_EQ(high, result->IntegerValue());
12857
12858 // Check misprediction of type in IC.
12859 result = CompileRun("var tmp_array = ext_array;"
12860 "var sum = 0;"
12861 "for (var i = 0; i < 8; i++) {"
12862 " tmp_array[i] = i;"
12863 " sum += tmp_array[i];"
12864 " if (i == 4) {"
12865 " tmp_array = {};"
12866 " }"
12867 "}"
12868 "sum;");
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012869 // Force GC to trigger verification.
12870 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Block3ce2e202009-11-05 08:53:23 +000012871 CHECK_EQ(28, result->Int32Value());
12872
12873 // Make sure out-of-range loads do not throw.
12874 i::OS::SNPrintF(test_buf,
12875 "var caught_exception = false;"
12876 "try {"
12877 " ext_array[%d];"
12878 "} catch (e) {"
12879 " caught_exception = true;"
12880 "}"
12881 "caught_exception;",
12882 kElementCount);
12883 result = CompileRun(test_buf.start());
12884 CHECK_EQ(false, result->BooleanValue());
12885
12886 // Make sure out-of-range stores do not throw.
12887 i::OS::SNPrintF(test_buf,
12888 "var caught_exception = false;"
12889 "try {"
12890 " ext_array[%d] = 1;"
12891 "} catch (e) {"
12892 " caught_exception = true;"
12893 "}"
12894 "caught_exception;",
12895 kElementCount);
12896 result = CompileRun(test_buf.start());
12897 CHECK_EQ(false, result->BooleanValue());
12898
12899 // Check other boundary conditions, values and operations.
12900 result = CompileRun("for (var i = 0; i < 8; i++) {"
12901 " ext_array[7] = undefined;"
12902 "}"
12903 "ext_array[7];");
12904 CHECK_EQ(0, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070012905 CHECK_EQ(
12906 0, static_cast<int>(jsobj->GetElement(7)->ToObjectChecked()->Number()));
Steve Block3ce2e202009-11-05 08:53:23 +000012907
12908 result = CompileRun("for (var i = 0; i < 8; i++) {"
12909 " ext_array[6] = '2.3';"
12910 "}"
12911 "ext_array[6];");
12912 CHECK_EQ(2, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070012913 CHECK_EQ(
12914 2, static_cast<int>(jsobj->GetElement(6)->ToObjectChecked()->Number()));
Steve Block3ce2e202009-11-05 08:53:23 +000012915
Ben Murdoch257744e2011-11-30 15:57:28 +000012916 if (array_type != v8::kExternalFloatArray &&
12917 array_type != v8::kExternalDoubleArray) {
Steve Block3ce2e202009-11-05 08:53:23 +000012918 // Though the specification doesn't state it, be explicit about
12919 // converting NaNs and +/-Infinity to zero.
12920 result = CompileRun("for (var i = 0; i < 8; i++) {"
12921 " ext_array[i] = 5;"
12922 "}"
12923 "for (var i = 0; i < 8; i++) {"
12924 " ext_array[i] = NaN;"
12925 "}"
12926 "ext_array[5];");
12927 CHECK_EQ(0, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070012928 CHECK_EQ(0,
12929 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
Steve Block3ce2e202009-11-05 08:53:23 +000012930
12931 result = CompileRun("for (var i = 0; i < 8; i++) {"
12932 " ext_array[i] = 5;"
12933 "}"
12934 "for (var i = 0; i < 8; i++) {"
12935 " ext_array[i] = Infinity;"
12936 "}"
12937 "ext_array[5];");
Steve Block44f0eee2011-05-26 01:26:41 +010012938 int expected_value =
12939 (array_type == v8::kExternalPixelArray) ? 255 : 0;
12940 CHECK_EQ(expected_value, result->Int32Value());
12941 CHECK_EQ(expected_value,
John Reck59135872010-11-02 12:39:01 -070012942 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
Steve Block3ce2e202009-11-05 08:53:23 +000012943
12944 result = CompileRun("for (var i = 0; i < 8; i++) {"
12945 " ext_array[i] = 5;"
12946 "}"
12947 "for (var i = 0; i < 8; i++) {"
12948 " ext_array[i] = -Infinity;"
12949 "}"
12950 "ext_array[5];");
12951 CHECK_EQ(0, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070012952 CHECK_EQ(0,
12953 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
Steve Block1e0659c2011-05-24 12:43:12 +010012954
12955 // Check truncation behavior of integral arrays.
12956 const char* unsigned_data =
12957 "var source_data = [0.6, 10.6];"
12958 "var expected_results = [0, 10];";
12959 const char* signed_data =
12960 "var source_data = [0.6, 10.6, -0.6, -10.6];"
12961 "var expected_results = [0, 10, 0, -10];";
Steve Block44f0eee2011-05-26 01:26:41 +010012962 const char* pixel_data =
12963 "var source_data = [0.6, 10.6];"
12964 "var expected_results = [1, 11];";
Steve Block1e0659c2011-05-24 12:43:12 +010012965 bool is_unsigned =
12966 (array_type == v8::kExternalUnsignedByteArray ||
12967 array_type == v8::kExternalUnsignedShortArray ||
12968 array_type == v8::kExternalUnsignedIntArray);
Steve Block44f0eee2011-05-26 01:26:41 +010012969 bool is_pixel_data = array_type == v8::kExternalPixelArray;
Steve Block1e0659c2011-05-24 12:43:12 +010012970
12971 i::OS::SNPrintF(test_buf,
12972 "%s"
12973 "var all_passed = true;"
12974 "for (var i = 0; i < source_data.length; i++) {"
12975 " for (var j = 0; j < 8; j++) {"
12976 " ext_array[j] = source_data[i];"
12977 " }"
12978 " all_passed = all_passed &&"
12979 " (ext_array[5] == expected_results[i]);"
12980 "}"
12981 "all_passed;",
Steve Block44f0eee2011-05-26 01:26:41 +010012982 (is_unsigned ?
12983 unsigned_data :
12984 (is_pixel_data ? pixel_data : signed_data)));
Steve Block1e0659c2011-05-24 12:43:12 +010012985 result = CompileRun(test_buf.start());
12986 CHECK_EQ(true, result->BooleanValue());
Steve Block3ce2e202009-11-05 08:53:23 +000012987 }
12988
Ben Murdoch8b112d22011-06-08 16:22:53 +010012989 for (int i = 0; i < kElementCount; i++) {
12990 array->set(i, static_cast<ElementType>(i));
12991 }
12992 // Test complex assignments
12993 result = CompileRun("function ee_op_test_complex_func(sum) {"
12994 " for (var i = 0; i < 40; ++i) {"
12995 " sum += (ext_array[i] += 1);"
12996 " sum += (ext_array[i] -= 1);"
12997 " } "
12998 " return sum;"
12999 "}"
13000 "sum=0;"
13001 "for (var i=0;i<10000;++i) {"
13002 " sum=ee_op_test_complex_func(sum);"
13003 "}"
13004 "sum;");
13005 CHECK_EQ(16000000, result->Int32Value());
13006
13007 // Test count operations
13008 result = CompileRun("function ee_op_test_count_func(sum) {"
13009 " for (var i = 0; i < 40; ++i) {"
13010 " sum += (++ext_array[i]);"
13011 " sum += (--ext_array[i]);"
13012 " } "
13013 " return sum;"
13014 "}"
13015 "sum=0;"
13016 "for (var i=0;i<10000;++i) {"
13017 " sum=ee_op_test_count_func(sum);"
13018 "}"
13019 "sum;");
13020 CHECK_EQ(16000000, result->Int32Value());
13021
Steve Block3ce2e202009-11-05 08:53:23 +000013022 result = CompileRun("ext_array[3] = 33;"
13023 "delete ext_array[3];"
13024 "ext_array[3];");
13025 CHECK_EQ(33, result->Int32Value());
13026
13027 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
13028 "ext_array[2] = 12; ext_array[3] = 13;"
13029 "ext_array.__defineGetter__('2',"
13030 "function() { return 120; });"
13031 "ext_array[2];");
13032 CHECK_EQ(12, result->Int32Value());
13033
13034 result = CompileRun("var js_array = new Array(40);"
13035 "js_array[0] = 77;"
13036 "js_array;");
13037 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
13038
13039 result = CompileRun("ext_array[1] = 23;"
13040 "ext_array.__proto__ = [];"
13041 "js_array.__proto__ = ext_array;"
13042 "js_array.concat(ext_array);");
13043 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
13044 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
13045
13046 result = CompileRun("ext_array[1] = 23;");
13047 CHECK_EQ(23, result->Int32Value());
13048
Steve Blockd0582a62009-12-15 09:54:21 +000013049 // Test more complex manipulations which cause eax to contain values
13050 // that won't be completely overwritten by loads from the arrays.
13051 // This catches bugs in the instructions used for the KeyedLoadIC
13052 // for byte and word types.
13053 {
13054 const int kXSize = 300;
13055 const int kYSize = 300;
13056 const int kLargeElementCount = kXSize * kYSize * 4;
13057 ElementType* large_array_data =
13058 static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
Steve Blockd0582a62009-12-15 09:54:21 +000013059 v8::Handle<v8::Object> large_obj = v8::Object::New();
13060 // Set the elements to be the external array.
13061 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
13062 array_type,
13063 kLargeElementCount);
13064 context->Global()->Set(v8_str("large_array"), large_obj);
13065 // Initialize contents of a few rows.
13066 for (int x = 0; x < 300; x++) {
13067 int row = 0;
13068 int offset = row * 300 * 4;
13069 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
13070 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
13071 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
13072 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
13073 row = 150;
13074 offset = row * 300 * 4;
13075 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
13076 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
13077 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
13078 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
13079 row = 298;
13080 offset = row * 300 * 4;
13081 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
13082 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
13083 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
13084 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
13085 }
13086 // The goal of the code below is to make "offset" large enough
13087 // that the computation of the index (which goes into eax) has
13088 // high bits set which will not be overwritten by a byte or short
13089 // load.
13090 result = CompileRun("var failed = false;"
13091 "var offset = 0;"
13092 "for (var i = 0; i < 300; i++) {"
13093 " if (large_array[4 * i] != 127 ||"
13094 " large_array[4 * i + 1] != 0 ||"
13095 " large_array[4 * i + 2] != 0 ||"
13096 " large_array[4 * i + 3] != 127) {"
13097 " failed = true;"
13098 " }"
13099 "}"
13100 "offset = 150 * 300 * 4;"
13101 "for (var i = 0; i < 300; i++) {"
13102 " if (large_array[offset + 4 * i] != 127 ||"
13103 " large_array[offset + 4 * i + 1] != 0 ||"
13104 " large_array[offset + 4 * i + 2] != 0 ||"
13105 " large_array[offset + 4 * i + 3] != 127) {"
13106 " failed = true;"
13107 " }"
13108 "}"
13109 "offset = 298 * 300 * 4;"
13110 "for (var i = 0; i < 300; i++) {"
13111 " if (large_array[offset + 4 * i] != 127 ||"
13112 " large_array[offset + 4 * i + 1] != 0 ||"
13113 " large_array[offset + 4 * i + 2] != 0 ||"
13114 " large_array[offset + 4 * i + 3] != 127) {"
13115 " failed = true;"
13116 " }"
13117 "}"
13118 "!failed;");
13119 CHECK_EQ(true, result->BooleanValue());
13120 free(large_array_data);
13121 }
13122
Steve Block44f0eee2011-05-26 01:26:41 +010013123 // The "" property descriptor is overloaded to store information about
13124 // the external array. Ensure that setting and accessing the "" property
13125 // works (it should overwrite the information cached about the external
13126 // array in the DescriptorArray) in various situations.
13127 result = CompileRun("ext_array[''] = 23; ext_array['']");
13128 CHECK_EQ(23, result->Int32Value());
13129
13130 // Property "" set after the external array is associated with the object.
13131 {
13132 v8::Handle<v8::Object> obj2 = v8::Object::New();
13133 obj2->Set(v8_str("ee_test_field"), v8::Int32::New(256));
13134 obj2->Set(v8_str(""), v8::Int32::New(1503));
13135 // Set the elements to be the external array.
13136 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
13137 array_type,
13138 kElementCount);
13139 context->Global()->Set(v8_str("ext_array"), obj2);
13140 result = CompileRun("ext_array['']");
13141 CHECK_EQ(1503, result->Int32Value());
13142 }
13143
13144 // Property "" set after the external array is associated with the object.
13145 {
13146 v8::Handle<v8::Object> obj2 = v8::Object::New();
13147 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
13148 // Set the elements to be the external array.
13149 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
13150 array_type,
13151 kElementCount);
13152 obj2->Set(v8_str(""), v8::Int32::New(1503));
13153 context->Global()->Set(v8_str("ext_array"), obj2);
13154 result = CompileRun("ext_array['']");
13155 CHECK_EQ(1503, result->Int32Value());
13156 }
13157
13158 // Should reuse the map from previous test.
13159 {
13160 v8::Handle<v8::Object> obj2 = v8::Object::New();
13161 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
13162 // Set the elements to be the external array. Should re-use the map
13163 // from previous test.
13164 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
13165 array_type,
13166 kElementCount);
13167 context->Global()->Set(v8_str("ext_array"), obj2);
13168 result = CompileRun("ext_array['']");
13169 }
13170
13171 // Property "" is a constant function that shouldn't not be interfered with
13172 // when an external array is set.
13173 {
13174 v8::Handle<v8::Object> obj2 = v8::Object::New();
13175 // Start
13176 obj2->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
13177
13178 // Add a constant function to an object.
13179 context->Global()->Set(v8_str("ext_array"), obj2);
13180 result = CompileRun("ext_array[''] = function() {return 1503;};"
13181 "ext_array['']();");
13182
13183 // Add an external array transition to the same map that
13184 // has the constant transition.
13185 v8::Handle<v8::Object> obj3 = v8::Object::New();
13186 obj3->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
13187 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
13188 array_type,
13189 kElementCount);
13190 context->Global()->Set(v8_str("ext_array"), obj3);
13191 }
13192
13193 // If a external array transition is in the map, it should get clobbered
13194 // by a constant function.
13195 {
13196 // Add an external array transition.
13197 v8::Handle<v8::Object> obj3 = v8::Object::New();
13198 obj3->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
13199 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
13200 array_type,
13201 kElementCount);
13202
13203 // Add a constant function to the same map that just got an external array
13204 // transition.
13205 v8::Handle<v8::Object> obj2 = v8::Object::New();
13206 obj2->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
13207 context->Global()->Set(v8_str("ext_array"), obj2);
13208 result = CompileRun("ext_array[''] = function() {return 1503;};"
13209 "ext_array['']();");
13210 }
13211
Steve Block3ce2e202009-11-05 08:53:23 +000013212 free(array_data);
13213}
13214
13215
13216THREADED_TEST(ExternalByteArray) {
Steve Block8defd9f2010-07-08 12:39:36 +010013217 ExternalArrayTestHelper<i::ExternalByteArray, int8_t>(
Steve Block3ce2e202009-11-05 08:53:23 +000013218 v8::kExternalByteArray,
13219 -128,
13220 127);
13221}
13222
13223
13224THREADED_TEST(ExternalUnsignedByteArray) {
Steve Block8defd9f2010-07-08 12:39:36 +010013225 ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>(
Steve Block3ce2e202009-11-05 08:53:23 +000013226 v8::kExternalUnsignedByteArray,
13227 0,
13228 255);
13229}
13230
13231
Steve Block44f0eee2011-05-26 01:26:41 +010013232THREADED_TEST(ExternalPixelArray) {
13233 ExternalArrayTestHelper<i::ExternalPixelArray, uint8_t>(
13234 v8::kExternalPixelArray,
13235 0,
13236 255);
13237}
13238
13239
Steve Block3ce2e202009-11-05 08:53:23 +000013240THREADED_TEST(ExternalShortArray) {
Steve Block8defd9f2010-07-08 12:39:36 +010013241 ExternalArrayTestHelper<i::ExternalShortArray, int16_t>(
Steve Block3ce2e202009-11-05 08:53:23 +000013242 v8::kExternalShortArray,
13243 -32768,
13244 32767);
13245}
13246
13247
13248THREADED_TEST(ExternalUnsignedShortArray) {
Steve Block8defd9f2010-07-08 12:39:36 +010013249 ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>(
Steve Block3ce2e202009-11-05 08:53:23 +000013250 v8::kExternalUnsignedShortArray,
13251 0,
13252 65535);
13253}
13254
13255
13256THREADED_TEST(ExternalIntArray) {
Steve Block8defd9f2010-07-08 12:39:36 +010013257 ExternalArrayTestHelper<i::ExternalIntArray, int32_t>(
Steve Block3ce2e202009-11-05 08:53:23 +000013258 v8::kExternalIntArray,
13259 INT_MIN, // -2147483648
13260 INT_MAX); // 2147483647
13261}
13262
13263
13264THREADED_TEST(ExternalUnsignedIntArray) {
Steve Block8defd9f2010-07-08 12:39:36 +010013265 ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>(
Steve Block3ce2e202009-11-05 08:53:23 +000013266 v8::kExternalUnsignedIntArray,
13267 0,
13268 UINT_MAX); // 4294967295
13269}
13270
13271
13272THREADED_TEST(ExternalFloatArray) {
Steve Block8defd9f2010-07-08 12:39:36 +010013273 ExternalArrayTestHelper<i::ExternalFloatArray, float>(
Steve Block3ce2e202009-11-05 08:53:23 +000013274 v8::kExternalFloatArray,
13275 -500,
13276 500);
13277}
13278
13279
Ben Murdoch257744e2011-11-30 15:57:28 +000013280THREADED_TEST(ExternalDoubleArray) {
13281 ExternalArrayTestHelper<i::ExternalDoubleArray, double>(
13282 v8::kExternalDoubleArray,
13283 -500,
13284 500);
13285}
13286
13287
Steve Block3ce2e202009-11-05 08:53:23 +000013288THREADED_TEST(ExternalArrays) {
13289 TestExternalByteArray();
13290 TestExternalUnsignedByteArray();
13291 TestExternalShortArray();
13292 TestExternalUnsignedShortArray();
13293 TestExternalIntArray();
13294 TestExternalUnsignedIntArray();
13295 TestExternalFloatArray();
13296}
13297
13298
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010013299void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
13300 v8::HandleScope scope;
13301 LocalContext context;
13302 for (int size = 0; size < 100; size += 10) {
13303 int element_size = ExternalArrayElementSize(array_type);
13304 void* external_data = malloc(size * element_size);
13305 v8::Handle<v8::Object> obj = v8::Object::New();
13306 obj->SetIndexedPropertiesToExternalArrayData(
13307 external_data, array_type, size);
13308 CHECK(obj->HasIndexedPropertiesInExternalArrayData());
13309 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
13310 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
13311 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
13312 free(external_data);
13313 }
13314}
13315
13316
13317THREADED_TEST(ExternalArrayInfo) {
13318 ExternalArrayInfoTestHelper(v8::kExternalByteArray);
13319 ExternalArrayInfoTestHelper(v8::kExternalUnsignedByteArray);
13320 ExternalArrayInfoTestHelper(v8::kExternalShortArray);
13321 ExternalArrayInfoTestHelper(v8::kExternalUnsignedShortArray);
13322 ExternalArrayInfoTestHelper(v8::kExternalIntArray);
13323 ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray);
13324 ExternalArrayInfoTestHelper(v8::kExternalFloatArray);
Ben Murdoch257744e2011-11-30 15:57:28 +000013325 ExternalArrayInfoTestHelper(v8::kExternalDoubleArray);
Steve Block44f0eee2011-05-26 01:26:41 +010013326 ExternalArrayInfoTestHelper(v8::kExternalPixelArray);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010013327}
13328
13329
Steve Blocka7e24c12009-10-30 11:49:00 +000013330THREADED_TEST(ScriptContextDependence) {
13331 v8::HandleScope scope;
13332 LocalContext c1;
13333 const char *source = "foo";
13334 v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
13335 v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
13336 c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
13337 CHECK_EQ(dep->Run()->Int32Value(), 100);
13338 CHECK_EQ(indep->Run()->Int32Value(), 100);
13339 LocalContext c2;
13340 c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
13341 CHECK_EQ(dep->Run()->Int32Value(), 100);
13342 CHECK_EQ(indep->Run()->Int32Value(), 101);
13343}
13344
13345
13346THREADED_TEST(StackTrace) {
13347 v8::HandleScope scope;
13348 LocalContext context;
13349 v8::TryCatch try_catch;
13350 const char *source = "function foo() { FAIL.FAIL; }; foo();";
13351 v8::Handle<v8::String> src = v8::String::New(source);
13352 v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
13353 v8::Script::New(src, origin)->Run();
13354 CHECK(try_catch.HasCaught());
13355 v8::String::Utf8Value stack(try_catch.StackTrace());
13356 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
13357}
13358
13359
Kristian Monsen25f61362010-05-21 11:50:48 +010013360// Checks that a StackFrame has certain expected values.
13361void checkStackFrame(const char* expected_script_name,
13362 const char* expected_func_name, int expected_line_number,
13363 int expected_column, bool is_eval, bool is_constructor,
13364 v8::Handle<v8::StackFrame> frame) {
13365 v8::HandleScope scope;
13366 v8::String::Utf8Value func_name(frame->GetFunctionName());
13367 v8::String::Utf8Value script_name(frame->GetScriptName());
13368 if (*script_name == NULL) {
13369 // The situation where there is no associated script, like for evals.
13370 CHECK(expected_script_name == NULL);
13371 } else {
13372 CHECK(strstr(*script_name, expected_script_name) != NULL);
13373 }
13374 CHECK(strstr(*func_name, expected_func_name) != NULL);
13375 CHECK_EQ(expected_line_number, frame->GetLineNumber());
13376 CHECK_EQ(expected_column, frame->GetColumn());
13377 CHECK_EQ(is_eval, frame->IsEval());
13378 CHECK_EQ(is_constructor, frame->IsConstructor());
13379}
13380
13381
13382v8::Handle<Value> AnalyzeStackInNativeCode(const v8::Arguments& args) {
13383 v8::HandleScope scope;
13384 const char* origin = "capture-stack-trace-test";
13385 const int kOverviewTest = 1;
13386 const int kDetailedTest = 2;
13387
13388 ASSERT(args.Length() == 1);
13389
13390 int testGroup = args[0]->Int32Value();
13391 if (testGroup == kOverviewTest) {
13392 v8::Handle<v8::StackTrace> stackTrace =
13393 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
13394 CHECK_EQ(4, stackTrace->GetFrameCount());
13395 checkStackFrame(origin, "bar", 2, 10, false, false,
13396 stackTrace->GetFrame(0));
13397 checkStackFrame(origin, "foo", 6, 3, false, false,
13398 stackTrace->GetFrame(1));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013399 // This is the source string inside the eval which has the call to foo.
13400 checkStackFrame(NULL, "", 1, 5, false, false,
Kristian Monsen25f61362010-05-21 11:50:48 +010013401 stackTrace->GetFrame(2));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013402 // The last frame is an anonymous function which has the initial eval call.
Kristian Monsen25f61362010-05-21 11:50:48 +010013403 checkStackFrame(origin, "", 8, 7, false, false,
13404 stackTrace->GetFrame(3));
13405
13406 CHECK(stackTrace->AsArray()->IsArray());
13407 } else if (testGroup == kDetailedTest) {
13408 v8::Handle<v8::StackTrace> stackTrace =
13409 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
13410 CHECK_EQ(4, stackTrace->GetFrameCount());
13411 checkStackFrame(origin, "bat", 4, 22, false, false,
13412 stackTrace->GetFrame(0));
13413 checkStackFrame(origin, "baz", 8, 3, false, true,
13414 stackTrace->GetFrame(1));
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010013415#ifdef ENABLE_DEBUGGER_SUPPORT
13416 bool is_eval = true;
13417#else // ENABLE_DEBUGGER_SUPPORT
13418 bool is_eval = false;
13419#endif // ENABLE_DEBUGGER_SUPPORT
13420
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013421 // This is the source string inside the eval which has the call to baz.
13422 checkStackFrame(NULL, "", 1, 5, is_eval, false,
Kristian Monsen25f61362010-05-21 11:50:48 +010013423 stackTrace->GetFrame(2));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013424 // The last frame is an anonymous function which has the initial eval call.
Kristian Monsen25f61362010-05-21 11:50:48 +010013425 checkStackFrame(origin, "", 10, 1, false, false,
13426 stackTrace->GetFrame(3));
13427
13428 CHECK(stackTrace->AsArray()->IsArray());
13429 }
13430 return v8::Undefined();
13431}
13432
13433
13434// Tests the C++ StackTrace API.
Ben Murdochb0fe1622011-05-05 13:52:32 +010013435// TODO(3074796): Reenable this as a THREADED_TEST once it passes.
13436// THREADED_TEST(CaptureStackTrace) {
13437TEST(CaptureStackTrace) {
Kristian Monsen25f61362010-05-21 11:50:48 +010013438 v8::HandleScope scope;
13439 v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
13440 Local<ObjectTemplate> templ = ObjectTemplate::New();
13441 templ->Set(v8_str("AnalyzeStackInNativeCode"),
13442 v8::FunctionTemplate::New(AnalyzeStackInNativeCode));
13443 LocalContext context(0, templ);
13444
13445 // Test getting OVERVIEW information. Should ignore information that is not
13446 // script name, function name, line number, and column offset.
13447 const char *overview_source =
13448 "function bar() {\n"
13449 " var y; AnalyzeStackInNativeCode(1);\n"
13450 "}\n"
13451 "function foo() {\n"
13452 "\n"
13453 " bar();\n"
13454 "}\n"
13455 "var x;eval('new foo();');";
13456 v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
Ben Murdoch592a9fc2012-03-05 11:04:45 +000013457 v8::Handle<Value> overview_result(
13458 v8::Script::New(overview_src, origin)->Run());
Ben Murdochc7cc0282012-03-05 14:35:55 +000013459 CHECK(!overview_result.IsEmpty());
13460 CHECK(overview_result->IsObject());
Kristian Monsen25f61362010-05-21 11:50:48 +010013461
13462 // Test getting DETAILED information.
13463 const char *detailed_source =
13464 "function bat() {AnalyzeStackInNativeCode(2);\n"
13465 "}\n"
13466 "\n"
13467 "function baz() {\n"
13468 " bat();\n"
13469 "}\n"
13470 "eval('new baz();');";
13471 v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
13472 // Make the script using a non-zero line and column offset.
13473 v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
13474 v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
13475 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
13476 v8::Handle<v8::Script> detailed_script(
13477 v8::Script::New(detailed_src, &detailed_origin));
Ben Murdoch592a9fc2012-03-05 11:04:45 +000013478 v8::Handle<Value> detailed_result(detailed_script->Run());
Ben Murdochc7cc0282012-03-05 14:35:55 +000013479 CHECK(!detailed_result.IsEmpty());
13480 CHECK(detailed_result->IsObject());
Kristian Monsen25f61362010-05-21 11:50:48 +010013481}
13482
13483
Ben Murdoch3bec4d22010-07-22 14:51:16 +010013484static void StackTraceForUncaughtExceptionListener(
13485 v8::Handle<v8::Message> message,
13486 v8::Handle<Value>) {
13487 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
13488 CHECK_EQ(2, stack_trace->GetFrameCount());
13489 checkStackFrame("origin", "foo", 2, 3, false, false,
13490 stack_trace->GetFrame(0));
13491 checkStackFrame("origin", "bar", 5, 3, false, false,
13492 stack_trace->GetFrame(1));
13493}
13494
13495TEST(CaptureStackTraceForUncaughtException) {
13496 report_count = 0;
13497 v8::HandleScope scope;
13498 LocalContext env;
13499 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
13500 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
13501
13502 Script::Compile(v8_str("function foo() {\n"
13503 " throw 1;\n"
13504 "};\n"
13505 "function bar() {\n"
13506 " foo();\n"
13507 "};"),
13508 v8_str("origin"))->Run();
13509 v8::Local<v8::Object> global = env->Global();
13510 Local<Value> trouble = global->Get(v8_str("bar"));
13511 CHECK(trouble->IsFunction());
13512 Function::Cast(*trouble)->Call(global, 0, NULL);
13513 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
13514 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
13515}
13516
13517
Steve Block1e0659c2011-05-24 12:43:12 +010013518TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
13519 v8::HandleScope scope;
13520 LocalContext env;
13521 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
13522 1024,
13523 v8::StackTrace::kDetailed);
13524
13525 CompileRun(
13526 "var setters = ['column', 'lineNumber', 'scriptName',\n"
13527 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
13528 " 'isConstructor'];\n"
13529 "for (var i = 0; i < setters.length; i++) {\n"
13530 " var prop = setters[i];\n"
13531 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
13532 "}\n");
13533 CompileRun("throw 'exception';");
13534 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
13535}
13536
13537
Ben Murdochf87a2032010-10-22 12:50:53 +010013538v8::Handle<Value> AnalyzeStackOfEvalWithSourceURL(const v8::Arguments& args) {
13539 v8::HandleScope scope;
13540 v8::Handle<v8::StackTrace> stackTrace =
13541 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
13542 CHECK_EQ(5, stackTrace->GetFrameCount());
13543 v8::Handle<v8::String> url = v8_str("eval_url");
13544 for (int i = 0; i < 3; i++) {
13545 v8::Handle<v8::String> name =
13546 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
13547 CHECK(!name.IsEmpty());
13548 CHECK_EQ(url, name);
13549 }
13550 return v8::Undefined();
13551}
13552
13553
13554TEST(SourceURLInStackTrace) {
13555 v8::HandleScope scope;
13556 Local<ObjectTemplate> templ = ObjectTemplate::New();
13557 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
13558 v8::FunctionTemplate::New(AnalyzeStackOfEvalWithSourceURL));
13559 LocalContext context(0, templ);
13560
13561 const char *source =
13562 "function outer() {\n"
13563 "function bar() {\n"
13564 " AnalyzeStackOfEvalWithSourceURL();\n"
13565 "}\n"
13566 "function foo() {\n"
13567 "\n"
13568 " bar();\n"
13569 "}\n"
13570 "foo();\n"
13571 "}\n"
13572 "eval('(' + outer +')()//@ sourceURL=eval_url');";
13573 CHECK(CompileRun(source)->IsUndefined());
13574}
13575
13576
Steve Block3ce2e202009-11-05 08:53:23 +000013577// Test that idle notification can be handled and eventually returns true.
Ben Murdochc7cc0282012-03-05 14:35:55 +000013578// This just checks the contract of the IdleNotification() function,
13579// and does not verify that it does reasonable work.
Steve Blocka7e24c12009-10-30 11:49:00 +000013580THREADED_TEST(IdleNotification) {
Ben Murdochc7cc0282012-03-05 14:35:55 +000013581 v8::HandleScope scope;
13582 LocalContext env;
13583 CompileRun("function binom(n, m) {"
13584 " var C = [[1]];"
13585 " for (var i = 1; i <= n; ++i) {"
13586 " C[i] = [1];"
13587 " for (var j = 1; j < i; ++j) {"
13588 " C[i][j] = C[i-1][j-1] + C[i-1][j];"
13589 " }"
13590 " C[i][i] = 1;"
13591 " }"
13592 " return C[n][m];"
13593 "};"
13594 "binom(1000, 500)");
Steve Block3ce2e202009-11-05 08:53:23 +000013595 bool rv = false;
13596 for (int i = 0; i < 100; i++) {
13597 rv = v8::V8::IdleNotification();
13598 if (rv)
13599 break;
13600 }
13601 CHECK(rv == true);
Steve Blocka7e24c12009-10-30 11:49:00 +000013602}
13603
Ben Murdochc7cc0282012-03-05 14:35:55 +000013604// Test that idle notification can be handled and eventually returns true.
13605// This just checks the contract of the IdleNotification() function,
13606// and does not verify that it does reasonable work.
13607TEST(IdleNotificationWithHint) {
13608 v8::HandleScope scope;
13609 LocalContext env;
13610 {
13611 i::AlwaysAllocateScope always_allocate;
13612 CompileRun("function binom(n, m) {"
13613 " var C = [[1]];"
13614 " for (var i = 1; i <= n; ++i) {"
13615 " C[i] = [1];"
13616 " for (var j = 1; j < i; ++j) {"
13617 " C[i][j] = C[i-1][j-1] + C[i-1][j];"
13618 " }"
13619 " C[i][i] = 1;"
13620 " }"
13621 " return C[n][m];"
13622 "};"
13623 "binom(1000, 500)");
13624 }
13625 bool rv = false;
13626 intptr_t old_size = HEAP->SizeOfObjects();
13627 bool no_idle_work = v8::V8::IdleNotification(10);
13628 for (int i = 0; i < 200; i++) {
13629 rv = v8::V8::IdleNotification(10);
13630 if (rv)
13631 break;
13632 }
13633 CHECK(rv == true);
13634 intptr_t new_size = HEAP->SizeOfObjects();
13635 CHECK(no_idle_work || new_size < old_size);
13636}
13637
Steve Blocka7e24c12009-10-30 11:49:00 +000013638
13639static uint32_t* stack_limit;
13640
13641static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
Steve Block44f0eee2011-05-26 01:26:41 +010013642 stack_limit = reinterpret_cast<uint32_t*>(
13643 i::Isolate::Current()->stack_guard()->real_climit());
Steve Blocka7e24c12009-10-30 11:49:00 +000013644 return v8::Undefined();
13645}
13646
13647
13648// Uses the address of a local variable to determine the stack top now.
13649// Given a size, returns an address that is that far from the current
13650// top of stack.
13651static uint32_t* ComputeStackLimit(uint32_t size) {
13652 uint32_t* answer = &size - (size / sizeof(size));
13653 // If the size is very large and the stack is very near the bottom of
13654 // memory then the calculation above may wrap around and give an address
13655 // that is above the (downwards-growing) stack. In that case we return
13656 // a very low address.
13657 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
13658 return answer;
13659}
13660
13661
13662TEST(SetResourceConstraints) {
13663 static const int K = 1024;
13664 uint32_t* set_limit = ComputeStackLimit(128 * K);
13665
13666 // Set stack limit.
13667 v8::ResourceConstraints constraints;
13668 constraints.set_stack_limit(set_limit);
13669 CHECK(v8::SetResourceConstraints(&constraints));
13670
13671 // Execute a script.
13672 v8::HandleScope scope;
13673 LocalContext env;
13674 Local<v8::FunctionTemplate> fun_templ =
13675 v8::FunctionTemplate::New(GetStackLimitCallback);
13676 Local<Function> fun = fun_templ->GetFunction();
13677 env->Global()->Set(v8_str("get_stack_limit"), fun);
13678 CompileRun("get_stack_limit();");
13679
13680 CHECK(stack_limit == set_limit);
13681}
13682
13683
13684TEST(SetResourceConstraintsInThread) {
13685 uint32_t* set_limit;
13686 {
13687 v8::Locker locker;
13688 static const int K = 1024;
13689 set_limit = ComputeStackLimit(128 * K);
13690
13691 // Set stack limit.
13692 v8::ResourceConstraints constraints;
13693 constraints.set_stack_limit(set_limit);
13694 CHECK(v8::SetResourceConstraints(&constraints));
13695
13696 // Execute a script.
13697 v8::HandleScope scope;
13698 LocalContext env;
13699 Local<v8::FunctionTemplate> fun_templ =
13700 v8::FunctionTemplate::New(GetStackLimitCallback);
13701 Local<Function> fun = fun_templ->GetFunction();
13702 env->Global()->Set(v8_str("get_stack_limit"), fun);
13703 CompileRun("get_stack_limit();");
13704
13705 CHECK(stack_limit == set_limit);
13706 }
13707 {
13708 v8::Locker locker;
13709 CHECK(stack_limit == set_limit);
13710 }
13711}
Steve Block3ce2e202009-11-05 08:53:23 +000013712
13713
13714THREADED_TEST(GetHeapStatistics) {
13715 v8::HandleScope scope;
13716 LocalContext c1;
13717 v8::HeapStatistics heap_statistics;
Steve Blockd0582a62009-12-15 09:54:21 +000013718 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
13719 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
Steve Block3ce2e202009-11-05 08:53:23 +000013720 v8::V8::GetHeapStatistics(&heap_statistics);
Steve Blockd0582a62009-12-15 09:54:21 +000013721 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
13722 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
13723}
13724
13725
Ben Murdochc7cc0282012-03-05 14:35:55 +000013726class VisitorImpl : public v8::ExternalResourceVisitor {
13727 public:
13728 VisitorImpl(TestResource* r1, TestResource* r2)
13729 : resource1_(r1),
13730 resource2_(r2),
13731 found_resource1_(false),
13732 found_resource2_(false) {}
13733 virtual ~VisitorImpl() {}
13734 virtual void VisitExternalString(v8::Handle<v8::String> string) {
13735 if (!string->IsExternal()) {
13736 CHECK(string->IsExternalAscii());
13737 return;
13738 }
13739 v8::String::ExternalStringResource* resource =
13740 string->GetExternalStringResource();
13741 CHECK(resource);
13742 if (resource1_ == resource) {
13743 CHECK(!found_resource1_);
13744 found_resource1_ = true;
13745 }
13746 if (resource2_ == resource) {
13747 CHECK(!found_resource2_);
13748 found_resource2_ = true;
13749 }
13750 }
13751 void CheckVisitedResources() {
13752 CHECK(found_resource1_);
13753 CHECK(found_resource2_);
13754 }
13755
13756 private:
13757 v8::String::ExternalStringResource* resource1_;
13758 v8::String::ExternalStringResource* resource2_;
13759 bool found_resource1_;
13760 bool found_resource2_;
13761};
13762
13763TEST(VisitExternalStrings) {
13764 v8::HandleScope scope;
13765 LocalContext env;
13766 const char* string = "Some string";
13767 uint16_t* two_byte_string = AsciiToTwoByteString(string);
13768 TestResource* resource1 = new TestResource(two_byte_string);
13769 v8::Local<v8::String> string1 = v8::String::NewExternal(resource1);
13770 TestResource* resource2 = new TestResource(two_byte_string);
13771 v8::Local<v8::String> string2 = v8::String::NewExternal(resource2);
13772
13773 // We need to add usages for string1 and string2 to avoid warnings in GCC 4.7
13774 CHECK(string1->IsExternal());
13775 CHECK(string2->IsExternal());
13776
13777 VisitorImpl visitor(resource1, resource2);
13778 v8::V8::VisitExternalResources(&visitor);
13779 visitor.CheckVisitedResources();
13780}
13781
13782
Steve Blockd0582a62009-12-15 09:54:21 +000013783static double DoubleFromBits(uint64_t value) {
13784 double target;
Steve Blockd0582a62009-12-15 09:54:21 +000013785 memcpy(&target, &value, sizeof(target));
Steve Blockd0582a62009-12-15 09:54:21 +000013786 return target;
13787}
13788
13789
13790static uint64_t DoubleToBits(double value) {
13791 uint64_t target;
Steve Blockd0582a62009-12-15 09:54:21 +000013792 memcpy(&target, &value, sizeof(target));
Steve Blockd0582a62009-12-15 09:54:21 +000013793 return target;
13794}
13795
13796
13797static double DoubleToDateTime(double input) {
13798 double date_limit = 864e13;
13799 if (IsNaN(input) || input < -date_limit || input > date_limit) {
13800 return i::OS::nan_value();
13801 }
13802 return (input < 0) ? -(floor(-input)) : floor(input);
13803}
13804
13805// We don't have a consistent way to write 64-bit constants syntactically, so we
13806// split them into two 32-bit constants and combine them programmatically.
13807static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
13808 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
13809}
13810
13811
13812THREADED_TEST(QuietSignalingNaNs) {
13813 v8::HandleScope scope;
13814 LocalContext context;
13815 v8::TryCatch try_catch;
13816
13817 // Special double values.
13818 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
13819 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
13820 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
13821 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
13822 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
13823 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
13824 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
13825
13826 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
13827 // on either side of the epoch.
13828 double date_limit = 864e13;
13829
13830 double test_values[] = {
13831 snan,
13832 qnan,
13833 infinity,
13834 max_normal,
13835 date_limit + 1,
13836 date_limit,
13837 min_normal,
13838 max_denormal,
13839 min_denormal,
13840 0,
13841 -0,
13842 -min_denormal,
13843 -max_denormal,
13844 -min_normal,
13845 -date_limit,
13846 -date_limit - 1,
13847 -max_normal,
13848 -infinity,
13849 -qnan,
13850 -snan
13851 };
13852 int num_test_values = 20;
13853
13854 for (int i = 0; i < num_test_values; i++) {
13855 double test_value = test_values[i];
13856
13857 // Check that Number::New preserves non-NaNs and quiets SNaNs.
13858 v8::Handle<v8::Value> number = v8::Number::New(test_value);
13859 double stored_number = number->NumberValue();
13860 if (!IsNaN(test_value)) {
13861 CHECK_EQ(test_value, stored_number);
13862 } else {
13863 uint64_t stored_bits = DoubleToBits(stored_number);
13864 // Check if quiet nan (bits 51..62 all set).
Ben Murdoch592a9fc2012-03-05 11:04:45 +000013865#if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
13866 // Most significant fraction bit for quiet nan is set to 0
13867 // on MIPS architecture. Allowed by IEEE-754.
13868 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
13869#else
Steve Blockd0582a62009-12-15 09:54:21 +000013870 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
Ben Murdoch592a9fc2012-03-05 11:04:45 +000013871#endif
Steve Blockd0582a62009-12-15 09:54:21 +000013872 }
13873
13874 // Check that Date::New preserves non-NaNs in the date range and
13875 // quiets SNaNs.
13876 v8::Handle<v8::Value> date = v8::Date::New(test_value);
13877 double expected_stored_date = DoubleToDateTime(test_value);
13878 double stored_date = date->NumberValue();
13879 if (!IsNaN(expected_stored_date)) {
13880 CHECK_EQ(expected_stored_date, stored_date);
13881 } else {
13882 uint64_t stored_bits = DoubleToBits(stored_date);
13883 // Check if quiet nan (bits 51..62 all set).
Ben Murdoch592a9fc2012-03-05 11:04:45 +000013884#if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
13885 // Most significant fraction bit for quiet nan is set to 0
13886 // on MIPS architecture. Allowed by IEEE-754.
13887 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
13888#else
Steve Blockd0582a62009-12-15 09:54:21 +000013889 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
Ben Murdoch592a9fc2012-03-05 11:04:45 +000013890#endif
Steve Blockd0582a62009-12-15 09:54:21 +000013891 }
13892 }
13893}
13894
13895
13896static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
13897 v8::HandleScope scope;
13898 v8::TryCatch tc;
Ben Murdoch592a9fc2012-03-05 11:04:45 +000013899 v8::Handle<v8::String> str(args[0]->ToString());
Ben Murdochc7cc0282012-03-05 14:35:55 +000013900 USE(str);
Steve Blockd0582a62009-12-15 09:54:21 +000013901 if (tc.HasCaught())
13902 return tc.ReThrow();
13903 return v8::Undefined();
13904}
13905
13906
13907// Test that an exception can be propagated down through a spaghetti
13908// stack using ReThrow.
13909THREADED_TEST(SpaghettiStackReThrow) {
13910 v8::HandleScope scope;
13911 LocalContext context;
13912 context->Global()->Set(
13913 v8::String::New("s"),
13914 v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
13915 v8::TryCatch try_catch;
13916 CompileRun(
13917 "var i = 0;"
13918 "var o = {"
13919 " toString: function () {"
13920 " if (i == 10) {"
13921 " throw 'Hey!';"
13922 " } else {"
13923 " i++;"
13924 " return s(o);"
13925 " }"
13926 " }"
13927 "};"
13928 "s(o);");
13929 CHECK(try_catch.HasCaught());
13930 v8::String::Utf8Value value(try_catch.Exception());
13931 CHECK_EQ(0, strcmp(*value, "Hey!"));
13932}
13933
13934
Steve Blockd0582a62009-12-15 09:54:21 +000013935TEST(Regress528) {
13936 v8::V8::Initialize();
13937
13938 v8::HandleScope scope;
13939 v8::Persistent<Context> context;
13940 v8::Persistent<Context> other_context;
13941 int gc_count;
13942
13943 // Create a context used to keep the code from aging in the compilation
13944 // cache.
13945 other_context = Context::New();
13946
13947 // Context-dependent context data creates reference from the compilation
13948 // cache to the global object.
13949 const char* source_simple = "1";
13950 context = Context::New();
13951 {
13952 v8::HandleScope scope;
13953
13954 context->Enter();
13955 Local<v8::String> obj = v8::String::New("");
13956 context->SetData(obj);
13957 CompileRun(source_simple);
13958 context->Exit();
13959 }
13960 context.Dispose();
13961 for (gc_count = 1; gc_count < 10; gc_count++) {
13962 other_context->Enter();
13963 CompileRun(source_simple);
13964 other_context->Exit();
Ben Murdoch592a9fc2012-03-05 11:04:45 +000013965 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blockd0582a62009-12-15 09:54:21 +000013966 if (GetGlobalObjectsCount() == 1) break;
13967 }
13968 CHECK_GE(2, gc_count);
13969 CHECK_EQ(1, GetGlobalObjectsCount());
13970
13971 // Eval in a function creates reference from the compilation cache to the
13972 // global object.
13973 const char* source_eval = "function f(){eval('1')}; f()";
13974 context = Context::New();
13975 {
13976 v8::HandleScope scope;
13977
13978 context->Enter();
13979 CompileRun(source_eval);
13980 context->Exit();
13981 }
13982 context.Dispose();
13983 for (gc_count = 1; gc_count < 10; gc_count++) {
13984 other_context->Enter();
13985 CompileRun(source_eval);
13986 other_context->Exit();
Ben Murdoch592a9fc2012-03-05 11:04:45 +000013987 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blockd0582a62009-12-15 09:54:21 +000013988 if (GetGlobalObjectsCount() == 1) break;
13989 }
13990 CHECK_GE(2, gc_count);
13991 CHECK_EQ(1, GetGlobalObjectsCount());
13992
13993 // Looking up the line number for an exception creates reference from the
13994 // compilation cache to the global object.
13995 const char* source_exception = "function f(){throw 1;} f()";
13996 context = Context::New();
13997 {
13998 v8::HandleScope scope;
13999
14000 context->Enter();
14001 v8::TryCatch try_catch;
14002 CompileRun(source_exception);
14003 CHECK(try_catch.HasCaught());
14004 v8::Handle<v8::Message> message = try_catch.Message();
14005 CHECK(!message.IsEmpty());
14006 CHECK_EQ(1, message->GetLineNumber());
14007 context->Exit();
14008 }
14009 context.Dispose();
14010 for (gc_count = 1; gc_count < 10; gc_count++) {
14011 other_context->Enter();
14012 CompileRun(source_exception);
14013 other_context->Exit();
Ben Murdoch592a9fc2012-03-05 11:04:45 +000014014 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blockd0582a62009-12-15 09:54:21 +000014015 if (GetGlobalObjectsCount() == 1) break;
14016 }
14017 CHECK_GE(2, gc_count);
14018 CHECK_EQ(1, GetGlobalObjectsCount());
14019
14020 other_context.Dispose();
Steve Block3ce2e202009-11-05 08:53:23 +000014021}
Andrei Popescu402d9372010-02-26 13:31:12 +000014022
14023
14024THREADED_TEST(ScriptOrigin) {
14025 v8::HandleScope scope;
14026 LocalContext env;
14027 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
14028 v8::Handle<v8::String> script = v8::String::New(
14029 "function f() {}\n\nfunction g() {}");
14030 v8::Script::Compile(script, &origin)->Run();
14031 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
14032 env->Global()->Get(v8::String::New("f")));
14033 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
14034 env->Global()->Get(v8::String::New("g")));
14035
14036 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
14037 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
14038 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
14039
14040 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
14041 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
14042 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
14043}
14044
Ben Murdochc7cc0282012-03-05 14:35:55 +000014045THREADED_TEST(FunctionGetInferredName) {
14046 v8::HandleScope scope;
14047 LocalContext env;
14048 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
14049 v8::Handle<v8::String> script = v8::String::New(
14050 "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
14051 v8::Script::Compile(script, &origin)->Run();
14052 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
14053 env->Global()->Get(v8::String::New("f")));
14054 CHECK_EQ("foo.bar.baz", *v8::String::AsciiValue(f->GetInferredName()));
14055}
Andrei Popescu402d9372010-02-26 13:31:12 +000014056
14057THREADED_TEST(ScriptLineNumber) {
14058 v8::HandleScope scope;
14059 LocalContext env;
14060 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
14061 v8::Handle<v8::String> script = v8::String::New(
14062 "function f() {}\n\nfunction g() {}");
14063 v8::Script::Compile(script, &origin)->Run();
14064 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
14065 env->Global()->Get(v8::String::New("f")));
14066 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
14067 env->Global()->Get(v8::String::New("g")));
14068 CHECK_EQ(0, f->GetScriptLineNumber());
14069 CHECK_EQ(2, g->GetScriptLineNumber());
14070}
14071
14072
Ben Murdoch592a9fc2012-03-05 11:04:45 +000014073THREADED_TEST(ScriptColumnNumber) {
14074 v8::HandleScope scope;
14075 LocalContext env;
14076 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"),
14077 v8::Integer::New(3), v8::Integer::New(2));
14078 v8::Handle<v8::String> script = v8::String::New(
14079 "function foo() {}\n\n function bar() {}");
14080 v8::Script::Compile(script, &origin)->Run();
14081 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
14082 env->Global()->Get(v8::String::New("foo")));
14083 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
14084 env->Global()->Get(v8::String::New("bar")));
14085 CHECK_EQ(14, foo->GetScriptColumnNumber());
14086 CHECK_EQ(17, bar->GetScriptColumnNumber());
14087}
14088
14089
14090THREADED_TEST(FunctionGetScriptId) {
14091 v8::HandleScope scope;
14092 LocalContext env;
14093 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"),
14094 v8::Integer::New(3), v8::Integer::New(2));
14095 v8::Handle<v8::String> scriptSource = v8::String::New(
14096 "function foo() {}\n\n function bar() {}");
14097 v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
14098 script->Run();
14099 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
14100 env->Global()->Get(v8::String::New("foo")));
14101 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
14102 env->Global()->Get(v8::String::New("bar")));
14103 CHECK_EQ(script->Id(), foo->GetScriptId());
14104 CHECK_EQ(script->Id(), bar->GetScriptId());
14105}
14106
14107
Andrei Popescu402d9372010-02-26 13:31:12 +000014108static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
14109 const AccessorInfo& info) {
14110 return v8_num(42);
14111}
14112
14113
14114static void SetterWhichSetsYOnThisTo23(Local<String> name,
14115 Local<Value> value,
14116 const AccessorInfo& info) {
14117 info.This()->Set(v8_str("y"), v8_num(23));
14118}
14119
14120
Steve Block6ded16b2010-05-10 14:33:55 +010014121TEST(SetterOnConstructorPrototype) {
Andrei Popescu402d9372010-02-26 13:31:12 +000014122 v8::HandleScope scope;
14123 Local<ObjectTemplate> templ = ObjectTemplate::New();
14124 templ->SetAccessor(v8_str("x"),
14125 GetterWhichReturns42,
14126 SetterWhichSetsYOnThisTo23);
14127 LocalContext context;
14128 context->Global()->Set(v8_str("P"), templ->NewInstance());
14129 CompileRun("function C1() {"
14130 " this.x = 23;"
14131 "};"
14132 "C1.prototype = P;"
14133 "function C2() {"
14134 " this.x = 23"
14135 "};"
14136 "C2.prototype = { };"
14137 "C2.prototype.__proto__ = P;");
14138
14139 v8::Local<v8::Script> script;
14140 script = v8::Script::Compile(v8_str("new C1();"));
14141 for (int i = 0; i < 10; i++) {
14142 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
14143 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
14144 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
14145 }
14146
14147 script = v8::Script::Compile(v8_str("new C2();"));
14148 for (int i = 0; i < 10; i++) {
14149 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
14150 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
14151 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
14152 }
14153}
14154
14155
14156static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
14157 Local<String> name, const AccessorInfo& info) {
14158 return v8_num(42);
14159}
14160
14161
14162static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
14163 Local<String> name, Local<Value> value, const AccessorInfo& info) {
14164 if (name->Equals(v8_str("x"))) {
14165 info.This()->Set(v8_str("y"), v8_num(23));
14166 }
14167 return v8::Handle<Value>();
14168}
14169
14170
14171THREADED_TEST(InterceptorOnConstructorPrototype) {
14172 v8::HandleScope scope;
14173 Local<ObjectTemplate> templ = ObjectTemplate::New();
14174 templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
14175 NamedPropertySetterWhichSetsYOnThisTo23);
14176 LocalContext context;
14177 context->Global()->Set(v8_str("P"), templ->NewInstance());
14178 CompileRun("function C1() {"
14179 " this.x = 23;"
14180 "};"
14181 "C1.prototype = P;"
14182 "function C2() {"
14183 " this.x = 23"
14184 "};"
14185 "C2.prototype = { };"
14186 "C2.prototype.__proto__ = P;");
14187
14188 v8::Local<v8::Script> script;
14189 script = v8::Script::Compile(v8_str("new C1();"));
14190 for (int i = 0; i < 10; i++) {
14191 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
14192 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
14193 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
14194 }
14195
14196 script = v8::Script::Compile(v8_str("new C2();"));
14197 for (int i = 0; i < 10; i++) {
14198 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
14199 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
14200 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
14201 }
14202}
Steve Block6ded16b2010-05-10 14:33:55 +010014203
14204
14205TEST(Bug618) {
14206 const char* source = "function C1() {"
14207 " this.x = 23;"
14208 "};"
14209 "C1.prototype = P;";
14210
14211 v8::HandleScope scope;
14212 LocalContext context;
14213 v8::Local<v8::Script> script;
14214
14215 // Use a simple object as prototype.
14216 v8::Local<v8::Object> prototype = v8::Object::New();
14217 prototype->Set(v8_str("y"), v8_num(42));
14218 context->Global()->Set(v8_str("P"), prototype);
14219
14220 // This compile will add the code to the compilation cache.
14221 CompileRun(source);
14222
14223 script = v8::Script::Compile(v8_str("new C1();"));
Kristian Monsen0d5e1162010-09-30 15:31:59 +010014224 // Allow enough iterations for the inobject slack tracking logic
14225 // to finalize instance size and install the fast construct stub.
14226 for (int i = 0; i < 256; i++) {
Steve Block6ded16b2010-05-10 14:33:55 +010014227 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
14228 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
14229 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
14230 }
14231
14232 // Use an API object with accessors as prototype.
14233 Local<ObjectTemplate> templ = ObjectTemplate::New();
14234 templ->SetAccessor(v8_str("x"),
14235 GetterWhichReturns42,
14236 SetterWhichSetsYOnThisTo23);
14237 context->Global()->Set(v8_str("P"), templ->NewInstance());
14238
14239 // This compile will get the code from the compilation cache.
14240 CompileRun(source);
14241
14242 script = v8::Script::Compile(v8_str("new C1();"));
14243 for (int i = 0; i < 10; i++) {
14244 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
14245 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
14246 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
14247 }
14248}
14249
14250int prologue_call_count = 0;
14251int epilogue_call_count = 0;
14252int prologue_call_count_second = 0;
14253int epilogue_call_count_second = 0;
14254
14255void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
14256 ++prologue_call_count;
14257}
14258
14259void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
14260 ++epilogue_call_count;
14261}
14262
14263void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
14264 ++prologue_call_count_second;
14265}
14266
14267void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
14268 ++epilogue_call_count_second;
14269}
14270
14271TEST(GCCallbacks) {
14272 LocalContext context;
14273
14274 v8::V8::AddGCPrologueCallback(PrologueCallback);
14275 v8::V8::AddGCEpilogueCallback(EpilogueCallback);
14276 CHECK_EQ(0, prologue_call_count);
14277 CHECK_EQ(0, epilogue_call_count);
Ben Murdoch592a9fc2012-03-05 11:04:45 +000014278 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Block6ded16b2010-05-10 14:33:55 +010014279 CHECK_EQ(1, prologue_call_count);
14280 CHECK_EQ(1, epilogue_call_count);
14281 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
14282 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
Ben Murdoch592a9fc2012-03-05 11:04:45 +000014283 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Block6ded16b2010-05-10 14:33:55 +010014284 CHECK_EQ(2, prologue_call_count);
14285 CHECK_EQ(2, epilogue_call_count);
14286 CHECK_EQ(1, prologue_call_count_second);
14287 CHECK_EQ(1, epilogue_call_count_second);
14288 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
14289 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
Ben Murdoch592a9fc2012-03-05 11:04:45 +000014290 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Block6ded16b2010-05-10 14:33:55 +010014291 CHECK_EQ(2, prologue_call_count);
14292 CHECK_EQ(2, epilogue_call_count);
14293 CHECK_EQ(2, prologue_call_count_second);
14294 CHECK_EQ(2, epilogue_call_count_second);
14295 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
14296 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
Ben Murdoch592a9fc2012-03-05 11:04:45 +000014297 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Block6ded16b2010-05-10 14:33:55 +010014298 CHECK_EQ(2, prologue_call_count);
14299 CHECK_EQ(2, epilogue_call_count);
14300 CHECK_EQ(2, prologue_call_count_second);
14301 CHECK_EQ(2, epilogue_call_count_second);
14302}
Kristian Monsen25f61362010-05-21 11:50:48 +010014303
14304
14305THREADED_TEST(AddToJSFunctionResultCache) {
14306 i::FLAG_allow_natives_syntax = true;
14307 v8::HandleScope scope;
14308
14309 LocalContext context;
14310
14311 const char* code =
14312 "(function() {"
14313 " var key0 = 'a';"
14314 " var key1 = 'b';"
14315 " var r0 = %_GetFromCache(0, key0);"
14316 " var r1 = %_GetFromCache(0, key1);"
14317 " var r0_ = %_GetFromCache(0, key0);"
14318 " if (r0 !== r0_)"
14319 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
14320 " var r1_ = %_GetFromCache(0, key1);"
14321 " if (r1 !== r1_)"
14322 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
14323 " return 'PASSED';"
14324 "})()";
Steve Block44f0eee2011-05-26 01:26:41 +010014325 HEAP->ClearJSFunctionResultCaches();
Kristian Monsen25f61362010-05-21 11:50:48 +010014326 ExpectString(code, "PASSED");
14327}
14328
14329
14330static const int k0CacheSize = 16;
14331
14332THREADED_TEST(FillJSFunctionResultCache) {
14333 i::FLAG_allow_natives_syntax = true;
14334 v8::HandleScope scope;
14335
14336 LocalContext context;
14337
14338 const char* code =
14339 "(function() {"
14340 " var k = 'a';"
14341 " var r = %_GetFromCache(0, k);"
14342 " for (var i = 0; i < 16; i++) {"
14343 " %_GetFromCache(0, 'a' + i);"
14344 " };"
14345 " if (r === %_GetFromCache(0, k))"
14346 " return 'FAILED: k0CacheSize is too small';"
14347 " return 'PASSED';"
14348 "})()";
Steve Block44f0eee2011-05-26 01:26:41 +010014349 HEAP->ClearJSFunctionResultCaches();
Kristian Monsen25f61362010-05-21 11:50:48 +010014350 ExpectString(code, "PASSED");
14351}
14352
14353
14354THREADED_TEST(RoundRobinGetFromCache) {
14355 i::FLAG_allow_natives_syntax = true;
14356 v8::HandleScope scope;
14357
14358 LocalContext context;
14359
14360 const char* code =
14361 "(function() {"
14362 " var keys = [];"
14363 " for (var i = 0; i < 16; i++) keys.push(i);"
14364 " var values = [];"
14365 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
14366 " for (var i = 0; i < 16; i++) {"
14367 " var v = %_GetFromCache(0, keys[i]);"
Ben Murdochc7cc0282012-03-05 14:35:55 +000014368 " if (v.toString() !== values[i].toString())"
Kristian Monsen25f61362010-05-21 11:50:48 +010014369 " return 'Wrong value for ' + "
14370 " keys[i] + ': ' + v + ' vs. ' + values[i];"
14371 " };"
14372 " return 'PASSED';"
14373 "})()";
Steve Block44f0eee2011-05-26 01:26:41 +010014374 HEAP->ClearJSFunctionResultCaches();
Kristian Monsen25f61362010-05-21 11:50:48 +010014375 ExpectString(code, "PASSED");
14376}
14377
14378
14379THREADED_TEST(ReverseGetFromCache) {
14380 i::FLAG_allow_natives_syntax = true;
14381 v8::HandleScope scope;
14382
14383 LocalContext context;
14384
14385 const char* code =
14386 "(function() {"
14387 " var keys = [];"
14388 " for (var i = 0; i < 16; i++) keys.push(i);"
14389 " var values = [];"
14390 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
14391 " for (var i = 15; i >= 16; i--) {"
14392 " var v = %_GetFromCache(0, keys[i]);"
14393 " if (v !== values[i])"
14394 " return 'Wrong value for ' + "
14395 " keys[i] + ': ' + v + ' vs. ' + values[i];"
14396 " };"
14397 " return 'PASSED';"
14398 "})()";
Steve Block44f0eee2011-05-26 01:26:41 +010014399 HEAP->ClearJSFunctionResultCaches();
Kristian Monsen25f61362010-05-21 11:50:48 +010014400 ExpectString(code, "PASSED");
14401}
14402
14403
14404THREADED_TEST(TestEviction) {
14405 i::FLAG_allow_natives_syntax = true;
14406 v8::HandleScope scope;
14407
14408 LocalContext context;
14409
14410 const char* code =
14411 "(function() {"
14412 " for (var i = 0; i < 2*16; i++) {"
14413 " %_GetFromCache(0, 'a' + i);"
14414 " };"
14415 " return 'PASSED';"
14416 "})()";
Steve Block44f0eee2011-05-26 01:26:41 +010014417 HEAP->ClearJSFunctionResultCaches();
Kristian Monsen25f61362010-05-21 11:50:48 +010014418 ExpectString(code, "PASSED");
14419}
Steve Block8defd9f2010-07-08 12:39:36 +010014420
14421
14422THREADED_TEST(TwoByteStringInAsciiCons) {
14423 // See Chromium issue 47824.
14424 v8::HandleScope scope;
14425
14426 LocalContext context;
14427 const char* init_code =
14428 "var str1 = 'abelspendabel';"
14429 "var str2 = str1 + str1 + str1;"
14430 "str2;";
14431 Local<Value> result = CompileRun(init_code);
14432
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014433 Local<Value> indexof = CompileRun("str2.indexOf('els')");
14434 Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
14435
Steve Block8defd9f2010-07-08 12:39:36 +010014436 CHECK(result->IsString());
14437 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
14438 int length = string->length();
14439 CHECK(string->IsAsciiRepresentation());
14440
14441 FlattenString(string);
14442 i::Handle<i::String> flat_string = FlattenGetString(string);
14443
14444 CHECK(string->IsAsciiRepresentation());
14445 CHECK(flat_string->IsAsciiRepresentation());
14446
14447 // Create external resource.
14448 uint16_t* uc16_buffer = new uint16_t[length + 1];
14449
14450 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
14451 uc16_buffer[length] = 0;
14452
14453 TestResource resource(uc16_buffer);
14454
14455 flat_string->MakeExternal(&resource);
14456
14457 CHECK(flat_string->IsTwoByteRepresentation());
14458
14459 // At this point, we should have a Cons string which is flat and ASCII,
14460 // with a first half that is a two-byte string (although it only contains
14461 // ASCII characters). This is a valid sequence of steps, and it can happen
14462 // in real pages.
14463
14464 CHECK(string->IsAsciiRepresentation());
14465 i::ConsString* cons = i::ConsString::cast(*string);
14466 CHECK_EQ(0, cons->second()->length());
14467 CHECK(cons->first()->IsTwoByteRepresentation());
14468
14469 // Check that some string operations work.
14470
14471 // Atom RegExp.
14472 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
14473 CHECK_EQ(6, reresult->Int32Value());
14474
14475 // Nonatom RegExp.
14476 reresult = CompileRun("str2.match(/abe./g).length;");
14477 CHECK_EQ(6, reresult->Int32Value());
14478
14479 reresult = CompileRun("str2.search(/bel/g);");
14480 CHECK_EQ(1, reresult->Int32Value());
14481
14482 reresult = CompileRun("str2.search(/be./g);");
14483 CHECK_EQ(1, reresult->Int32Value());
14484
14485 ExpectTrue("/bel/g.test(str2);");
14486
14487 ExpectTrue("/be./g.test(str2);");
14488
14489 reresult = CompileRun("/bel/g.exec(str2);");
14490 CHECK(!reresult->IsNull());
14491
14492 reresult = CompileRun("/be./g.exec(str2);");
14493 CHECK(!reresult->IsNull());
14494
14495 ExpectString("str2.substring(2, 10);", "elspenda");
14496
14497 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
14498
14499 ExpectString("str2.charAt(2);", "e");
14500
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014501 ExpectObject("str2.indexOf('els');", indexof);
14502
14503 ExpectObject("str2.lastIndexOf('dab');", lastindexof);
14504
Steve Block8defd9f2010-07-08 12:39:36 +010014505 reresult = CompileRun("str2.charCodeAt(2);");
14506 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
14507}
Iain Merrick75681382010-08-19 15:07:18 +010014508
14509
14510// Failed access check callback that performs a GC on each invocation.
14511void FailedAccessCheckCallbackGC(Local<v8::Object> target,
14512 v8::AccessType type,
14513 Local<v8::Value> data) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +000014514 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Iain Merrick75681382010-08-19 15:07:18 +010014515}
14516
14517
14518TEST(GCInFailedAccessCheckCallback) {
14519 // Install a failed access check callback that performs a GC on each
14520 // invocation. Then force the callback to be called from va
14521
14522 v8::V8::Initialize();
14523 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
14524
14525 v8::HandleScope scope;
14526
14527 // Create an ObjectTemplate for global objects and install access
14528 // check callbacks that will block access.
14529 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
14530 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
14531 IndexedGetAccessBlocker,
14532 v8::Handle<v8::Value>(),
14533 false);
14534
14535 // Create a context and set an x property on it's global object.
14536 LocalContext context0(NULL, global_template);
14537 context0->Global()->Set(v8_str("x"), v8_num(42));
14538 v8::Handle<v8::Object> global0 = context0->Global();
14539
14540 // Create a context with a different security token so that the
14541 // failed access check callback will be called on each access.
14542 LocalContext context1(NULL, global_template);
14543 context1->Global()->Set(v8_str("other"), global0);
14544
14545 // Get property with failed access check.
14546 ExpectUndefined("other.x");
14547
14548 // Get element with failed access check.
14549 ExpectUndefined("other[0]");
14550
14551 // Set property with failed access check.
14552 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
14553 CHECK(result->IsObject());
14554
14555 // Set element with failed access check.
14556 result = CompileRun("other[0] = new Object()");
14557 CHECK(result->IsObject());
14558
14559 // Get property attribute with failed access check.
14560 ExpectFalse("\'x\' in other");
14561
14562 // Get property attribute for element with failed access check.
14563 ExpectFalse("0 in other");
14564
14565 // Delete property.
14566 ExpectFalse("delete other.x");
14567
14568 // Delete element.
14569 CHECK_EQ(false, global0->Delete(0));
14570
14571 // DefineAccessor.
14572 CHECK_EQ(false,
14573 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
14574
14575 // Define JavaScript accessor.
14576 ExpectUndefined("Object.prototype.__defineGetter__.call("
14577 " other, \'x\', function() { return 42; })");
14578
14579 // LookupAccessor.
14580 ExpectUndefined("Object.prototype.__lookupGetter__.call("
14581 " other, \'x\')");
14582
14583 // HasLocalElement.
14584 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
14585
14586 CHECK_EQ(false, global0->HasRealIndexedProperty(0));
14587 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
14588 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
14589
14590 // Reset the failed access check callback so it does not influence
14591 // the other tests.
14592 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
14593}
Kristian Monsen0d5e1162010-09-30 15:31:59 +010014594
Steve Block44f0eee2011-05-26 01:26:41 +010014595TEST(DefaultIsolateGetCurrent) {
14596 CHECK(v8::Isolate::GetCurrent() != NULL);
14597 v8::Isolate* isolate = v8::Isolate::GetCurrent();
14598 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
14599 printf("*** %s\n", "DefaultIsolateGetCurrent success");
14600}
14601
14602TEST(IsolateNewDispose) {
14603 v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
14604 v8::Isolate* isolate = v8::Isolate::New();
14605 CHECK(isolate != NULL);
14606 CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
14607 CHECK(current_isolate != isolate);
14608 CHECK(current_isolate == v8::Isolate::GetCurrent());
14609
14610 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14611 last_location = last_message = NULL;
14612 isolate->Dispose();
14613 CHECK_EQ(last_location, NULL);
14614 CHECK_EQ(last_message, NULL);
14615}
14616
14617TEST(IsolateEnterExitDefault) {
14618 v8::HandleScope scope;
14619 LocalContext context;
14620 v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
14621 CHECK(current_isolate != NULL); // Default isolate.
14622 ExpectString("'hello'", "hello");
14623 current_isolate->Enter();
14624 ExpectString("'still working'", "still working");
14625 current_isolate->Exit();
14626 ExpectString("'still working 2'", "still working 2");
14627 current_isolate->Exit();
14628 // Default isolate is always, well, 'default current'.
14629 CHECK_EQ(v8::Isolate::GetCurrent(), current_isolate);
14630 // Still working since default isolate is auto-entering any thread
14631 // that has no isolate and attempts to execute V8 APIs.
14632 ExpectString("'still working 3'", "still working 3");
14633}
14634
14635TEST(DisposeDefaultIsolate) {
14636 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14637
14638 // Run some V8 code to trigger default isolate to become 'current'.
14639 v8::HandleScope scope;
14640 LocalContext context;
14641 ExpectString("'run some V8'", "run some V8");
14642
14643 v8::Isolate* isolate = v8::Isolate::GetCurrent();
14644 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
14645 last_location = last_message = NULL;
14646 isolate->Dispose();
14647 // It is not possible to dispose default isolate via Isolate API.
14648 CHECK_NE(last_location, NULL);
14649 CHECK_NE(last_message, NULL);
14650}
14651
14652TEST(RunDefaultAndAnotherIsolate) {
14653 v8::HandleScope scope;
14654 LocalContext context;
14655
14656 // Enter new isolate.
14657 v8::Isolate* isolate = v8::Isolate::New();
14658 CHECK(isolate);
14659 isolate->Enter();
14660 { // Need this block because subsequent Exit() will deallocate Heap,
14661 // so we need all scope objects to be deconstructed when it happens.
14662 v8::HandleScope scope_new;
14663 LocalContext context_new;
14664
14665 // Run something in new isolate.
14666 CompileRun("var foo = 153;");
14667 ExpectTrue("function f() { return foo == 153; }; f()");
14668 }
14669 isolate->Exit();
14670
14671 // This runs automatically in default isolate.
14672 // Variables in another isolate should be not available.
14673 ExpectTrue("function f() {"
14674 " try {"
14675 " foo;"
14676 " return false;"
14677 " } catch(e) {"
14678 " return true;"
14679 " }"
14680 "};"
14681 "var bar = 371;"
14682 "f()");
14683
14684 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14685 last_location = last_message = NULL;
14686 isolate->Dispose();
14687 CHECK_EQ(last_location, NULL);
14688 CHECK_EQ(last_message, NULL);
14689
14690 // Check that default isolate still runs.
14691 ExpectTrue("function f() { return bar == 371; }; f()");
14692}
14693
14694TEST(DisposeIsolateWhenInUse) {
14695 v8::Isolate* isolate = v8::Isolate::New();
14696 CHECK(isolate);
14697 isolate->Enter();
14698 v8::HandleScope scope;
14699 LocalContext context;
14700 // Run something in this isolate.
14701 ExpectTrue("true");
14702 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14703 last_location = last_message = NULL;
14704 // Still entered, should fail.
14705 isolate->Dispose();
14706 CHECK_NE(last_location, NULL);
14707 CHECK_NE(last_message, NULL);
14708}
14709
14710TEST(RunTwoIsolatesOnSingleThread) {
14711 // Run isolate 1.
14712 v8::Isolate* isolate1 = v8::Isolate::New();
14713 isolate1->Enter();
14714 v8::Persistent<v8::Context> context1 = v8::Context::New();
14715
14716 {
14717 v8::Context::Scope cscope(context1);
14718 v8::HandleScope scope;
14719 // Run something in new isolate.
14720 CompileRun("var foo = 'isolate 1';");
14721 ExpectString("function f() { return foo; }; f()", "isolate 1");
14722 }
14723
14724 // Run isolate 2.
14725 v8::Isolate* isolate2 = v8::Isolate::New();
14726 v8::Persistent<v8::Context> context2;
14727
14728 {
14729 v8::Isolate::Scope iscope(isolate2);
14730 context2 = v8::Context::New();
14731 v8::Context::Scope cscope(context2);
14732 v8::HandleScope scope;
14733
14734 // Run something in new isolate.
14735 CompileRun("var foo = 'isolate 2';");
14736 ExpectString("function f() { return foo; }; f()", "isolate 2");
14737 }
14738
14739 {
14740 v8::Context::Scope cscope(context1);
14741 v8::HandleScope scope;
14742 // Now again in isolate 1
14743 ExpectString("function f() { return foo; }; f()", "isolate 1");
14744 }
14745
14746 isolate1->Exit();
14747
14748 // Run some stuff in default isolate.
14749 v8::Persistent<v8::Context> context_default = v8::Context::New();
14750
14751 {
14752 v8::Context::Scope cscope(context_default);
14753 v8::HandleScope scope;
14754 // Variables in other isolates should be not available, verify there
14755 // is an exception.
14756 ExpectTrue("function f() {"
14757 " try {"
14758 " foo;"
14759 " return false;"
14760 " } catch(e) {"
14761 " return true;"
14762 " }"
14763 "};"
14764 "var isDefaultIsolate = true;"
14765 "f()");
14766 }
14767
14768 isolate1->Enter();
14769
14770 {
14771 v8::Isolate::Scope iscope(isolate2);
14772 v8::Context::Scope cscope(context2);
14773 v8::HandleScope scope;
14774 ExpectString("function f() { return foo; }; f()", "isolate 2");
14775 }
14776
14777 {
14778 v8::Context::Scope cscope(context1);
14779 v8::HandleScope scope;
14780 ExpectString("function f() { return foo; }; f()", "isolate 1");
14781 }
14782
14783 {
14784 v8::Isolate::Scope iscope(isolate2);
14785 context2.Dispose();
14786 }
14787
14788 context1.Dispose();
14789 isolate1->Exit();
14790
14791 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14792 last_location = last_message = NULL;
14793
14794 isolate1->Dispose();
14795 CHECK_EQ(last_location, NULL);
14796 CHECK_EQ(last_message, NULL);
14797
14798 isolate2->Dispose();
14799 CHECK_EQ(last_location, NULL);
14800 CHECK_EQ(last_message, NULL);
14801
14802 // Check that default isolate still runs.
14803 {
14804 v8::Context::Scope cscope(context_default);
14805 v8::HandleScope scope;
14806 ExpectTrue("function f() { return isDefaultIsolate; }; f()");
14807 }
14808}
14809
14810static int CalcFibonacci(v8::Isolate* isolate, int limit) {
14811 v8::Isolate::Scope isolate_scope(isolate);
14812 v8::HandleScope scope;
14813 LocalContext context;
14814 i::ScopedVector<char> code(1024);
14815 i::OS::SNPrintF(code, "function fib(n) {"
14816 " if (n <= 2) return 1;"
14817 " return fib(n-1) + fib(n-2);"
14818 "}"
14819 "fib(%d)", limit);
14820 Local<Value> value = CompileRun(code.start());
14821 CHECK(value->IsNumber());
14822 return static_cast<int>(value->NumberValue());
14823}
14824
14825class IsolateThread : public v8::internal::Thread {
14826 public:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014827 IsolateThread(v8::Isolate* isolate, int fib_limit)
14828 : Thread("IsolateThread"),
Steve Block44f0eee2011-05-26 01:26:41 +010014829 isolate_(isolate),
14830 fib_limit_(fib_limit),
14831 result_(0) { }
14832
14833 void Run() {
14834 result_ = CalcFibonacci(isolate_, fib_limit_);
14835 }
14836
14837 int result() { return result_; }
14838
14839 private:
14840 v8::Isolate* isolate_;
14841 int fib_limit_;
14842 int result_;
14843};
14844
14845TEST(MultipleIsolatesOnIndividualThreads) {
14846 v8::Isolate* isolate1 = v8::Isolate::New();
14847 v8::Isolate* isolate2 = v8::Isolate::New();
14848
14849 IsolateThread thread1(isolate1, 21);
14850 IsolateThread thread2(isolate2, 12);
14851
14852 // Compute some fibonacci numbers on 3 threads in 3 isolates.
14853 thread1.Start();
14854 thread2.Start();
14855
14856 int result1 = CalcFibonacci(v8::Isolate::GetCurrent(), 21);
14857 int result2 = CalcFibonacci(v8::Isolate::GetCurrent(), 12);
14858
14859 thread1.Join();
14860 thread2.Join();
14861
14862 // Compare results. The actual fibonacci numbers for 12 and 21 are taken
14863 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
14864 CHECK_EQ(result1, 10946);
14865 CHECK_EQ(result2, 144);
14866 CHECK_EQ(result1, thread1.result());
14867 CHECK_EQ(result2, thread2.result());
14868
14869 isolate1->Dispose();
14870 isolate2->Dispose();
14871}
14872
Ben Murdoch257744e2011-11-30 15:57:28 +000014873TEST(IsolateDifferentContexts) {
14874 v8::Isolate* isolate = v8::Isolate::New();
14875 Persistent<v8::Context> context;
14876 {
14877 v8::Isolate::Scope isolate_scope(isolate);
14878 v8::HandleScope handle_scope;
14879 context = v8::Context::New();
14880 v8::Context::Scope context_scope(context);
14881 Local<Value> v = CompileRun("2");
14882 CHECK(v->IsNumber());
14883 CHECK_EQ(2, static_cast<int>(v->NumberValue()));
14884 }
14885 {
14886 v8::Isolate::Scope isolate_scope(isolate);
14887 v8::HandleScope handle_scope;
14888 context = v8::Context::New();
14889 v8::Context::Scope context_scope(context);
14890 Local<Value> v = CompileRun("22");
14891 CHECK(v->IsNumber());
14892 CHECK_EQ(22, static_cast<int>(v->NumberValue()));
14893 }
14894}
Steve Block44f0eee2011-05-26 01:26:41 +010014895
14896class InitDefaultIsolateThread : public v8::internal::Thread {
14897 public:
14898 enum TestCase {
14899 IgnoreOOM,
14900 SetResourceConstraints,
14901 SetFatalHandler,
14902 SetCounterFunction,
14903 SetCreateHistogramFunction,
14904 SetAddHistogramSampleFunction
14905 };
14906
14907 explicit InitDefaultIsolateThread(TestCase testCase)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014908 : Thread("InitDefaultIsolateThread"),
Steve Block44f0eee2011-05-26 01:26:41 +010014909 testCase_(testCase),
14910 result_(false) { }
14911
14912 void Run() {
14913 switch (testCase_) {
14914 case IgnoreOOM:
14915 v8::V8::IgnoreOutOfMemoryException();
14916 break;
14917
14918 case SetResourceConstraints: {
14919 static const int K = 1024;
14920 v8::ResourceConstraints constraints;
14921 constraints.set_max_young_space_size(256 * K);
14922 constraints.set_max_old_space_size(4 * K * K);
14923 v8::SetResourceConstraints(&constraints);
14924 break;
14925 }
14926
14927 case SetFatalHandler:
14928 v8::V8::SetFatalErrorHandler(NULL);
14929 break;
14930
14931 case SetCounterFunction:
14932 v8::V8::SetCounterFunction(NULL);
14933 break;
14934
14935 case SetCreateHistogramFunction:
14936 v8::V8::SetCreateHistogramFunction(NULL);
14937 break;
14938
14939 case SetAddHistogramSampleFunction:
14940 v8::V8::SetAddHistogramSampleFunction(NULL);
14941 break;
14942 }
14943 result_ = true;
14944 }
14945
14946 bool result() { return result_; }
14947
14948 private:
14949 TestCase testCase_;
14950 bool result_;
14951};
14952
14953
14954static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
14955 InitDefaultIsolateThread thread(testCase);
14956 thread.Start();
14957 thread.Join();
14958 CHECK_EQ(thread.result(), true);
14959}
14960
14961TEST(InitializeDefaultIsolateOnSecondaryThread1) {
14962 InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM);
14963}
14964
14965TEST(InitializeDefaultIsolateOnSecondaryThread2) {
14966 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
14967}
14968
14969TEST(InitializeDefaultIsolateOnSecondaryThread3) {
14970 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
14971}
14972
14973TEST(InitializeDefaultIsolateOnSecondaryThread4) {
14974 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
14975}
14976
14977TEST(InitializeDefaultIsolateOnSecondaryThread5) {
14978 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
14979}
14980
14981TEST(InitializeDefaultIsolateOnSecondaryThread6) {
14982 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
14983}
14984
Kristian Monsen0d5e1162010-09-30 15:31:59 +010014985
14986TEST(StringCheckMultipleContexts) {
14987 const char* code =
14988 "(function() { return \"a\".charAt(0); })()";
14989
14990 {
14991 // Run the code twice in the first context to initialize the call IC.
14992 v8::HandleScope scope;
14993 LocalContext context1;
14994 ExpectString(code, "a");
14995 ExpectString(code, "a");
14996 }
14997
14998 {
14999 // Change the String.prototype in the second context and check
15000 // that the right function gets called.
15001 v8::HandleScope scope;
15002 LocalContext context2;
15003 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
15004 ExpectString(code, "not a");
15005 }
15006}
15007
15008
15009TEST(NumberCheckMultipleContexts) {
15010 const char* code =
15011 "(function() { return (42).toString(); })()";
15012
15013 {
15014 // Run the code twice in the first context to initialize the call IC.
15015 v8::HandleScope scope;
15016 LocalContext context1;
15017 ExpectString(code, "42");
15018 ExpectString(code, "42");
15019 }
15020
15021 {
15022 // Change the Number.prototype in the second context and check
15023 // that the right function gets called.
15024 v8::HandleScope scope;
15025 LocalContext context2;
15026 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
15027 ExpectString(code, "not 42");
15028 }
15029}
15030
15031
15032TEST(BooleanCheckMultipleContexts) {
15033 const char* code =
15034 "(function() { return true.toString(); })()";
15035
15036 {
15037 // Run the code twice in the first context to initialize the call IC.
15038 v8::HandleScope scope;
15039 LocalContext context1;
15040 ExpectString(code, "true");
15041 ExpectString(code, "true");
15042 }
15043
15044 {
15045 // Change the Boolean.prototype in the second context and check
15046 // that the right function gets called.
15047 v8::HandleScope scope;
15048 LocalContext context2;
15049 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
15050 ExpectString(code, "");
15051 }
15052}
Ben Murdochf87a2032010-10-22 12:50:53 +010015053
15054
15055TEST(DontDeleteCellLoadIC) {
15056 const char* function_code =
15057 "function readCell() { while (true) { return cell; } }";
15058
15059 {
15060 // Run the code twice in the first context to initialize the load
15061 // IC for a don't delete cell.
15062 v8::HandleScope scope;
15063 LocalContext context1;
15064 CompileRun("var cell = \"first\";");
15065 ExpectBoolean("delete cell", false);
15066 CompileRun(function_code);
15067 ExpectString("readCell()", "first");
15068 ExpectString("readCell()", "first");
15069 }
15070
15071 {
15072 // Use a deletable cell in the second context.
15073 v8::HandleScope scope;
15074 LocalContext context2;
15075 CompileRun("cell = \"second\";");
15076 CompileRun(function_code);
15077 ExpectString("readCell()", "second");
15078 ExpectBoolean("delete cell", true);
15079 ExpectString("(function() {"
15080 " try {"
15081 " return readCell();"
15082 " } catch(e) {"
15083 " return e.toString();"
15084 " }"
15085 "})()",
15086 "ReferenceError: cell is not defined");
15087 CompileRun("cell = \"new_second\";");
Ben Murdoch592a9fc2012-03-05 11:04:45 +000015088 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
Ben Murdochf87a2032010-10-22 12:50:53 +010015089 ExpectString("readCell()", "new_second");
15090 ExpectString("readCell()", "new_second");
15091 }
15092}
15093
15094
15095TEST(DontDeleteCellLoadICForceDelete) {
15096 const char* function_code =
15097 "function readCell() { while (true) { return cell; } }";
15098
15099 // Run the code twice to initialize the load IC for a don't delete
15100 // cell.
15101 v8::HandleScope scope;
15102 LocalContext context;
15103 CompileRun("var cell = \"value\";");
15104 ExpectBoolean("delete cell", false);
15105 CompileRun(function_code);
15106 ExpectString("readCell()", "value");
15107 ExpectString("readCell()", "value");
15108
15109 // Delete the cell using the API and check the inlined code works
15110 // correctly.
15111 CHECK(context->Global()->ForceDelete(v8_str("cell")));
15112 ExpectString("(function() {"
15113 " try {"
15114 " return readCell();"
15115 " } catch(e) {"
15116 " return e.toString();"
15117 " }"
15118 "})()",
15119 "ReferenceError: cell is not defined");
15120}
15121
15122
15123TEST(DontDeleteCellLoadICAPI) {
15124 const char* function_code =
15125 "function readCell() { while (true) { return cell; } }";
15126
15127 // Run the code twice to initialize the load IC for a don't delete
15128 // cell created using the API.
15129 v8::HandleScope scope;
15130 LocalContext context;
15131 context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
15132 ExpectBoolean("delete cell", false);
15133 CompileRun(function_code);
15134 ExpectString("readCell()", "value");
15135 ExpectString("readCell()", "value");
15136
15137 // Delete the cell using the API and check the inlined code works
15138 // correctly.
15139 CHECK(context->Global()->ForceDelete(v8_str("cell")));
15140 ExpectString("(function() {"
15141 " try {"
15142 " return readCell();"
15143 " } catch(e) {"
15144 " return e.toString();"
15145 " }"
15146 "})()",
15147 "ReferenceError: cell is not defined");
15148}
15149
15150
Ben Murdochf87a2032010-10-22 12:50:53 +010015151TEST(RegExp) {
15152 v8::HandleScope scope;
15153 LocalContext context;
15154
15155 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
15156 CHECK(re->IsRegExp());
15157 CHECK(re->GetSource()->Equals(v8_str("foo")));
Ben Murdoch69a99ed2011-11-30 16:03:39 +000015158 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
Ben Murdochf87a2032010-10-22 12:50:53 +010015159
15160 re = v8::RegExp::New(v8_str("bar"),
15161 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
15162 v8::RegExp::kGlobal));
15163 CHECK(re->IsRegExp());
15164 CHECK(re->GetSource()->Equals(v8_str("bar")));
Ben Murdoch69a99ed2011-11-30 16:03:39 +000015165 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
15166 static_cast<int>(re->GetFlags()));
Ben Murdochf87a2032010-10-22 12:50:53 +010015167
15168 re = v8::RegExp::New(v8_str("baz"),
15169 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
15170 v8::RegExp::kMultiline));
15171 CHECK(re->IsRegExp());
15172 CHECK(re->GetSource()->Equals(v8_str("baz")));
Ben Murdoch69a99ed2011-11-30 16:03:39 +000015173 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
15174 static_cast<int>(re->GetFlags()));
Ben Murdochf87a2032010-10-22 12:50:53 +010015175
15176 re = CompileRun("/quux/").As<v8::RegExp>();
15177 CHECK(re->IsRegExp());
15178 CHECK(re->GetSource()->Equals(v8_str("quux")));
Ben Murdoch69a99ed2011-11-30 16:03:39 +000015179 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
Ben Murdochf87a2032010-10-22 12:50:53 +010015180
15181 re = CompileRun("/quux/gm").As<v8::RegExp>();
15182 CHECK(re->IsRegExp());
15183 CHECK(re->GetSource()->Equals(v8_str("quux")));
Ben Murdoch69a99ed2011-11-30 16:03:39 +000015184 CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
15185 static_cast<int>(re->GetFlags()));
Ben Murdochf87a2032010-10-22 12:50:53 +010015186
15187 // Override the RegExp constructor and check the API constructor
15188 // still works.
15189 CompileRun("RegExp = function() {}");
15190
15191 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
15192 CHECK(re->IsRegExp());
15193 CHECK(re->GetSource()->Equals(v8_str("foobar")));
Ben Murdoch69a99ed2011-11-30 16:03:39 +000015194 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
Ben Murdochf87a2032010-10-22 12:50:53 +010015195
15196 re = v8::RegExp::New(v8_str("foobarbaz"),
15197 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
15198 v8::RegExp::kMultiline));
15199 CHECK(re->IsRegExp());
15200 CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
Ben Murdoch69a99ed2011-11-30 16:03:39 +000015201 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
15202 static_cast<int>(re->GetFlags()));
Ben Murdochf87a2032010-10-22 12:50:53 +010015203
15204 context->Global()->Set(v8_str("re"), re);
15205 ExpectTrue("re.test('FoobarbaZ')");
15206
Ben Murdoch257744e2011-11-30 15:57:28 +000015207 // RegExps are objects on which you can set properties.
15208 re->Set(v8_str("property"), v8::Integer::New(32));
Ben Murdoch592a9fc2012-03-05 11:04:45 +000015209 v8::Handle<v8::Value> value(CompileRun("re.property"));
Ben Murdochc7cc0282012-03-05 14:35:55 +000015210 CHECK_EQ(32, value->Int32Value());
Ben Murdoch257744e2011-11-30 15:57:28 +000015211
Ben Murdochf87a2032010-10-22 12:50:53 +010015212 v8::TryCatch try_catch;
15213 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
15214 CHECK(re.IsEmpty());
15215 CHECK(try_catch.HasCaught());
15216 context->Global()->Set(v8_str("ex"), try_catch.Exception());
15217 ExpectTrue("ex instanceof SyntaxError");
15218}
15219
15220
Steve Block1e0659c2011-05-24 12:43:12 +010015221THREADED_TEST(Equals) {
15222 v8::HandleScope handleScope;
15223 LocalContext localContext;
15224
15225 v8::Handle<v8::Object> globalProxy = localContext->Global();
15226 v8::Handle<Value> global = globalProxy->GetPrototype();
15227
15228 CHECK(global->StrictEquals(global));
15229 CHECK(!global->StrictEquals(globalProxy));
15230 CHECK(!globalProxy->StrictEquals(global));
15231 CHECK(globalProxy->StrictEquals(globalProxy));
15232
15233 CHECK(global->Equals(global));
15234 CHECK(!global->Equals(globalProxy));
15235 CHECK(!globalProxy->Equals(global));
15236 CHECK(globalProxy->Equals(globalProxy));
15237}
15238
15239
Ben Murdochf87a2032010-10-22 12:50:53 +010015240static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
15241 const v8::AccessorInfo& info ) {
15242 return v8_str("42!");
15243}
15244
15245
15246static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo& info) {
15247 v8::Handle<v8::Array> result = v8::Array::New();
15248 result->Set(0, v8_str("universalAnswer"));
15249 return result;
15250}
15251
15252
15253TEST(NamedEnumeratorAndForIn) {
15254 v8::HandleScope handle_scope;
15255 LocalContext context;
15256 v8::Context::Scope context_scope(context.local());
15257
15258 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New();
15259 tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
15260 context->Global()->Set(v8_str("o"), tmpl->NewInstance());
15261 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
15262 "var result = []; for (var k in o) result.push(k); result"));
15263 CHECK_EQ(1, result->Length());
15264 CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
15265}
Steve Block1e0659c2011-05-24 12:43:12 +010015266
15267
15268TEST(DefinePropertyPostDetach) {
15269 v8::HandleScope scope;
15270 LocalContext context;
15271 v8::Handle<v8::Object> proxy = context->Global();
15272 v8::Handle<v8::Function> define_property =
15273 CompileRun("(function() {"
15274 " Object.defineProperty("
15275 " this,"
15276 " 1,"
15277 " { configurable: true, enumerable: true, value: 3 });"
15278 "})").As<Function>();
15279 context->DetachGlobal();
15280 define_property->Call(proxy, 0, NULL);
15281}
Ben Murdoch8b112d22011-06-08 16:22:53 +010015282
15283
15284static void InstallContextId(v8::Handle<Context> context, int id) {
15285 Context::Scope scope(context);
15286 CompileRun("Object.prototype").As<Object>()->
15287 Set(v8_str("context_id"), v8::Integer::New(id));
15288}
15289
15290
15291static void CheckContextId(v8::Handle<Object> object, int expected) {
15292 CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
15293}
15294
15295
15296THREADED_TEST(CreationContext) {
15297 HandleScope handle_scope;
15298 Persistent<Context> context1 = Context::New();
15299 InstallContextId(context1, 1);
15300 Persistent<Context> context2 = Context::New();
15301 InstallContextId(context2, 2);
15302 Persistent<Context> context3 = Context::New();
15303 InstallContextId(context3, 3);
15304
15305 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New();
15306
15307 Local<Object> object1;
15308 Local<Function> func1;
15309 {
15310 Context::Scope scope(context1);
15311 object1 = Object::New();
15312 func1 = tmpl->GetFunction();
15313 }
15314
15315 Local<Object> object2;
15316 Local<Function> func2;
15317 {
15318 Context::Scope scope(context2);
15319 object2 = Object::New();
15320 func2 = tmpl->GetFunction();
15321 }
15322
15323 Local<Object> instance1;
15324 Local<Object> instance2;
15325
15326 {
15327 Context::Scope scope(context3);
15328 instance1 = func1->NewInstance();
15329 instance2 = func2->NewInstance();
15330 }
15331
15332 CHECK(object1->CreationContext() == context1);
15333 CheckContextId(object1, 1);
15334 CHECK(func1->CreationContext() == context1);
15335 CheckContextId(func1, 1);
15336 CHECK(instance1->CreationContext() == context1);
15337 CheckContextId(instance1, 1);
15338 CHECK(object2->CreationContext() == context2);
15339 CheckContextId(object2, 2);
15340 CHECK(func2->CreationContext() == context2);
15341 CheckContextId(func2, 2);
15342 CHECK(instance2->CreationContext() == context2);
15343 CheckContextId(instance2, 2);
15344
15345 {
15346 Context::Scope scope(context1);
15347 CHECK(object1->CreationContext() == context1);
15348 CheckContextId(object1, 1);
15349 CHECK(func1->CreationContext() == context1);
15350 CheckContextId(func1, 1);
15351 CHECK(instance1->CreationContext() == context1);
15352 CheckContextId(instance1, 1);
15353 CHECK(object2->CreationContext() == context2);
15354 CheckContextId(object2, 2);
15355 CHECK(func2->CreationContext() == context2);
15356 CheckContextId(func2, 2);
15357 CHECK(instance2->CreationContext() == context2);
15358 CheckContextId(instance2, 2);
15359 }
15360
15361 {
15362 Context::Scope scope(context2);
15363 CHECK(object1->CreationContext() == context1);
15364 CheckContextId(object1, 1);
15365 CHECK(func1->CreationContext() == context1);
15366 CheckContextId(func1, 1);
15367 CHECK(instance1->CreationContext() == context1);
15368 CheckContextId(instance1, 1);
15369 CHECK(object2->CreationContext() == context2);
15370 CheckContextId(object2, 2);
15371 CHECK(func2->CreationContext() == context2);
15372 CheckContextId(func2, 2);
15373 CHECK(instance2->CreationContext() == context2);
15374 CheckContextId(instance2, 2);
15375 }
15376
15377 context1.Dispose();
15378 context2.Dispose();
15379 context3.Dispose();
15380}
Ben Murdoch257744e2011-11-30 15:57:28 +000015381
15382
Ben Murdoch69a99ed2011-11-30 16:03:39 +000015383THREADED_TEST(CreationContextOfJsFunction) {
15384 HandleScope handle_scope;
15385 Persistent<Context> context = Context::New();
15386 InstallContextId(context, 1);
15387
15388 Local<Object> function;
15389 {
15390 Context::Scope scope(context);
15391 function = CompileRun("function foo() {}; foo").As<Object>();
15392 }
15393
15394 CHECK(function->CreationContext() == context);
15395 CheckContextId(function, 1);
15396
15397 context.Dispose();
15398}
15399
15400
Ben Murdoch257744e2011-11-30 15:57:28 +000015401Handle<Value> HasOwnPropertyIndexedPropertyGetter(uint32_t index,
15402 const AccessorInfo& info) {
15403 if (index == 42) return v8_str("yes");
15404 return Handle<v8::Integer>();
15405}
15406
15407
15408Handle<Value> HasOwnPropertyNamedPropertyGetter(Local<String> property,
15409 const AccessorInfo& info) {
15410 if (property->Equals(v8_str("foo"))) return v8_str("yes");
15411 return Handle<Value>();
15412}
15413
15414
15415Handle<v8::Integer> HasOwnPropertyIndexedPropertyQuery(
15416 uint32_t index, const AccessorInfo& info) {
15417 if (index == 42) return v8_num(1).As<v8::Integer>();
15418 return Handle<v8::Integer>();
15419}
15420
15421
15422Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery(
15423 Local<String> property, const AccessorInfo& info) {
15424 if (property->Equals(v8_str("foo"))) return v8_num(1).As<v8::Integer>();
15425 return Handle<v8::Integer>();
15426}
15427
15428
15429Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery2(
15430 Local<String> property, const AccessorInfo& info) {
15431 if (property->Equals(v8_str("bar"))) return v8_num(1).As<v8::Integer>();
15432 return Handle<v8::Integer>();
15433}
15434
15435
15436Handle<Value> HasOwnPropertyAccessorGetter(Local<String> property,
15437 const AccessorInfo& info) {
15438 return v8_str("yes");
15439}
15440
15441
15442TEST(HasOwnProperty) {
15443 v8::HandleScope scope;
15444 LocalContext env;
15445 { // Check normal properties and defined getters.
15446 Handle<Value> value = CompileRun(
15447 "function Foo() {"
15448 " this.foo = 11;"
15449 " this.__defineGetter__('baz', function() { return 1; });"
15450 "};"
15451 "function Bar() { "
15452 " this.bar = 13;"
15453 " this.__defineGetter__('bla', function() { return 2; });"
15454 "};"
15455 "Bar.prototype = new Foo();"
15456 "new Bar();");
15457 CHECK(value->IsObject());
15458 Handle<Object> object = value->ToObject();
15459 CHECK(object->Has(v8_str("foo")));
15460 CHECK(!object->HasOwnProperty(v8_str("foo")));
15461 CHECK(object->HasOwnProperty(v8_str("bar")));
15462 CHECK(object->Has(v8_str("baz")));
15463 CHECK(!object->HasOwnProperty(v8_str("baz")));
15464 CHECK(object->HasOwnProperty(v8_str("bla")));
15465 }
15466 { // Check named getter interceptors.
15467 Handle<ObjectTemplate> templ = ObjectTemplate::New();
15468 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
15469 Handle<Object> instance = templ->NewInstance();
15470 CHECK(!instance->HasOwnProperty(v8_str("42")));
15471 CHECK(instance->HasOwnProperty(v8_str("foo")));
15472 CHECK(!instance->HasOwnProperty(v8_str("bar")));
15473 }
15474 { // Check indexed getter interceptors.
15475 Handle<ObjectTemplate> templ = ObjectTemplate::New();
15476 templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
15477 Handle<Object> instance = templ->NewInstance();
15478 CHECK(instance->HasOwnProperty(v8_str("42")));
15479 CHECK(!instance->HasOwnProperty(v8_str("43")));
15480 CHECK(!instance->HasOwnProperty(v8_str("foo")));
15481 }
15482 { // Check named query interceptors.
15483 Handle<ObjectTemplate> templ = ObjectTemplate::New();
15484 templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
15485 Handle<Object> instance = templ->NewInstance();
15486 CHECK(instance->HasOwnProperty(v8_str("foo")));
15487 CHECK(!instance->HasOwnProperty(v8_str("bar")));
15488 }
15489 { // Check indexed query interceptors.
15490 Handle<ObjectTemplate> templ = ObjectTemplate::New();
15491 templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
15492 Handle<Object> instance = templ->NewInstance();
15493 CHECK(instance->HasOwnProperty(v8_str("42")));
15494 CHECK(!instance->HasOwnProperty(v8_str("41")));
15495 }
15496 { // Check callbacks.
15497 Handle<ObjectTemplate> templ = ObjectTemplate::New();
15498 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
15499 Handle<Object> instance = templ->NewInstance();
15500 CHECK(instance->HasOwnProperty(v8_str("foo")));
15501 CHECK(!instance->HasOwnProperty(v8_str("bar")));
15502 }
15503 { // Check that query wins on disagreement.
15504 Handle<ObjectTemplate> templ = ObjectTemplate::New();
15505 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
15506 0,
15507 HasOwnPropertyNamedPropertyQuery2);
15508 Handle<Object> instance = templ->NewInstance();
15509 CHECK(!instance->HasOwnProperty(v8_str("foo")));
15510 CHECK(instance->HasOwnProperty(v8_str("bar")));
15511 }
15512}
15513
15514
15515void CheckCodeGenerationAllowed() {
15516 Handle<Value> result = CompileRun("eval('42')");
15517 CHECK_EQ(42, result->Int32Value());
15518 result = CompileRun("(function(e) { return e('42'); })(eval)");
15519 CHECK_EQ(42, result->Int32Value());
15520 result = CompileRun("var f = new Function('return 42'); f()");
15521 CHECK_EQ(42, result->Int32Value());
15522}
15523
15524
15525void CheckCodeGenerationDisallowed() {
15526 TryCatch try_catch;
15527
15528 Handle<Value> result = CompileRun("eval('42')");
15529 CHECK(result.IsEmpty());
15530 CHECK(try_catch.HasCaught());
15531 try_catch.Reset();
15532
15533 result = CompileRun("(function(e) { return e('42'); })(eval)");
15534 CHECK(result.IsEmpty());
15535 CHECK(try_catch.HasCaught());
15536 try_catch.Reset();
15537
15538 result = CompileRun("var f = new Function('return 42'); f()");
15539 CHECK(result.IsEmpty());
15540 CHECK(try_catch.HasCaught());
15541}
15542
15543
15544bool CodeGenerationAllowed(Local<Context> context) {
15545 ApiTestFuzzer::Fuzz();
15546 return true;
15547}
15548
15549
15550bool CodeGenerationDisallowed(Local<Context> context) {
15551 ApiTestFuzzer::Fuzz();
15552 return false;
15553}
15554
15555
15556THREADED_TEST(AllowCodeGenFromStrings) {
15557 v8::HandleScope scope;
15558 LocalContext context;
15559
15560 // eval and the Function constructor allowed by default.
15561 CheckCodeGenerationAllowed();
15562
15563 // Disallow eval and the Function constructor.
15564 context->AllowCodeGenerationFromStrings(false);
15565 CheckCodeGenerationDisallowed();
15566
15567 // Allow again.
15568 context->AllowCodeGenerationFromStrings(true);
15569 CheckCodeGenerationAllowed();
15570
15571 // Disallow but setting a global callback that will allow the calls.
15572 context->AllowCodeGenerationFromStrings(false);
15573 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
15574 CheckCodeGenerationAllowed();
15575
15576 // Set a callback that disallows the code generation.
15577 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
15578 CheckCodeGenerationDisallowed();
15579}
15580
15581
15582static v8::Handle<Value> NonObjectThis(const v8::Arguments& args) {
15583 return v8::Undefined();
15584}
15585
15586
15587THREADED_TEST(CallAPIFunctionOnNonObject) {
15588 v8::HandleScope scope;
15589 LocalContext context;
15590 Handle<FunctionTemplate> templ = v8::FunctionTemplate::New(NonObjectThis);
15591 Handle<Function> function = templ->GetFunction();
15592 context->Global()->Set(v8_str("f"), function);
15593 TryCatch try_catch;
15594 CompileRun("f.call(2)");
15595}
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015596
15597
15598// Regression test for issue 1470.
15599THREADED_TEST(ReadOnlyIndexedProperties) {
15600 v8::HandleScope scope;
15601 Local<ObjectTemplate> templ = ObjectTemplate::New();
15602
15603 LocalContext context;
15604 Local<v8::Object> obj = templ->NewInstance();
15605 context->Global()->Set(v8_str("obj"), obj);
15606 obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
15607 obj->Set(v8_str("1"), v8_str("foobar"));
15608 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
15609 obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
15610 obj->Set(v8_num(2), v8_str("foobar"));
15611 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
15612
15613 // Test non-smi case.
15614 obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
15615 obj->Set(v8_str("2000000000"), v8_str("foobar"));
15616 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
15617}
15618
15619
15620THREADED_TEST(Regress1516) {
15621 v8::HandleScope scope;
15622
15623 LocalContext context;
15624 { v8::HandleScope temp_scope;
15625 CompileRun("({'a': 0})");
15626 }
15627
15628 int elements;
15629 { i::MapCache* map_cache =
15630 i::MapCache::cast(i::Isolate::Current()->context()->map_cache());
15631 elements = map_cache->NumberOfElements();
15632 CHECK_LE(1, elements);
15633 }
15634
15635 i::Isolate::Current()->heap()->CollectAllGarbage(true);
15636 { i::Object* raw_map_cache = i::Isolate::Current()->context()->map_cache();
15637 if (raw_map_cache != i::Isolate::Current()->heap()->undefined_value()) {
15638 i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
15639 CHECK_GT(elements, map_cache->NumberOfElements());
15640 }
15641 }
15642}
15643
15644
15645static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
15646 Local<Value> name,
15647 v8::AccessType type,
15648 Local<Value> data) {
15649 // Only block read access to __proto__.
15650 if (type == v8::ACCESS_GET &&
15651 name->IsString() &&
15652 name->ToString()->Length() == 9 &&
15653 name->ToString()->Utf8Length() == 9) {
15654 char buffer[10];
15655 CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
15656 return strncmp(buffer, "__proto__", 9) != 0;
15657 }
15658
15659 return true;
15660}
15661
15662
15663THREADED_TEST(Regress93759) {
15664 HandleScope scope;
15665
15666 // Template for object with security check.
15667 Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New();
15668 // We don't do indexing, so any callback can be used for that.
15669 no_proto_template->SetAccessCheckCallbacks(
15670 BlockProtoNamedSecurityTestCallback,
15671 IndexedSecurityTestCallback);
15672
15673 // Templates for objects with hidden prototypes and possibly security check.
15674 Local<FunctionTemplate> hidden_proto_template = v8::FunctionTemplate::New();
15675 hidden_proto_template->SetHiddenPrototype(true);
15676
15677 Local<FunctionTemplate> protected_hidden_proto_template =
15678 v8::FunctionTemplate::New();
15679 protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
15680 BlockProtoNamedSecurityTestCallback,
15681 IndexedSecurityTestCallback);
15682 protected_hidden_proto_template->SetHiddenPrototype(true);
15683
15684 // Context for "foreign" objects used in test.
15685 Persistent<Context> context = v8::Context::New();
15686 context->Enter();
15687
15688 // Plain object, no security check.
15689 Local<Object> simple_object = Object::New();
15690
15691 // Object with explicit security check.
15692 Local<Object> protected_object =
15693 no_proto_template->NewInstance();
15694
15695 // JSGlobalProxy object, always have security check.
15696 Local<Object> proxy_object =
15697 context->Global();
15698
15699 // Global object, the prototype of proxy_object. No security checks.
15700 Local<Object> global_object =
15701 proxy_object->GetPrototype()->ToObject();
15702
15703 // Hidden prototype without security check.
15704 Local<Object> hidden_prototype =
15705 hidden_proto_template->GetFunction()->NewInstance();
15706 Local<Object> object_with_hidden =
15707 Object::New();
15708 object_with_hidden->SetPrototype(hidden_prototype);
15709
15710 // Hidden prototype with security check on the hidden prototype.
15711 Local<Object> protected_hidden_prototype =
15712 protected_hidden_proto_template->GetFunction()->NewInstance();
15713 Local<Object> object_with_protected_hidden =
15714 Object::New();
15715 object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
15716
15717 context->Exit();
15718
15719 // Template for object for second context. Values to test are put on it as
15720 // properties.
15721 Local<ObjectTemplate> global_template = ObjectTemplate::New();
15722 global_template->Set(v8_str("simple"), simple_object);
15723 global_template->Set(v8_str("protected"), protected_object);
15724 global_template->Set(v8_str("global"), global_object);
15725 global_template->Set(v8_str("proxy"), proxy_object);
15726 global_template->Set(v8_str("hidden"), object_with_hidden);
15727 global_template->Set(v8_str("phidden"), object_with_protected_hidden);
15728
15729 LocalContext context2(NULL, global_template);
15730
15731 Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
15732 CHECK(result1->Equals(simple_object->GetPrototype()));
15733
15734 Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
15735 CHECK(result2->Equals(Undefined()));
15736
15737 Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
15738 CHECK(result3->Equals(global_object->GetPrototype()));
15739
15740 Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
15741 CHECK(result4->Equals(Undefined()));
15742
15743 Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
15744 CHECK(result5->Equals(
15745 object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
15746
15747 Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
15748 CHECK(result6->Equals(Undefined()));
15749
15750 context.Dispose();
15751}
Ben Murdoch69a99ed2011-11-30 16:03:39 +000015752
15753
15754static void TestReceiver(Local<Value> expected_result,
15755 Local<Value> expected_receiver,
15756 const char* code) {
15757 Local<Value> result = CompileRun(code);
15758 CHECK(result->IsObject());
15759 CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
15760 CHECK(expected_result->Equals(result->ToObject()->Get(0)));
15761}
15762
15763
15764THREADED_TEST(ForeignFunctionReceiver) {
15765 HandleScope scope;
15766
15767 // Create two contexts with different "id" properties ('i' and 'o').
15768 // Call a function both from its own context and from a the foreign
15769 // context, and see what "this" is bound to (returning both "this"
15770 // and "this.id" for comparison).
15771
15772 Persistent<Context> foreign_context = v8::Context::New();
15773 foreign_context->Enter();
15774 Local<Value> foreign_function =
15775 CompileRun("function func() { return { 0: this.id, "
15776 " 1: this, "
15777 " toString: function() { "
15778 " return this[0];"
15779 " }"
15780 " };"
15781 "}"
15782 "var id = 'i';"
15783 "func;");
15784 CHECK(foreign_function->IsFunction());
15785 foreign_context->Exit();
15786
15787 LocalContext context;
15788
15789 Local<String> password = v8_str("Password");
15790 // Don't get hit by security checks when accessing foreign_context's
15791 // global receiver (aka. global proxy).
15792 context->SetSecurityToken(password);
15793 foreign_context->SetSecurityToken(password);
15794
15795 Local<String> i = v8_str("i");
15796 Local<String> o = v8_str("o");
15797 Local<String> id = v8_str("id");
15798
15799 CompileRun("function ownfunc() { return { 0: this.id, "
15800 " 1: this, "
15801 " toString: function() { "
15802 " return this[0];"
15803 " }"
15804 " };"
15805 "}"
15806 "var id = 'o';"
15807 "ownfunc");
15808 context->Global()->Set(v8_str("func"), foreign_function);
15809
15810 // Sanity check the contexts.
15811 CHECK(i->Equals(foreign_context->Global()->Get(id)));
15812 CHECK(o->Equals(context->Global()->Get(id)));
15813
15814 // Checking local function's receiver.
15815 // Calling function using its call/apply methods.
15816 TestReceiver(o, context->Global(), "ownfunc.call()");
15817 TestReceiver(o, context->Global(), "ownfunc.apply()");
15818 // Making calls through built-in functions.
15819 TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
15820 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
15821 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
15822 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
15823 // Calling with environment record as base.
15824 TestReceiver(o, context->Global(), "ownfunc()");
15825 // Calling with no base.
15826 TestReceiver(o, context->Global(), "(1,ownfunc)()");
15827
15828 // Checking foreign function return value.
15829 // Calling function using its call/apply methods.
15830 TestReceiver(i, foreign_context->Global(), "func.call()");
15831 TestReceiver(i, foreign_context->Global(), "func.apply()");
15832 // Calling function using another context's call/apply methods.
15833 TestReceiver(i, foreign_context->Global(),
15834 "Function.prototype.call.call(func)");
15835 TestReceiver(i, foreign_context->Global(),
15836 "Function.prototype.call.apply(func)");
15837 TestReceiver(i, foreign_context->Global(),
15838 "Function.prototype.apply.call(func)");
15839 TestReceiver(i, foreign_context->Global(),
15840 "Function.prototype.apply.apply(func)");
15841 // Making calls through built-in functions.
15842 TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
15843 // ToString(func()) is func()[0], i.e., the returned this.id.
15844 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
15845 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
15846 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
15847
15848 // TODO(1547): Make the following also return "i".
15849 // Calling with environment record as base.
15850 TestReceiver(o, context->Global(), "func()");
15851 // Calling with no base.
15852 TestReceiver(o, context->Global(), "(1,func)()");
15853
15854 foreign_context.Dispose();
15855}
Ben Murdochc7cc0282012-03-05 14:35:55 +000015856
15857
15858uint8_t callback_fired = 0;
15859
15860
15861void CallCompletedCallback1() {
15862 i::OS::Print("Firing callback 1.\n");
15863 callback_fired ^= 1; // Toggle first bit.
15864}
15865
15866
15867void CallCompletedCallback2() {
15868 i::OS::Print("Firing callback 2.\n");
15869 callback_fired ^= 2; // Toggle second bit.
15870}
15871
15872
15873Handle<Value> RecursiveCall(const Arguments& args) {
15874 int32_t level = args[0]->Int32Value();
15875 if (level < 3) {
15876 level++;
15877 i::OS::Print("Entering recursion level %d.\n", level);
15878 char script[64];
15879 i::Vector<char> script_vector(script, sizeof(script));
15880 i::OS::SNPrintF(script_vector, "recursion(%d)", level);
15881 CompileRun(script_vector.start());
15882 i::OS::Print("Leaving recursion level %d.\n", level);
15883 CHECK_EQ(0, callback_fired);
15884 } else {
15885 i::OS::Print("Recursion ends.\n");
15886 CHECK_EQ(0, callback_fired);
15887 }
15888 return Undefined();
15889}
15890
15891
15892TEST(CallCompletedCallback) {
15893 v8::HandleScope scope;
15894 LocalContext env;
15895 v8::Handle<v8::FunctionTemplate> recursive_runtime =
15896 v8::FunctionTemplate::New(RecursiveCall);
15897 env->Global()->Set(v8_str("recursion"),
15898 recursive_runtime->GetFunction());
15899 // Adding the same callback a second time has no effect.
15900 v8::V8::AddCallCompletedCallback(CallCompletedCallback1);
15901 v8::V8::AddCallCompletedCallback(CallCompletedCallback1);
15902 v8::V8::AddCallCompletedCallback(CallCompletedCallback2);
15903 i::OS::Print("--- Script (1) ---\n");
15904 Local<Script> script =
15905 v8::Script::Compile(v8::String::New("recursion(0)"));
15906 script->Run();
15907 CHECK_EQ(3, callback_fired);
15908
15909 i::OS::Print("\n--- Script (2) ---\n");
15910 callback_fired = 0;
15911 v8::V8::RemoveCallCompletedCallback(CallCompletedCallback1);
15912 script->Run();
15913 CHECK_EQ(2, callback_fired);
15914
15915 i::OS::Print("\n--- Function ---\n");
15916 callback_fired = 0;
15917 Local<Function> recursive_function =
15918 Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
15919 v8::Handle<Value> args[] = { v8_num(0) };
15920 recursive_function->Call(env->Global(), 1, args);
15921 CHECK_EQ(2, callback_fired);
15922}
15923
15924
15925void CallCompletedCallbackNoException() {
15926 v8::HandleScope scope;
15927 CompileRun("1+1;");
15928}
15929
15930
15931void CallCompletedCallbackException() {
15932 v8::HandleScope scope;
15933 CompileRun("throw 'second exception';");
15934}
15935
15936
15937TEST(CallCompletedCallbackOneException) {
15938 v8::HandleScope scope;
15939 LocalContext env;
15940 v8::V8::AddCallCompletedCallback(CallCompletedCallbackNoException);
15941 CompileRun("throw 'exception';");
15942}
15943
15944
15945TEST(CallCompletedCallbackTwoExceptions) {
15946 v8::HandleScope scope;
15947 LocalContext env;
15948 v8::V8::AddCallCompletedCallback(CallCompletedCallbackException);
15949 CompileRun("throw 'first exception';");
15950}