blob: dab8b7c286c844c0932cc48515818ffbd0b139c2 [file] [log] [blame]
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001// Copyright 2011 the V8 project authors. All rights reserved.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
ager@chromium.org3811b432009-10-28 14:53:37 +000028#include <limits.h>
29
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000030#include "v8.h"
31
32#include "api.h"
lrn@chromium.org1c092762011-05-09 09:42:16 +000033#include "isolate.h"
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +000034#include "compilation-cache.h"
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000035#include "execution.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000036#include "snapshot.h"
37#include "platform.h"
ager@chromium.org3811b432009-10-28 14:53:37 +000038#include "utils.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000039#include "cctest.h"
ager@chromium.org5b2fbee2010-09-08 06:38:15 +000040#include "parser.h"
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +000041#include "unicode-inl.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000042
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000043static const bool kLogThreading = false;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000044
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000045static bool IsNaN(double x) {
46#ifdef WIN32
47 return _isnan(x);
48#else
49 return isnan(x);
50#endif
51}
52
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000053using ::v8::AccessorInfo;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000054using ::v8::Arguments;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000055using ::v8::Context;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000056using ::v8::Extension;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000057using ::v8::Function;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000058using ::v8::FunctionTemplate;
59using ::v8::Handle;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000060using ::v8::HandleScope;
61using ::v8::Local;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000062using ::v8::Message;
63using ::v8::MessageCallback;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000064using ::v8::Object;
65using ::v8::ObjectTemplate;
66using ::v8::Persistent;
67using ::v8::Script;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000068using ::v8::StackTrace;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000069using ::v8::String;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000070using ::v8::TryCatch;
71using ::v8::Undefined;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000072using ::v8::V8;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000073using ::v8::Value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000074
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000075
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +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
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +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}
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +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
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000096static void ExpectTrue(const char* code) {
97 ExpectBoolean(code, true);
98}
99
100
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000101static void ExpectFalse(const char* code) {
102 ExpectBoolean(code, false);
103}
104
105
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +0000106static void ExpectObject(const char* code, Local<Value> expected) {
107 Local<Value> result = CompileRun(code);
108 CHECK(result->Equals(expected));
109}
110
111
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000112static void ExpectUndefined(const char* code) {
113 Local<Value> result = CompileRun(code);
114 CHECK(result->IsUndefined());
115}
116
117
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +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
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +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
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +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) == '';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000222 CHECK(value1->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000223
224 v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000225 CHECK(value2->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000226
227 v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000228 CHECK(value3->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000229
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]'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000250 CHECK(value4->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000251
252 v8::Handle<Value> value5 = CompileRun(
253 "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000254 CHECK(value5->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000255
256 v8::Handle<Value> value6 = CompileRun(
257 "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000258 CHECK(value6->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000259
260 v8::Handle<Value> value7 = CompileRun(
261 "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
262 "'[object Cons1],[object Cons2],[object Cons3],d';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000263 CHECK(value7->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000264
265 v8::Handle<Value> value8 = CompileRun(
266 "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000267 CHECK(value8->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000268}
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
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000298THREADED_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
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +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) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000328 int array_length = i::StrLength(source) + 1;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000329 uint16_t* converted = i::NewArray<uint16_t>(array_length);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000330 for (int i = 0; i < array_length; i++) converted[i] = source[i];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000331 return converted;
332}
333
334
335class TestResource: public String::ExternalStringResource {
336 public:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000337 explicit TestResource(uint16_t* data, int* counter = NULL)
338 : data_(data), length_(0), counter_(counter) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000339 while (data[length_]) ++length_;
340 }
341
342 ~TestResource() {
343 i::DeleteArray(data_);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000344 if (counter_ != NULL) ++*counter_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +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_;
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000357 int* counter_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000358};
359
360
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000361class TestAsciiResource: public String::ExternalAsciiStringResource {
362 public:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000363 explicit TestAsciiResource(const char* data, int* counter = NULL)
364 : data_(data), length_(strlen(data)), counter_(counter) { }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000365
366 ~TestAsciiResource() {
367 i::DeleteArray(data_);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000368 if (counter_ != NULL) ++*counter_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000369 }
370
371 const char* data() const {
372 return data_;
373 }
374
375 size_t length() const {
376 return length_;
377 }
378 private:
ager@chromium.org5ec48922009-05-05 07:25:34 +0000379 const char* data_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000380 size_t length_;
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000381 int* counter_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000382};
383
384
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000385THREADED_TEST(ScriptUsingStringResource) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000386 int dispose_count = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +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;
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000392 TestResource* resource = new TestResource(two_byte_source, &dispose_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +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()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000401 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000402 CHECK_EQ(0, dispose_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000403 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000404 v8::internal::Isolate::Current()->compilation_cache()->Clear();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000405 HEAP->CollectAllAvailableGarbage();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000406 CHECK_EQ(1, dispose_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000407}
408
409
410THREADED_TEST(ScriptUsingAsciiStringResource) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000411 int dispose_count = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000412 const char* c_source = "1 + 2 * 3";
413 {
414 v8::HandleScope scope;
415 LocalContext env;
416 Local<String> source =
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000417 String::NewExternal(new TestAsciiResource(i::StrDup(c_source),
418 &dispose_count));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000419 Local<Script> script = Script::Compile(source);
420 Local<Value> value = script->Run();
421 CHECK(value->IsNumber());
422 CHECK_EQ(7, value->Int32Value());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000423 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000424 CHECK_EQ(0, dispose_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000425 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000426 i::Isolate::Current()->compilation_cache()->Clear();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000427 HEAP->CollectAllAvailableGarbage();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000428 CHECK_EQ(1, dispose_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000429}
430
431
ager@chromium.org6f10e412009-02-13 10:11:16 +0000432THREADED_TEST(ScriptMakingExternalString) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000433 int dispose_count = 0;
ager@chromium.org6f10e412009-02-13 10:11:16 +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);
ager@chromium.org5c838252010-02-19 08:53:10 +0000439 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000440 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
441 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000442 bool success = source->MakeExternal(new TestResource(two_byte_source,
443 &dispose_count));
ager@chromium.org6f10e412009-02-13 10:11:16 +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());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000449 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000450 CHECK_EQ(0, dispose_count);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000451 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000452 i::Isolate::Current()->compilation_cache()->Clear();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000453 // TODO(1608): This should use kAbortIncrementalMarking.
454 HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000455 CHECK_EQ(1, dispose_count);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000456}
457
458
459THREADED_TEST(ScriptMakingExternalAsciiString) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000460 int dispose_count = 0;
ager@chromium.org6f10e412009-02-13 10:11:16 +0000461 const char* c_source = "1 + 2 * 3";
462 {
463 v8::HandleScope scope;
464 LocalContext env;
465 Local<String> source = v8_str(c_source);
ager@chromium.org5c838252010-02-19 08:53:10 +0000466 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000467 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
468 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
ager@chromium.org6f10e412009-02-13 10:11:16 +0000469 bool success = source->MakeExternal(
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000470 new TestAsciiResource(i::StrDup(c_source), &dispose_count));
ager@chromium.org6f10e412009-02-13 10:11:16 +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());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000476 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000477 CHECK_EQ(0, dispose_count);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000478 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000479 i::Isolate::Current()->compilation_cache()->Clear();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000480 // TODO(1608): This should use kAbortIncrementalMarking.
481 HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000482 CHECK_EQ(1, dispose_count);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000483}
484
485
ager@chromium.org5c838252010-02-19 08:53:10 +0000486TEST(MakingExternalStringConditions) {
487 v8::HandleScope scope;
488 LocalContext env;
489
490 // Free some space in the new space so that we can check freshness.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000491 HEAP->CollectGarbage(i::NEW_SPACE);
492 HEAP->CollectGarbage(i::NEW_SPACE);
ager@chromium.org5c838252010-02-19 08:53:10 +0000493
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000494 uint16_t* two_byte_string = AsciiToTwoByteString("s1");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000495 Local<String> small_string = String::New(two_byte_string);
496 i::DeleteArray(two_byte_string);
497
ager@chromium.org5c838252010-02-19 08:53:10 +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.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000501 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
502 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
ager@chromium.org5c838252010-02-19 08:53:10 +0000503 // Old space strings should be accepted.
504 CHECK(small_string->CanMakeExternal());
505
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000506 two_byte_string = AsciiToTwoByteString("small string 2");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000507 small_string = String::New(two_byte_string);
508 i::DeleteArray(two_byte_string);
509
ager@chromium.org5c838252010-02-19 08:53:10 +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';
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000522
523 two_byte_string = AsciiToTwoByteString(buf);
524 Local<String> large_string = String::New(two_byte_string);
ager@chromium.org5c838252010-02-19 08:53:10 +0000525 i::DeleteArray(buf);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000526 i::DeleteArray(two_byte_string);
ager@chromium.org5c838252010-02-19 08:53:10 +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.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000537 HEAP->CollectGarbage(i::NEW_SPACE);
538 HEAP->CollectGarbage(i::NEW_SPACE);
ager@chromium.org5c838252010-02-19 08:53:10 +0000539
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000540 Local<String> small_string = String::New("s1");
ager@chromium.org5c838252010-02-19 08:53:10 +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.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000544 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
545 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
ager@chromium.org5c838252010-02-19 08:53:10 +0000546 // Old space strings should be accepted.
547 CHECK(small_string->CanMakeExternal());
548
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000549 small_string = String::New("small string 2");
ager@chromium.org5c838252010-02-19 08:53:10 +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
ager@chromium.org6f10e412009-02-13 10:11:16 +0000569THREADED_TEST(UsingExternalString) {
ager@chromium.orge2902be2009-06-08 12:21:35 +0000570 {
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.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000577 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);
ager@chromium.orge2902be2009-06-08 12:21:35 +0000580 CHECK(isymbol->IsSymbol());
581 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000582 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
583 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000584}
585
586
587THREADED_TEST(UsingExternalAsciiString) {
ager@chromium.orge2902be2009-06-08 12:21:35 +0000588 {
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.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000595 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);
ager@chromium.orge2902be2009-06-08 12:21:35 +0000598 CHECK(isymbol->IsSymbol());
599 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000600 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
601 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000602}
603
604
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000605THREADED_TEST(ScavengeExternalString) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000606 int dispose_count = 0;
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000607 bool in_new_space = false;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000608 {
609 v8::HandleScope scope;
610 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
611 Local<String> string =
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000612 String::NewExternal(new TestResource(two_byte_string,
613 &dispose_count));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000614 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000615 HEAP->CollectGarbage(i::NEW_SPACE);
616 in_new_space = HEAP->InNewSpace(*istring);
617 CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000618 CHECK_EQ(0, dispose_count);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000619 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000620 HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000621 CHECK_EQ(1, dispose_count);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000622}
623
624
625THREADED_TEST(ScavengeExternalAsciiString) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000626 int dispose_count = 0;
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000627 bool in_new_space = false;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000628 {
629 v8::HandleScope scope;
630 const char* one_byte_string = "test string";
631 Local<String> string = String::NewExternal(
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000632 new TestAsciiResource(i::StrDup(one_byte_string), &dispose_count));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000633 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000634 HEAP->CollectGarbage(i::NEW_SPACE);
635 in_new_space = HEAP->InNewSpace(*istring);
636 CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000637 CHECK_EQ(0, dispose_count);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000638 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000639 HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000640 CHECK_EQ(1, dispose_count);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000641}
642
643
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000644class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
645 public:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000646 // Only used by non-threaded tests, so it can use static fields.
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000647 static int dispose_calls;
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000648 static int dispose_count;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000649
650 TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000651 : TestAsciiResource(data, &dispose_count),
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000652 dispose_(dispose) { }
653
654 void Dispose() {
655 ++dispose_calls;
656 if (dispose_) delete this;
657 }
658 private:
659 bool dispose_;
660};
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000661
662
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000663int TestAsciiResourceWithDisposeControl::dispose_count = 0;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000664int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000665
666
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000667TEST(ExternalStringWithDisposeHandling) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000668 const char* c_source = "1 + 2 * 3";
669
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000670 // Use a stack allocated external string resource allocated object.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000671 TestAsciiResourceWithDisposeControl::dispose_count = 0;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000672 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
673 TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000674 {
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());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000682 HEAP->CollectAllAvailableGarbage();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000683 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000684 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000685 i::Isolate::Current()->compilation_cache()->Clear();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000686 HEAP->CollectAllAvailableGarbage();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000687 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000688 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000689
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000690 // Use a heap allocated external string resource allocated object.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000691 TestAsciiResourceWithDisposeControl::dispose_count = 0;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000692 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
693 TestAsciiResource* res_heap =
694 new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000695 {
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());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000703 HEAP->CollectAllAvailableGarbage();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000704 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000705 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000706 i::Isolate::Current()->compilation_cache()->Clear();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000707 HEAP->CollectAllAvailableGarbage();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000708 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000709 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_count);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000710}
711
712
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +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);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000725
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
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +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);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000739
740 two_byte_source = AsciiToTwoByteString(two_byte_string_2);
741 right = String::New(two_byte_source);
742 i::DeleteArray(two_byte_source);
743
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +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 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000753 i::Isolate::Current()->compilation_cache()->Clear();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000754 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
755 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000756}
757
758
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +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
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000782static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
783 ApiTestFuzzer::Fuzz();
784 return v8_num(239);
785}
786
787
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +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"));
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000814 fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), Return239);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +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);
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000822
823 result = v8_compile("(new obj()).m")->Run();
824 CHECK_EQ(239, result->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000825 }
826}
827
828
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000829static 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);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000833 return v8::True();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000834}
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)
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000889 // Check a value with a leading 1 bit in x64 Smi encoding.
890 expected_ptr = reinterpret_cast<void*>(0x400000000);
891 TestExternalPointerWrapping();
892
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000893 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
894 TestExternalPointerWrapping();
895
896 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
897 TestExternalPointerWrapping();
898#endif
899}
900
901
sgjesse@chromium.org900d3b72009-08-07 11:24:25 +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
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +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
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +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
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +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;
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +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());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +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);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001192 v8::Handle<v8::Object> obj(env->Global());
1193 v8::Handle<Script> script(v8_compile("dummy()"));
1194 v8::Handle<Value> result(script->Run());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001195 CHECK_EQ(13.4, result->NumberValue());
1196 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1197 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1198}
1199
1200
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001201THREADED_TEST(ObjectTemplate) {
1202 v8::HandleScope scope;
1203 Local<ObjectTemplate> templ1 = ObjectTemplate::New();
1204 templ1->Set("x", v8_num(10));
1205 templ1->Set("y", v8_num(13));
1206 LocalContext env;
1207 Local<v8::Object> instance1 = templ1->NewInstance();
1208 env->Global()->Set(v8_str("p"), instance1);
1209 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1210 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1211 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
1212 fun->PrototypeTemplate()->Set("nirk", v8_num(123));
1213 Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1214 templ2->Set("a", v8_num(12));
1215 templ2->Set("b", templ1);
1216 Local<v8::Object> instance2 = templ2->NewInstance();
1217 env->Global()->Set(v8_str("q"), instance2);
1218 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1219 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1220 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1221 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1222}
1223
1224
1225static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
1226 ApiTestFuzzer::Fuzz();
1227 return v8_num(17.2);
1228}
1229
1230
1231static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
1232 ApiTestFuzzer::Fuzz();
1233 return v8_num(15.2);
1234}
1235
1236
1237THREADED_TEST(DescriptorInheritance) {
1238 v8::HandleScope scope;
1239 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
1240 super->PrototypeTemplate()->Set("flabby",
1241 v8::FunctionTemplate::New(GetFlabby));
1242 super->PrototypeTemplate()->Set("PI", v8_num(3.14));
1243
1244 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1245
1246 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
1247 base1->Inherit(super);
1248 base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
1249
1250 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
1251 base2->Inherit(super);
1252 base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
1253
1254 LocalContext env;
1255
1256 env->Global()->Set(v8_str("s"), super->GetFunction());
1257 env->Global()->Set(v8_str("base1"), base1->GetFunction());
1258 env->Global()->Set(v8_str("base2"), base2->GetFunction());
1259
1260 // Checks right __proto__ chain.
1261 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1262 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1263
1264 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1265
1266 // Instance accessor should not be visible on function object or its prototype
1267 CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1268 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1269 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1270
1271 env->Global()->Set(v8_str("obj"),
1272 base1->GetFunction()->NewInstance());
1273 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1274 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1275 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1276 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1277 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1278
1279 env->Global()->Set(v8_str("obj2"),
1280 base2->GetFunction()->NewInstance());
1281 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1282 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1283 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1284 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1285 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1286
1287 // base1 and base2 cannot cross reference to each's prototype
1288 CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1289 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1290}
1291
1292
1293int echo_named_call_count;
1294
1295
1296static v8::Handle<Value> EchoNamedProperty(Local<String> name,
1297 const AccessorInfo& info) {
1298 ApiTestFuzzer::Fuzz();
1299 CHECK_EQ(v8_str("data"), info.Data());
1300 echo_named_call_count++;
1301 return name;
1302}
1303
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001304// Helper functions for Interceptor/Accessor interaction tests
1305
1306Handle<Value> SimpleAccessorGetter(Local<String> name,
1307 const AccessorInfo& info) {
1308 Handle<Object> self = info.This();
1309 return self->Get(String::Concat(v8_str("accessor_"), name));
1310}
1311
1312void SimpleAccessorSetter(Local<String> name, Local<Value> value,
1313 const AccessorInfo& info) {
1314 Handle<Object> self = info.This();
1315 self->Set(String::Concat(v8_str("accessor_"), name), value);
1316}
1317
1318Handle<Value> EmptyInterceptorGetter(Local<String> name,
1319 const AccessorInfo& info) {
1320 return Handle<Value>();
1321}
1322
1323Handle<Value> EmptyInterceptorSetter(Local<String> name,
1324 Local<Value> value,
1325 const AccessorInfo& info) {
1326 return Handle<Value>();
1327}
1328
1329Handle<Value> InterceptorGetter(Local<String> name,
1330 const AccessorInfo& info) {
1331 // Intercept names that start with 'interceptor_'.
1332 String::AsciiValue ascii(name);
1333 char* name_str = *ascii;
1334 char prefix[] = "interceptor_";
1335 int i;
1336 for (i = 0; name_str[i] && prefix[i]; ++i) {
1337 if (name_str[i] != prefix[i]) return Handle<Value>();
1338 }
1339 Handle<Object> self = info.This();
1340 return self->GetHiddenValue(v8_str(name_str + i));
1341}
1342
1343Handle<Value> InterceptorSetter(Local<String> name,
1344 Local<Value> value,
1345 const AccessorInfo& info) {
1346 // Intercept accesses that set certain integer values.
1347 if (value->IsInt32() && value->Int32Value() < 10000) {
1348 Handle<Object> self = info.This();
1349 self->SetHiddenValue(name, value);
1350 return value;
1351 }
1352 return Handle<Value>();
1353}
1354
1355void AddAccessor(Handle<FunctionTemplate> templ,
1356 Handle<String> name,
1357 v8::AccessorGetter getter,
1358 v8::AccessorSetter setter) {
1359 templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
1360}
1361
1362void AddInterceptor(Handle<FunctionTemplate> templ,
1363 v8::NamedPropertyGetter getter,
1364 v8::NamedPropertySetter setter) {
1365 templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
1366}
1367
1368THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
1369 v8::HandleScope scope;
1370 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1371 Handle<FunctionTemplate> child = FunctionTemplate::New();
1372 child->Inherit(parent);
1373 AddAccessor(parent, v8_str("age"),
1374 SimpleAccessorGetter, SimpleAccessorSetter);
1375 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1376 LocalContext env;
1377 env->Global()->Set(v8_str("Child"), child->GetFunction());
1378 CompileRun("var child = new Child;"
1379 "child.age = 10;");
1380 ExpectBoolean("child.hasOwnProperty('age')", false);
1381 ExpectInt32("child.age", 10);
1382 ExpectInt32("child.accessor_age", 10);
1383}
1384
1385THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
1386 v8::HandleScope scope;
1387 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1388 Handle<FunctionTemplate> child = FunctionTemplate::New();
1389 child->Inherit(parent);
1390 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1391 LocalContext env;
1392 env->Global()->Set(v8_str("Child"), child->GetFunction());
1393 CompileRun("var child = new Child;"
1394 "var parent = child.__proto__;"
1395 "Object.defineProperty(parent, 'age', "
1396 " {get: function(){ return this.accessor_age; }, "
1397 " set: function(v){ this.accessor_age = v; }, "
1398 " enumerable: true, configurable: true});"
1399 "child.age = 10;");
1400 ExpectBoolean("child.hasOwnProperty('age')", false);
1401 ExpectInt32("child.age", 10);
1402 ExpectInt32("child.accessor_age", 10);
1403}
1404
1405THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
1406 v8::HandleScope scope;
1407 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1408 Handle<FunctionTemplate> child = FunctionTemplate::New();
1409 child->Inherit(parent);
1410 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1411 LocalContext env;
1412 env->Global()->Set(v8_str("Child"), child->GetFunction());
1413 CompileRun("var child = new Child;"
1414 "var parent = child.__proto__;"
1415 "parent.name = 'Alice';");
1416 ExpectBoolean("child.hasOwnProperty('name')", false);
1417 ExpectString("child.name", "Alice");
1418 CompileRun("child.name = 'Bob';");
1419 ExpectString("child.name", "Bob");
1420 ExpectBoolean("child.hasOwnProperty('name')", true);
1421 ExpectString("parent.name", "Alice");
1422}
1423
1424THREADED_TEST(SwitchFromInterceptorToAccessor) {
1425 v8::HandleScope scope;
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001426 Handle<FunctionTemplate> templ = FunctionTemplate::New();
1427 AddAccessor(templ, v8_str("age"),
1428 SimpleAccessorGetter, SimpleAccessorSetter);
1429 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1430 LocalContext env;
1431 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1432 CompileRun("var obj = new Obj;"
1433 "function setAge(i){ obj.age = i; };"
1434 "for(var i = 0; i <= 10000; i++) setAge(i);");
1435 // All i < 10000 go to the interceptor.
1436 ExpectInt32("obj.interceptor_age", 9999);
1437 // The last i goes to the accessor.
1438 ExpectInt32("obj.accessor_age", 10000);
1439}
1440
1441THREADED_TEST(SwitchFromAccessorToInterceptor) {
1442 v8::HandleScope scope;
1443 Handle<FunctionTemplate> templ = FunctionTemplate::New();
1444 AddAccessor(templ, v8_str("age"),
1445 SimpleAccessorGetter, SimpleAccessorSetter);
1446 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1447 LocalContext env;
1448 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1449 CompileRun("var obj = new Obj;"
1450 "function setAge(i){ obj.age = i; };"
1451 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1452 // All i >= 10000 go to the accessor.
1453 ExpectInt32("obj.accessor_age", 10000);
1454 // The last i goes to the interceptor.
1455 ExpectInt32("obj.interceptor_age", 9999);
1456}
1457
1458THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
1459 v8::HandleScope scope;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001460 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1461 Handle<FunctionTemplate> child = FunctionTemplate::New();
1462 child->Inherit(parent);
1463 AddAccessor(parent, v8_str("age"),
1464 SimpleAccessorGetter, SimpleAccessorSetter);
1465 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1466 LocalContext env;
1467 env->Global()->Set(v8_str("Child"), child->GetFunction());
1468 CompileRun("var child = new Child;"
1469 "function setAge(i){ child.age = i; };"
1470 "for(var i = 0; i <= 10000; i++) setAge(i);");
1471 // All i < 10000 go to the interceptor.
1472 ExpectInt32("child.interceptor_age", 9999);
1473 // The last i goes to the accessor.
1474 ExpectInt32("child.accessor_age", 10000);
1475}
1476
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001477THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001478 v8::HandleScope scope;
1479 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1480 Handle<FunctionTemplate> child = FunctionTemplate::New();
1481 child->Inherit(parent);
1482 AddAccessor(parent, v8_str("age"),
1483 SimpleAccessorGetter, SimpleAccessorSetter);
1484 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1485 LocalContext env;
1486 env->Global()->Set(v8_str("Child"), child->GetFunction());
1487 CompileRun("var child = new Child;"
1488 "function setAge(i){ child.age = i; };"
1489 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1490 // All i >= 10000 go to the accessor.
1491 ExpectInt32("child.accessor_age", 10000);
1492 // The last i goes to the interceptor.
1493 ExpectInt32("child.interceptor_age", 9999);
1494}
1495
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001496THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
1497 v8::HandleScope scope;
1498 Handle<FunctionTemplate> templ = FunctionTemplate::New();
1499 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1500 LocalContext env;
1501 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1502 CompileRun("var obj = new Obj;"
1503 "function setter(i) { this.accessor_age = i; };"
1504 "function getter() { return this.accessor_age; };"
1505 "function setAge(i) { obj.age = i; };"
1506 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
1507 "for(var i = 0; i <= 10000; i++) setAge(i);");
1508 // All i < 10000 go to the interceptor.
1509 ExpectInt32("obj.interceptor_age", 9999);
1510 // The last i goes to the JavaScript accessor.
1511 ExpectInt32("obj.accessor_age", 10000);
1512 // The installed JavaScript getter is still intact.
1513 // This last part is a regression test for issue 1651 and relies on the fact
1514 // that both interceptor and accessor are being installed on the same object.
1515 ExpectInt32("obj.age", 10000);
1516 ExpectBoolean("obj.hasOwnProperty('age')", true);
1517 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
1518}
1519
1520THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
1521 v8::HandleScope scope;
1522 Handle<FunctionTemplate> templ = FunctionTemplate::New();
1523 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1524 LocalContext env;
1525 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1526 CompileRun("var obj = new Obj;"
1527 "function setter(i) { this.accessor_age = i; };"
1528 "function getter() { return this.accessor_age; };"
1529 "function setAge(i) { obj.age = i; };"
1530 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
1531 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1532 // All i >= 10000 go to the accessor.
1533 ExpectInt32("obj.accessor_age", 10000);
1534 // The last i goes to the interceptor.
1535 ExpectInt32("obj.interceptor_age", 9999);
1536 // The installed JavaScript getter is still intact.
1537 // This last part is a regression test for issue 1651 and relies on the fact
1538 // that both interceptor and accessor are being installed on the same object.
1539 ExpectInt32("obj.age", 10000);
1540 ExpectBoolean("obj.hasOwnProperty('age')", true);
1541 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
1542}
1543
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001544THREADED_TEST(SwitchFromInterceptorToProperty) {
1545 v8::HandleScope scope;
1546 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1547 Handle<FunctionTemplate> child = FunctionTemplate::New();
1548 child->Inherit(parent);
1549 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1550 LocalContext env;
1551 env->Global()->Set(v8_str("Child"), child->GetFunction());
1552 CompileRun("var child = new Child;"
1553 "function setAge(i){ child.age = i; };"
1554 "for(var i = 0; i <= 10000; i++) setAge(i);");
1555 // All i < 10000 go to the interceptor.
1556 ExpectInt32("child.interceptor_age", 9999);
1557 // The last i goes to child's own property.
1558 ExpectInt32("child.age", 10000);
1559}
1560
1561THREADED_TEST(SwitchFromPropertyToInterceptor) {
1562 v8::HandleScope scope;
1563 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1564 Handle<FunctionTemplate> child = FunctionTemplate::New();
1565 child->Inherit(parent);
1566 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1567 LocalContext env;
1568 env->Global()->Set(v8_str("Child"), child->GetFunction());
1569 CompileRun("var child = new Child;"
1570 "function setAge(i){ child.age = i; };"
1571 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1572 // All i >= 10000 go to child's own property.
1573 ExpectInt32("child.age", 10000);
1574 // The last i goes to the interceptor.
1575 ExpectInt32("child.interceptor_age", 9999);
1576}
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001577
1578THREADED_TEST(NamedPropertyHandlerGetter) {
1579 echo_named_call_count = 0;
1580 v8::HandleScope scope;
1581 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1582 templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
1583 0, 0, 0, 0,
1584 v8_str("data"));
1585 LocalContext env;
1586 env->Global()->Set(v8_str("obj"),
1587 templ->GetFunction()->NewInstance());
1588 CHECK_EQ(echo_named_call_count, 0);
1589 v8_compile("obj.x")->Run();
1590 CHECK_EQ(echo_named_call_count, 1);
1591 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
1592 v8::Handle<Value> str = CompileRun(code);
1593 String::AsciiValue value(str);
1594 CHECK_EQ(*value, "oddlepoddle");
1595 // Check default behavior
1596 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
1597 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
1598 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
1599}
1600
1601
1602int echo_indexed_call_count = 0;
1603
1604
1605static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
1606 const AccessorInfo& info) {
1607 ApiTestFuzzer::Fuzz();
1608 CHECK_EQ(v8_num(637), info.Data());
1609 echo_indexed_call_count++;
1610 return v8_num(index);
1611}
1612
1613
1614THREADED_TEST(IndexedPropertyHandlerGetter) {
1615 v8::HandleScope scope;
1616 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1617 templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
1618 0, 0, 0, 0,
1619 v8_num(637));
1620 LocalContext env;
1621 env->Global()->Set(v8_str("obj"),
1622 templ->GetFunction()->NewInstance());
1623 Local<Script> script = v8_compile("obj[900]");
1624 CHECK_EQ(script->Run()->Int32Value(), 900);
1625}
1626
1627
1628v8::Handle<v8::Object> bottom;
1629
1630static v8::Handle<Value> CheckThisIndexedPropertyHandler(
1631 uint32_t index,
1632 const AccessorInfo& info) {
1633 ApiTestFuzzer::Fuzz();
1634 CHECK(info.This()->Equals(bottom));
1635 return v8::Handle<Value>();
1636}
1637
1638static v8::Handle<Value> CheckThisNamedPropertyHandler(
1639 Local<String> name,
1640 const AccessorInfo& info) {
1641 ApiTestFuzzer::Fuzz();
1642 CHECK(info.This()->Equals(bottom));
1643 return v8::Handle<Value>();
1644}
1645
1646
1647v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
1648 Local<Value> value,
1649 const AccessorInfo& info) {
1650 ApiTestFuzzer::Fuzz();
1651 CHECK(info.This()->Equals(bottom));
1652 return v8::Handle<Value>();
1653}
1654
1655
1656v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
1657 Local<Value> value,
1658 const AccessorInfo& info) {
1659 ApiTestFuzzer::Fuzz();
1660 CHECK(info.This()->Equals(bottom));
1661 return v8::Handle<Value>();
1662}
1663
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001664v8::Handle<v8::Integer> CheckThisIndexedPropertyQuery(
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001665 uint32_t index,
1666 const AccessorInfo& info) {
1667 ApiTestFuzzer::Fuzz();
1668 CHECK(info.This()->Equals(bottom));
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001669 return v8::Handle<v8::Integer>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001670}
1671
1672
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001673v8::Handle<v8::Integer> CheckThisNamedPropertyQuery(Local<String> property,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001674 const AccessorInfo& info) {
1675 ApiTestFuzzer::Fuzz();
1676 CHECK(info.This()->Equals(bottom));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001677 return v8::Handle<v8::Integer>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001678}
1679
1680
1681v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
1682 uint32_t index,
1683 const AccessorInfo& info) {
1684 ApiTestFuzzer::Fuzz();
1685 CHECK(info.This()->Equals(bottom));
1686 return v8::Handle<v8::Boolean>();
1687}
1688
1689
1690v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
1691 Local<String> property,
1692 const AccessorInfo& info) {
1693 ApiTestFuzzer::Fuzz();
1694 CHECK(info.This()->Equals(bottom));
1695 return v8::Handle<v8::Boolean>();
1696}
1697
1698
1699v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
1700 const AccessorInfo& info) {
1701 ApiTestFuzzer::Fuzz();
1702 CHECK(info.This()->Equals(bottom));
1703 return v8::Handle<v8::Array>();
1704}
1705
1706
1707v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
1708 const AccessorInfo& info) {
1709 ApiTestFuzzer::Fuzz();
1710 CHECK(info.This()->Equals(bottom));
1711 return v8::Handle<v8::Array>();
1712}
1713
1714
1715THREADED_TEST(PropertyHandlerInPrototype) {
1716 v8::HandleScope scope;
1717 LocalContext env;
1718
1719 // Set up a prototype chain with three interceptors.
1720 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1721 templ->InstanceTemplate()->SetIndexedPropertyHandler(
1722 CheckThisIndexedPropertyHandler,
1723 CheckThisIndexedPropertySetter,
1724 CheckThisIndexedPropertyQuery,
1725 CheckThisIndexedPropertyDeleter,
1726 CheckThisIndexedPropertyEnumerator);
1727
1728 templ->InstanceTemplate()->SetNamedPropertyHandler(
1729 CheckThisNamedPropertyHandler,
1730 CheckThisNamedPropertySetter,
1731 CheckThisNamedPropertyQuery,
1732 CheckThisNamedPropertyDeleter,
1733 CheckThisNamedPropertyEnumerator);
1734
1735 bottom = templ->GetFunction()->NewInstance();
1736 Local<v8::Object> top = templ->GetFunction()->NewInstance();
1737 Local<v8::Object> middle = templ->GetFunction()->NewInstance();
1738
1739 bottom->Set(v8_str("__proto__"), middle);
1740 middle->Set(v8_str("__proto__"), top);
1741 env->Global()->Set(v8_str("obj"), bottom);
1742
1743 // Indexed and named get.
1744 Script::Compile(v8_str("obj[0]"))->Run();
1745 Script::Compile(v8_str("obj.x"))->Run();
1746
1747 // Indexed and named set.
1748 Script::Compile(v8_str("obj[1] = 42"))->Run();
1749 Script::Compile(v8_str("obj.y = 42"))->Run();
1750
1751 // Indexed and named query.
1752 Script::Compile(v8_str("0 in obj"))->Run();
1753 Script::Compile(v8_str("'x' in obj"))->Run();
1754
1755 // Indexed and named deleter.
1756 Script::Compile(v8_str("delete obj[0]"))->Run();
1757 Script::Compile(v8_str("delete obj.x"))->Run();
1758
1759 // Enumerators.
1760 Script::Compile(v8_str("for (var p in obj) ;"))->Run();
1761}
1762
1763
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001764static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
1765 const AccessorInfo& info) {
1766 ApiTestFuzzer::Fuzz();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001767 if (v8_str("pre")->Equals(key)) {
1768 return v8_str("PrePropertyHandler: pre");
1769 }
1770 return v8::Handle<String>();
1771}
1772
1773
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001774static v8::Handle<v8::Integer> PrePropertyHandlerQuery(Local<String> key,
1775 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001776 if (v8_str("pre")->Equals(key)) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001777 return v8::Integer::New(v8::None);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001778 }
1779
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001780 return v8::Handle<v8::Integer>(); // do not intercept the call
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001781}
1782
1783
1784THREADED_TEST(PrePropertyHandler) {
1785 v8::HandleScope scope;
1786 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
1787 desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
1788 0,
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001789 PrePropertyHandlerQuery);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001790 LocalContext env(NULL, desc->InstanceTemplate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001791 Script::Compile(v8_str(
1792 "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
1793 v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
1794 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
1795 v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
1796 CHECK_EQ(v8_str("Object: on"), result_on);
1797 v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
1798 CHECK(result_post.IsEmpty());
1799}
1800
1801
ager@chromium.org870a0b62008-11-04 11:43:05 +00001802THREADED_TEST(UndefinedIsNotEnumerable) {
1803 v8::HandleScope scope;
1804 LocalContext env;
1805 v8::Handle<Value> result = Script::Compile(v8_str(
1806 "this.propertyIsEnumerable(undefined)"))->Run();
1807 CHECK(result->IsFalse());
1808}
1809
1810
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001811v8::Handle<Script> call_recursively_script;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001812static const int kTargetRecursionDepth = 200; // near maximum
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001813
1814
1815static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
1816 ApiTestFuzzer::Fuzz();
1817 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1818 if (depth == kTargetRecursionDepth) return v8::Undefined();
1819 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1820 return call_recursively_script->Run();
1821}
1822
1823
1824static v8::Handle<Value> CallFunctionRecursivelyCall(
1825 const v8::Arguments& args) {
1826 ApiTestFuzzer::Fuzz();
1827 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1828 if (depth == kTargetRecursionDepth) {
1829 printf("[depth = %d]\n", depth);
1830 return v8::Undefined();
1831 }
1832 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1833 v8::Handle<Value> function =
1834 args.This()->Get(v8_str("callFunctionRecursively"));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001835 return function.As<Function>()->Call(args.This(), 0, NULL);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001836}
1837
1838
1839THREADED_TEST(DeepCrossLanguageRecursion) {
1840 v8::HandleScope scope;
1841 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
1842 global->Set(v8_str("callScriptRecursively"),
1843 v8::FunctionTemplate::New(CallScriptRecursivelyCall));
1844 global->Set(v8_str("callFunctionRecursively"),
1845 v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
1846 LocalContext env(NULL, global);
1847
1848 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1849 call_recursively_script = v8_compile("callScriptRecursively()");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001850 v8::Handle<Value> result(call_recursively_script->Run());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001851 call_recursively_script = v8::Handle<Script>();
1852
1853 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1854 Script::Compile(v8_str("callFunctionRecursively()"))->Run();
1855}
1856
1857
1858static v8::Handle<Value>
1859 ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1860 ApiTestFuzzer::Fuzz();
1861 return v8::ThrowException(key);
1862}
1863
1864
1865static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
1866 Local<Value>,
1867 const AccessorInfo&) {
1868 v8::ThrowException(key);
1869 return v8::Undefined(); // not the same as v8::Handle<v8::Value>()
1870}
1871
1872
1873THREADED_TEST(CallbackExceptionRegression) {
1874 v8::HandleScope scope;
1875 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1876 obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
1877 ThrowingPropertyHandlerSet);
1878 LocalContext env;
1879 env->Global()->Set(v8_str("obj"), obj->NewInstance());
1880 v8::Handle<Value> otto = Script::Compile(v8_str(
1881 "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
1882 CHECK_EQ(v8_str("otto"), otto);
1883 v8::Handle<Value> netto = Script::Compile(v8_str(
1884 "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
1885 CHECK_EQ(v8_str("netto"), netto);
1886}
1887
1888
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001889THREADED_TEST(FunctionPrototype) {
1890 v8::HandleScope scope;
1891 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
1892 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
1893 LocalContext env;
1894 env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
1895 Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
1896 CHECK_EQ(script->Run()->Int32Value(), 321);
1897}
1898
1899
1900THREADED_TEST(InternalFields) {
1901 v8::HandleScope scope;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001902 LocalContext env;
1903
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001904 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1905 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1906 instance_templ->SetInternalFieldCount(1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001907 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1908 CHECK_EQ(1, obj->InternalFieldCount());
1909 CHECK(obj->GetInternalField(0)->IsUndefined());
1910 obj->SetInternalField(0, v8_num(17));
1911 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
1912}
1913
1914
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001915THREADED_TEST(GlobalObjectInternalFields) {
1916 v8::HandleScope scope;
1917 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
1918 global_template->SetInternalFieldCount(1);
1919 LocalContext env(NULL, global_template);
1920 v8::Handle<v8::Object> global_proxy = env->Global();
1921 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
1922 CHECK_EQ(1, global->InternalFieldCount());
1923 CHECK(global->GetInternalField(0)->IsUndefined());
1924 global->SetInternalField(0, v8_num(17));
1925 CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
1926}
1927
1928
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001929THREADED_TEST(InternalFieldsNativePointers) {
1930 v8::HandleScope scope;
1931 LocalContext env;
1932
1933 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1934 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1935 instance_templ->SetInternalFieldCount(1);
1936 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1937 CHECK_EQ(1, obj->InternalFieldCount());
1938 CHECK(obj->GetPointerFromInternalField(0) == NULL);
1939
1940 char* data = new char[100];
1941
1942 void* aligned = data;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001943 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001944 void* unaligned = data + 1;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001945 CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001946
1947 // Check reading and writing aligned pointers.
1948 obj->SetPointerInInternalField(0, aligned);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001949 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001950 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1951
1952 // Check reading and writing unaligned pointers.
1953 obj->SetPointerInInternalField(0, unaligned);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001954 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001955 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1956
1957 delete[] data;
1958}
1959
1960
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001961THREADED_TEST(InternalFieldsNativePointersAndExternal) {
1962 v8::HandleScope scope;
1963 LocalContext env;
1964
1965 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1966 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1967 instance_templ->SetInternalFieldCount(1);
1968 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1969 CHECK_EQ(1, obj->InternalFieldCount());
1970 CHECK(obj->GetPointerFromInternalField(0) == NULL);
1971
1972 char* data = new char[100];
1973
1974 void* aligned = data;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001975 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001976 void* unaligned = data + 1;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001977 CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001978
1979 obj->SetPointerInInternalField(0, aligned);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001980 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001981 CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0)));
1982
1983 obj->SetPointerInInternalField(0, unaligned);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001984 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001985 CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0)));
1986
1987 obj->SetInternalField(0, v8::External::Wrap(aligned));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001988 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001989 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1990
1991 obj->SetInternalField(0, v8::External::Wrap(unaligned));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001992 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001993 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1994
1995 delete[] data;
1996}
1997
1998
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001999THREADED_TEST(IdentityHash) {
2000 v8::HandleScope scope;
2001 LocalContext env;
2002
2003 // Ensure that the test starts with an fresh heap to test whether the hash
2004 // code is based on the address.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002005 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002006 Local<v8::Object> obj = v8::Object::New();
2007 int hash = obj->GetIdentityHash();
2008 int hash1 = obj->GetIdentityHash();
2009 CHECK_EQ(hash, hash1);
2010 int hash2 = v8::Object::New()->GetIdentityHash();
2011 // Since the identity hash is essentially a random number two consecutive
2012 // objects should not be assigned the same hash code. If the test below fails
2013 // the random number generator should be evaluated.
2014 CHECK_NE(hash, hash2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002015 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002016 int hash3 = v8::Object::New()->GetIdentityHash();
2017 // Make sure that the identity hash is not based on the initial address of
2018 // the object alone. If the test below fails the random number generator
2019 // should be evaluated.
2020 CHECK_NE(hash, hash3);
2021 int hash4 = obj->GetIdentityHash();
2022 CHECK_EQ(hash, hash4);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002023
2024 // Check identity hashes behaviour in the presence of JS accessors.
2025 // Put a getter for 'v8::IdentityHash' on the Object's prototype:
2026 {
2027 CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
2028 Local<v8::Object> o1 = v8::Object::New();
2029 Local<v8::Object> o2 = v8::Object::New();
2030 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2031 }
2032 {
2033 CompileRun(
2034 "function cnst() { return 42; };\n"
2035 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
2036 Local<v8::Object> o1 = v8::Object::New();
2037 Local<v8::Object> o2 = v8::Object::New();
2038 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2039 }
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002040}
2041
2042
2043THREADED_TEST(HiddenProperties) {
2044 v8::HandleScope scope;
2045 LocalContext env;
2046
2047 v8::Local<v8::Object> obj = v8::Object::New();
2048 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
2049 v8::Local<v8::String> empty = v8_str("");
2050 v8::Local<v8::String> prop_name = v8_str("prop_name");
2051
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002052 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002053
kasperl@chromium.orgacae3782009-04-11 09:17:08 +00002054 // Make sure delete of a non-existent hidden value works
2055 CHECK(obj->DeleteHiddenValue(key));
2056
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002057 CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
2058 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
2059 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
2060 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2061
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002062 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002063
2064 // Make sure we do not find the hidden property.
2065 CHECK(!obj->Has(empty));
2066 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2067 CHECK(obj->Get(empty)->IsUndefined());
2068 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2069 CHECK(obj->Set(empty, v8::Integer::New(2003)));
2070 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2071 CHECK_EQ(2003, obj->Get(empty)->Int32Value());
2072
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002073 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002074
2075 // Add another property and delete it afterwards to force the object in
2076 // slow case.
2077 CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
2078 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2079 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
2080 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2081 CHECK(obj->Delete(prop_name));
2082 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2083
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002084 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002085
2086 CHECK(obj->DeleteHiddenValue(key));
2087 CHECK(obj->GetHiddenValue(key).IsEmpty());
2088}
2089
2090
ricow@chromium.org9fe9cdf2011-09-27 08:04:16 +00002091THREADED_TEST(Regress97784) {
2092 // Regression test for crbug.com/97784
2093 // Messing with the Object.prototype should not have effect on
2094 // hidden properties.
2095 v8::HandleScope scope;
2096 LocalContext env;
2097
2098 v8::Local<v8::Object> obj = v8::Object::New();
2099 v8::Local<v8::String> key = v8_str("hidden");
2100
2101 CompileRun(
2102 "set_called = false;"
2103 "Object.defineProperty("
2104 " Object.prototype,"
2105 " 'hidden',"
2106 " {get: function() { return 45; },"
2107 " set: function() { set_called = true; }})");
2108
2109 CHECK(obj->GetHiddenValue(key).IsEmpty());
2110 // Make sure that the getter and setter from Object.prototype is not invoked.
2111 // If it did we would have full access to the hidden properties in
2112 // the accessor.
2113 CHECK(obj->SetHiddenValue(key, v8::Integer::New(42)));
2114 ExpectFalse("set_called");
2115 CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
2116}
2117
2118
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002119static bool interceptor_for_hidden_properties_called;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002120static v8::Handle<Value> InterceptorForHiddenProperties(
2121 Local<String> name, const AccessorInfo& info) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002122 interceptor_for_hidden_properties_called = true;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002123 return v8::Handle<Value>();
2124}
2125
2126
2127THREADED_TEST(HiddenPropertiesWithInterceptors) {
2128 v8::HandleScope scope;
2129 LocalContext context;
2130
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002131 interceptor_for_hidden_properties_called = false;
2132
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002133 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
2134
2135 // Associate an interceptor with an object and start setting hidden values.
2136 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
2137 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
2138 instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
2139 Local<v8::Function> function = fun_templ->GetFunction();
2140 Local<v8::Object> obj = function->NewInstance();
2141 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
2142 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002143 CHECK(!interceptor_for_hidden_properties_called);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002144}
2145
2146
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002147THREADED_TEST(External) {
2148 v8::HandleScope scope;
2149 int x = 3;
2150 Local<v8::External> ext = v8::External::New(&x);
2151 LocalContext env;
2152 env->Global()->Set(v8_str("ext"), ext);
2153 Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002154 v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002155 int* ptr = static_cast<int*>(reext->Value());
2156 CHECK_EQ(x, 3);
2157 *ptr = 10;
2158 CHECK_EQ(x, 10);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002159
2160 // Make sure unaligned pointers are wrapped properly.
2161 char* data = i::StrDup("0123456789");
2162 Local<v8::Value> zero = v8::External::Wrap(&data[0]);
2163 Local<v8::Value> one = v8::External::Wrap(&data[1]);
2164 Local<v8::Value> two = v8::External::Wrap(&data[2]);
2165 Local<v8::Value> three = v8::External::Wrap(&data[3]);
2166
2167 char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero));
2168 CHECK_EQ('0', *char_ptr);
2169 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one));
2170 CHECK_EQ('1', *char_ptr);
2171 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two));
2172 CHECK_EQ('2', *char_ptr);
2173 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three));
2174 CHECK_EQ('3', *char_ptr);
2175 i::DeleteArray(data);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002176}
2177
2178
2179THREADED_TEST(GlobalHandle) {
2180 v8::Persistent<String> global;
2181 {
2182 v8::HandleScope scope;
2183 Local<String> str = v8_str("str");
2184 global = v8::Persistent<String>::New(str);
2185 }
2186 CHECK_EQ(global->Length(), 3);
2187 global.Dispose();
2188}
2189
2190
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002191class WeakCallCounter {
2192 public:
2193 explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
2194 int id() { return id_; }
2195 void increment() { number_of_weak_calls_++; }
2196 int NumberOfWeakCalls() { return number_of_weak_calls_; }
2197 private:
2198 int id_;
2199 int number_of_weak_calls_;
2200};
2201
2202
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002203static void WeakPointerCallback(Persistent<Value> handle, void* id) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002204 WeakCallCounter* counter = reinterpret_cast<WeakCallCounter*>(id);
2205 CHECK_EQ(1234, counter->id());
2206 counter->increment();
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002207 handle.Dispose();
2208}
2209
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002210
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002211THREADED_TEST(ApiObjectGroups) {
2212 HandleScope scope;
2213 LocalContext env;
2214
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002215 Persistent<Object> g1s1;
2216 Persistent<Object> g1s2;
2217 Persistent<Object> g1c1;
2218 Persistent<Object> g2s1;
2219 Persistent<Object> g2s2;
2220 Persistent<Object> g2c1;
2221
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002222 WeakCallCounter counter(1234);
2223
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002224 {
2225 HandleScope scope;
2226 g1s1 = Persistent<Object>::New(Object::New());
2227 g1s2 = Persistent<Object>::New(Object::New());
2228 g1c1 = Persistent<Object>::New(Object::New());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002229 g1s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2230 g1s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2231 g1c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002232
2233 g2s1 = Persistent<Object>::New(Object::New());
2234 g2s2 = Persistent<Object>::New(Object::New());
2235 g2c1 = Persistent<Object>::New(Object::New());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002236 g2s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2237 g2s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2238 g2c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002239 }
2240
2241 Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
2242
2243 // Connect group 1 and 2, make a cycle.
2244 CHECK(g1s2->Set(0, g2s2));
2245 CHECK(g2s1->Set(0, g1s1));
2246
2247 {
2248 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2249 Persistent<Value> g1_children[] = { g1c1 };
2250 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2251 Persistent<Value> g2_children[] = { g2c1 };
2252 V8::AddObjectGroup(g1_objects, 2);
2253 V8::AddImplicitReferences(g1s1, g1_children, 1);
2254 V8::AddObjectGroup(g2_objects, 2);
2255 V8::AddImplicitReferences(g2s2, g2_children, 1);
2256 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002257 // Do a single full GC. Use kMakeHeapIterableMask to ensure that
2258 // incremental garbage collection is stopped.
2259 HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002260
2261 // All object should be alive.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002262 CHECK_EQ(0, counter.NumberOfWeakCalls());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002263
2264 // Weaken the root.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002265 root.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002266 // But make children strong roots---all the objects (except for children)
2267 // should be collectable now.
2268 g1c1.ClearWeak();
2269 g2c1.ClearWeak();
2270
2271 // Groups are deleted, rebuild groups.
2272 {
2273 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2274 Persistent<Value> g1_children[] = { g1c1 };
2275 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2276 Persistent<Value> g2_children[] = { g2c1 };
2277 V8::AddObjectGroup(g1_objects, 2);
2278 V8::AddImplicitReferences(g1s1, g1_children, 1);
2279 V8::AddObjectGroup(g2_objects, 2);
2280 V8::AddImplicitReferences(g2s2, g2_children, 1);
2281 }
2282
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002283 HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002284
2285 // All objects should be gone. 5 global handles in total.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002286 CHECK_EQ(5, counter.NumberOfWeakCalls());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002287
2288 // And now make children weak again and collect them.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002289 g1c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2290 g2c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002291
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002292 HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
2293 CHECK_EQ(7, counter.NumberOfWeakCalls());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002294}
2295
2296
2297THREADED_TEST(ApiObjectGroupsCycle) {
2298 HandleScope scope;
2299 LocalContext env;
2300
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002301 WeakCallCounter counter(1234);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002302
2303 Persistent<Object> g1s1;
2304 Persistent<Object> g1s2;
2305 Persistent<Object> g2s1;
2306 Persistent<Object> g2s2;
2307 Persistent<Object> g3s1;
2308 Persistent<Object> g3s2;
2309
2310 {
2311 HandleScope scope;
2312 g1s1 = Persistent<Object>::New(Object::New());
2313 g1s2 = Persistent<Object>::New(Object::New());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002314 g1s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2315 g1s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002316
2317 g2s1 = Persistent<Object>::New(Object::New());
2318 g2s2 = Persistent<Object>::New(Object::New());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002319 g2s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2320 g2s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002321
2322 g3s1 = Persistent<Object>::New(Object::New());
2323 g3s2 = Persistent<Object>::New(Object::New());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002324 g3s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2325 g3s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002326 }
2327
2328 Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
2329
2330 // Connect groups. We're building the following cycle:
2331 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
2332 // groups.
2333 {
2334 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2335 Persistent<Value> g1_children[] = { g2s1 };
2336 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2337 Persistent<Value> g2_children[] = { g3s1 };
2338 Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2339 Persistent<Value> g3_children[] = { g1s1 };
2340 V8::AddObjectGroup(g1_objects, 2);
2341 V8::AddImplicitReferences(g1s1, g1_children, 1);
2342 V8::AddObjectGroup(g2_objects, 2);
2343 V8::AddImplicitReferences(g2s1, g2_children, 1);
2344 V8::AddObjectGroup(g3_objects, 2);
2345 V8::AddImplicitReferences(g3s1, g3_children, 1);
2346 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002347 // Do a single full GC
2348 HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002349
2350 // All object should be alive.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002351 CHECK_EQ(0, counter.NumberOfWeakCalls());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002352
2353 // Weaken the root.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002354 root.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002355
2356 // Groups are deleted, rebuild groups.
2357 {
2358 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2359 Persistent<Value> g1_children[] = { g2s1 };
2360 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2361 Persistent<Value> g2_children[] = { g3s1 };
2362 Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2363 Persistent<Value> g3_children[] = { g1s1 };
2364 V8::AddObjectGroup(g1_objects, 2);
2365 V8::AddImplicitReferences(g1s1, g1_children, 1);
2366 V8::AddObjectGroup(g2_objects, 2);
2367 V8::AddImplicitReferences(g2s1, g2_children, 1);
2368 V8::AddObjectGroup(g3_objects, 2);
2369 V8::AddImplicitReferences(g3s1, g3_children, 1);
2370 }
2371
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002372 HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002373
2374 // All objects should be gone. 7 global handles in total.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002375 CHECK_EQ(7, counter.NumberOfWeakCalls());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002376}
2377
2378
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002379THREADED_TEST(ScriptException) {
2380 v8::HandleScope scope;
2381 LocalContext env;
2382 Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
2383 v8::TryCatch try_catch;
2384 Local<Value> result = script->Run();
2385 CHECK(result.IsEmpty());
2386 CHECK(try_catch.HasCaught());
2387 String::AsciiValue exception_value(try_catch.Exception());
2388 CHECK_EQ(*exception_value, "panama!");
2389}
2390
2391
2392bool message_received;
2393
2394
2395static void check_message(v8::Handle<v8::Message> message,
2396 v8::Handle<Value> data) {
2397 CHECK_EQ(5.76, data->NumberValue());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002398 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002399 CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002400 message_received = true;
2401}
2402
2403
2404THREADED_TEST(MessageHandlerData) {
2405 message_received = false;
2406 v8::HandleScope scope;
2407 CHECK(!message_received);
2408 v8::V8::AddMessageListener(check_message, v8_num(5.76));
2409 LocalContext context;
2410 v8::ScriptOrigin origin =
2411 v8::ScriptOrigin(v8_str("6.75"));
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002412 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
2413 &origin);
2414 script->SetData(v8_str("7.56"));
2415 script->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002416 CHECK(message_received);
2417 // clear out the message listener
2418 v8::V8::RemoveMessageListeners(check_message);
2419}
2420
2421
2422THREADED_TEST(GetSetProperty) {
2423 v8::HandleScope scope;
2424 LocalContext context;
2425 context->Global()->Set(v8_str("foo"), v8_num(14));
2426 context->Global()->Set(v8_str("12"), v8_num(92));
2427 context->Global()->Set(v8::Integer::New(16), v8_num(32));
2428 context->Global()->Set(v8_num(13), v8_num(56));
2429 Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
2430 CHECK_EQ(14, foo->Int32Value());
2431 Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
2432 CHECK_EQ(92, twelve->Int32Value());
2433 Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
2434 CHECK_EQ(32, sixteen->Int32Value());
2435 Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
2436 CHECK_EQ(56, thirteen->Int32Value());
2437 CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
2438 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
2439 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
2440 CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
2441 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
2442 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
2443 CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
2444 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
2445 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
2446}
2447
2448
2449THREADED_TEST(PropertyAttributes) {
2450 v8::HandleScope scope;
2451 LocalContext context;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002452 // none
2453 Local<String> prop = v8_str("none");
2454 context->Global()->Set(prop, v8_num(7));
2455 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002456 // read-only
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002457 prop = v8_str("read_only");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002458 context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
2459 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002460 CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002461 Script::Compile(v8_str("read_only = 9"))->Run();
2462 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2463 context->Global()->Set(prop, v8_num(10));
2464 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2465 // dont-delete
2466 prop = v8_str("dont_delete");
2467 context->Global()->Set(prop, v8_num(13), v8::DontDelete);
2468 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
2469 Script::Compile(v8_str("delete dont_delete"))->Run();
2470 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002471 CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
2472 // dont-enum
2473 prop = v8_str("dont_enum");
2474 context->Global()->Set(prop, v8_num(28), v8::DontEnum);
2475 CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
2476 // absent
2477 prop = v8_str("absent");
2478 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
2479 Local<Value> fake_prop = v8_num(1);
2480 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
2481 // exception
2482 TryCatch try_catch;
2483 Local<Value> exception =
2484 CompileRun("({ toString: function() { throw 'exception';} })");
2485 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
2486 CHECK(try_catch.HasCaught());
2487 String::AsciiValue exception_value(try_catch.Exception());
2488 CHECK_EQ("exception", *exception_value);
2489 try_catch.Reset();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002490}
2491
2492
2493THREADED_TEST(Array) {
2494 v8::HandleScope scope;
2495 LocalContext context;
2496 Local<v8::Array> array = v8::Array::New();
2497 CHECK_EQ(0, array->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002498 CHECK(array->Get(0)->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002499 CHECK(!array->Has(0));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002500 CHECK(array->Get(100)->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002501 CHECK(!array->Has(100));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002502 array->Set(2, v8_num(7));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002503 CHECK_EQ(3, array->Length());
2504 CHECK(!array->Has(0));
2505 CHECK(!array->Has(1));
2506 CHECK(array->Has(2));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002507 CHECK_EQ(7, array->Get(2)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002508 Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002509 Local<v8::Array> arr = obj.As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002510 CHECK_EQ(3, arr->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002511 CHECK_EQ(1, arr->Get(0)->Int32Value());
2512 CHECK_EQ(2, arr->Get(1)->Int32Value());
2513 CHECK_EQ(3, arr->Get(2)->Int32Value());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002514 array = v8::Array::New(27);
2515 CHECK_EQ(27, array->Length());
2516 array = v8::Array::New(-27);
2517 CHECK_EQ(0, array->Length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002518}
2519
2520
2521v8::Handle<Value> HandleF(const v8::Arguments& args) {
2522 v8::HandleScope scope;
2523 ApiTestFuzzer::Fuzz();
2524 Local<v8::Array> result = v8::Array::New(args.Length());
2525 for (int i = 0; i < args.Length(); i++)
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002526 result->Set(i, args[i]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002527 return scope.Close(result);
2528}
2529
2530
2531THREADED_TEST(Vector) {
2532 v8::HandleScope scope;
2533 Local<ObjectTemplate> global = ObjectTemplate::New();
2534 global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
2535 LocalContext context(0, global);
2536
2537 const char* fun = "f()";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002538 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002539 CHECK_EQ(0, a0->Length());
2540
2541 const char* fun2 = "f(11)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002542 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002543 CHECK_EQ(1, a1->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002544 CHECK_EQ(11, a1->Get(0)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002545
2546 const char* fun3 = "f(12, 13)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002547 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002548 CHECK_EQ(2, a2->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002549 CHECK_EQ(12, a2->Get(0)->Int32Value());
2550 CHECK_EQ(13, a2->Get(1)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002551
2552 const char* fun4 = "f(14, 15, 16)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002553 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002554 CHECK_EQ(3, a3->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002555 CHECK_EQ(14, a3->Get(0)->Int32Value());
2556 CHECK_EQ(15, a3->Get(1)->Int32Value());
2557 CHECK_EQ(16, a3->Get(2)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002558
2559 const char* fun5 = "f(17, 18, 19, 20)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002560 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002561 CHECK_EQ(4, a4->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002562 CHECK_EQ(17, a4->Get(0)->Int32Value());
2563 CHECK_EQ(18, a4->Get(1)->Int32Value());
2564 CHECK_EQ(19, a4->Get(2)->Int32Value());
2565 CHECK_EQ(20, a4->Get(3)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002566}
2567
2568
2569THREADED_TEST(FunctionCall) {
2570 v8::HandleScope scope;
2571 LocalContext context;
2572 CompileRun(
2573 "function Foo() {"
2574 " var result = [];"
2575 " for (var i = 0; i < arguments.length; i++) {"
2576 " result.push(arguments[i]);"
2577 " }"
2578 " return result;"
2579 "}");
2580 Local<Function> Foo =
2581 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2582
2583 v8::Handle<Value>* args0 = NULL;
2584 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
2585 CHECK_EQ(0, a0->Length());
2586
2587 v8::Handle<Value> args1[] = { v8_num(1.1) };
2588 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
2589 CHECK_EQ(1, a1->Length());
2590 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2591
2592 v8::Handle<Value> args2[] = { v8_num(2.2),
2593 v8_num(3.3) };
2594 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
2595 CHECK_EQ(2, a2->Length());
2596 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2597 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2598
2599 v8::Handle<Value> args3[] = { v8_num(4.4),
2600 v8_num(5.5),
2601 v8_num(6.6) };
2602 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
2603 CHECK_EQ(3, a3->Length());
2604 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2605 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2606 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2607
2608 v8::Handle<Value> args4[] = { v8_num(7.7),
2609 v8_num(8.8),
2610 v8_num(9.9),
2611 v8_num(10.11) };
2612 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
2613 CHECK_EQ(4, a4->Length());
2614 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2615 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2616 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2617 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2618}
2619
2620
2621static const char* js_code_causing_out_of_memory =
2622 "var a = new Array(); while(true) a.push(a);";
2623
2624
2625// These tests run for a long time and prevent us from running tests
2626// that come after them so they cannot run in parallel.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002627TEST(OutOfMemory) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002628 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002629 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002630 // Set heap limits.
2631 static const int K = 1024;
2632 v8::ResourceConstraints constraints;
2633 constraints.set_max_young_space_size(256 * K);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002634 constraints.set_max_old_space_size(4 * K * K);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002635 v8::SetResourceConstraints(&constraints);
2636
2637 // Execute a script that causes out of memory.
2638 v8::HandleScope scope;
2639 LocalContext context;
2640 v8::V8::IgnoreOutOfMemoryException();
2641 Local<Script> script =
2642 Script::Compile(String::New(js_code_causing_out_of_memory));
2643 Local<Value> result = script->Run();
2644
2645 // Check for out of memory state.
2646 CHECK(result.IsEmpty());
2647 CHECK(context->HasOutOfMemoryException());
2648}
2649
2650
2651v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
2652 ApiTestFuzzer::Fuzz();
2653
2654 v8::HandleScope scope;
2655 LocalContext context;
2656 Local<Script> script =
2657 Script::Compile(String::New(js_code_causing_out_of_memory));
2658 Local<Value> result = script->Run();
2659
2660 // Check for out of memory state.
2661 CHECK(result.IsEmpty());
2662 CHECK(context->HasOutOfMemoryException());
2663
2664 return result;
2665}
2666
2667
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002668TEST(OutOfMemoryNested) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002669 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002670 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002671 // Set heap limits.
2672 static const int K = 1024;
2673 v8::ResourceConstraints constraints;
2674 constraints.set_max_young_space_size(256 * K);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002675 constraints.set_max_old_space_size(4 * K * K);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002676 v8::SetResourceConstraints(&constraints);
2677
2678 v8::HandleScope scope;
2679 Local<ObjectTemplate> templ = ObjectTemplate::New();
2680 templ->Set(v8_str("ProvokeOutOfMemory"),
2681 v8::FunctionTemplate::New(ProvokeOutOfMemory));
2682 LocalContext context(0, templ);
2683 v8::V8::IgnoreOutOfMemoryException();
2684 Local<Value> result = CompileRun(
2685 "var thrown = false;"
2686 "try {"
2687 " ProvokeOutOfMemory();"
2688 "} catch (e) {"
2689 " thrown = true;"
2690 "}");
2691 // Check for out of memory state.
2692 CHECK(result.IsEmpty());
2693 CHECK(context->HasOutOfMemoryException());
2694}
2695
2696
2697TEST(HugeConsStringOutOfMemory) {
2698 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002699 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002700 // Set heap limits.
2701 static const int K = 1024;
2702 v8::ResourceConstraints constraints;
2703 constraints.set_max_young_space_size(256 * K);
2704 constraints.set_max_old_space_size(2 * K * K);
2705 v8::SetResourceConstraints(&constraints);
2706
2707 // Execute a script that causes out of memory.
2708 v8::V8::IgnoreOutOfMemoryException();
2709
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002710 v8::HandleScope scope;
2711 LocalContext context;
2712
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002713 // Build huge string. This should fail with out of memory exception.
2714 Local<Value> result = CompileRun(
2715 "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002716 "for (var i = 0; i < 22; i++) { str = str + str; }");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002717
2718 // Check for out of memory state.
2719 CHECK(result.IsEmpty());
2720 CHECK(context->HasOutOfMemoryException());
2721}
2722
2723
2724THREADED_TEST(ConstructCall) {
2725 v8::HandleScope scope;
2726 LocalContext context;
2727 CompileRun(
2728 "function Foo() {"
2729 " var result = [];"
2730 " for (var i = 0; i < arguments.length; i++) {"
2731 " result.push(arguments[i]);"
2732 " }"
2733 " return result;"
2734 "}");
2735 Local<Function> Foo =
2736 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2737
2738 v8::Handle<Value>* args0 = NULL;
2739 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
2740 CHECK_EQ(0, a0->Length());
2741
2742 v8::Handle<Value> args1[] = { v8_num(1.1) };
2743 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
2744 CHECK_EQ(1, a1->Length());
2745 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2746
2747 v8::Handle<Value> args2[] = { v8_num(2.2),
2748 v8_num(3.3) };
2749 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
2750 CHECK_EQ(2, a2->Length());
2751 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2752 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2753
2754 v8::Handle<Value> args3[] = { v8_num(4.4),
2755 v8_num(5.5),
2756 v8_num(6.6) };
2757 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
2758 CHECK_EQ(3, a3->Length());
2759 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2760 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2761 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2762
2763 v8::Handle<Value> args4[] = { v8_num(7.7),
2764 v8_num(8.8),
2765 v8_num(9.9),
2766 v8_num(10.11) };
2767 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
2768 CHECK_EQ(4, a4->Length());
2769 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2770 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2771 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2772 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2773}
2774
2775
2776static void CheckUncle(v8::TryCatch* try_catch) {
2777 CHECK(try_catch->HasCaught());
2778 String::AsciiValue str_value(try_catch->Exception());
2779 CHECK_EQ(*str_value, "uncle?");
2780 try_catch->Reset();
2781}
2782
2783
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002784THREADED_TEST(ConversionNumber) {
2785 v8::HandleScope scope;
2786 LocalContext env;
2787 // Very large number.
2788 CompileRun("var obj = Math.pow(2,32) * 1237;");
2789 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2790 CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
2791 CHECK_EQ(0, obj->ToInt32()->Value());
2792 CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned.
2793 // Large number.
2794 CompileRun("var obj = -1234567890123;");
2795 obj = env->Global()->Get(v8_str("obj"));
2796 CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
2797 CHECK_EQ(-1912276171, obj->ToInt32()->Value());
2798 CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT
2799 // Small positive integer.
2800 CompileRun("var obj = 42;");
2801 obj = env->Global()->Get(v8_str("obj"));
2802 CHECK_EQ(42.0, obj->ToNumber()->Value());
2803 CHECK_EQ(42, obj->ToInt32()->Value());
2804 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
2805 // Negative integer.
2806 CompileRun("var obj = -37;");
2807 obj = env->Global()->Get(v8_str("obj"));
2808 CHECK_EQ(-37.0, obj->ToNumber()->Value());
2809 CHECK_EQ(-37, obj->ToInt32()->Value());
2810 CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT
2811 // Positive non-int32 integer.
2812 CompileRun("var obj = 0x81234567;");
2813 obj = env->Global()->Get(v8_str("obj"));
2814 CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
2815 CHECK_EQ(-2128394905, obj->ToInt32()->Value());
2816 CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT
2817 // Fraction.
2818 CompileRun("var obj = 42.3;");
2819 obj = env->Global()->Get(v8_str("obj"));
2820 CHECK_EQ(42.3, obj->ToNumber()->Value());
2821 CHECK_EQ(42, obj->ToInt32()->Value());
2822 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
2823 // Large negative fraction.
2824 CompileRun("var obj = -5726623061.75;");
2825 obj = env->Global()->Get(v8_str("obj"));
2826 CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
2827 CHECK_EQ(-1431655765, obj->ToInt32()->Value());
2828 CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT
2829}
2830
2831
2832THREADED_TEST(isNumberType) {
2833 v8::HandleScope scope;
2834 LocalContext env;
2835 // Very large number.
2836 CompileRun("var obj = Math.pow(2,32) * 1237;");
2837 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2838 CHECK(!obj->IsInt32());
2839 CHECK(!obj->IsUint32());
2840 // Large negative number.
2841 CompileRun("var obj = -1234567890123;");
2842 obj = env->Global()->Get(v8_str("obj"));
2843 CHECK(!obj->IsInt32());
2844 CHECK(!obj->IsUint32());
2845 // Small positive integer.
2846 CompileRun("var obj = 42;");
2847 obj = env->Global()->Get(v8_str("obj"));
2848 CHECK(obj->IsInt32());
2849 CHECK(obj->IsUint32());
2850 // Negative integer.
2851 CompileRun("var obj = -37;");
2852 obj = env->Global()->Get(v8_str("obj"));
2853 CHECK(obj->IsInt32());
2854 CHECK(!obj->IsUint32());
2855 // Positive non-int32 integer.
2856 CompileRun("var obj = 0x81234567;");
2857 obj = env->Global()->Get(v8_str("obj"));
2858 CHECK(!obj->IsInt32());
2859 CHECK(obj->IsUint32());
2860 // Fraction.
2861 CompileRun("var obj = 42.3;");
2862 obj = env->Global()->Get(v8_str("obj"));
2863 CHECK(!obj->IsInt32());
2864 CHECK(!obj->IsUint32());
2865 // Large negative fraction.
2866 CompileRun("var obj = -5726623061.75;");
2867 obj = env->Global()->Get(v8_str("obj"));
2868 CHECK(!obj->IsInt32());
2869 CHECK(!obj->IsUint32());
2870}
2871
2872
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002873THREADED_TEST(ConversionException) {
2874 v8::HandleScope scope;
2875 LocalContext env;
2876 CompileRun(
2877 "function TestClass() { };"
2878 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
2879 "var obj = new TestClass();");
2880 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2881
2882 v8::TryCatch try_catch;
2883
2884 Local<Value> to_string_result = obj->ToString();
2885 CHECK(to_string_result.IsEmpty());
2886 CheckUncle(&try_catch);
2887
2888 Local<Value> to_number_result = obj->ToNumber();
2889 CHECK(to_number_result.IsEmpty());
2890 CheckUncle(&try_catch);
2891
2892 Local<Value> to_integer_result = obj->ToInteger();
2893 CHECK(to_integer_result.IsEmpty());
2894 CheckUncle(&try_catch);
2895
2896 Local<Value> to_uint32_result = obj->ToUint32();
2897 CHECK(to_uint32_result.IsEmpty());
2898 CheckUncle(&try_catch);
2899
2900 Local<Value> to_int32_result = obj->ToInt32();
2901 CHECK(to_int32_result.IsEmpty());
2902 CheckUncle(&try_catch);
2903
2904 Local<Value> to_object_result = v8::Undefined()->ToObject();
2905 CHECK(to_object_result.IsEmpty());
2906 CHECK(try_catch.HasCaught());
2907 try_catch.Reset();
2908
2909 int32_t int32_value = obj->Int32Value();
2910 CHECK_EQ(0, int32_value);
2911 CheckUncle(&try_catch);
2912
2913 uint32_t uint32_value = obj->Uint32Value();
2914 CHECK_EQ(0, uint32_value);
2915 CheckUncle(&try_catch);
2916
2917 double number_value = obj->NumberValue();
2918 CHECK_NE(0, IsNaN(number_value));
2919 CheckUncle(&try_catch);
2920
2921 int64_t integer_value = obj->IntegerValue();
2922 CHECK_EQ(0.0, static_cast<double>(integer_value));
2923 CheckUncle(&try_catch);
2924}
2925
2926
2927v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
2928 ApiTestFuzzer::Fuzz();
2929 return v8::ThrowException(v8_str("konto"));
2930}
2931
2932
ager@chromium.org8bb60582008-12-11 12:02:20 +00002933v8::Handle<Value> CCatcher(const v8::Arguments& args) {
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00002934 if (args.Length() < 1) return v8::False();
ager@chromium.org8bb60582008-12-11 12:02:20 +00002935 v8::HandleScope scope;
2936 v8::TryCatch try_catch;
ager@chromium.org71daaf62009-04-01 07:22:49 +00002937 Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
2938 CHECK(!try_catch.HasCaught() || result.IsEmpty());
ager@chromium.org8bb60582008-12-11 12:02:20 +00002939 return v8::Boolean::New(try_catch.HasCaught());
2940}
2941
2942
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002943THREADED_TEST(APICatch) {
2944 v8::HandleScope scope;
2945 Local<ObjectTemplate> templ = ObjectTemplate::New();
2946 templ->Set(v8_str("ThrowFromC"),
2947 v8::FunctionTemplate::New(ThrowFromC));
2948 LocalContext context(0, templ);
2949 CompileRun(
2950 "var thrown = false;"
2951 "try {"
2952 " ThrowFromC();"
2953 "} catch (e) {"
2954 " thrown = true;"
2955 "}");
2956 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
2957 CHECK(thrown->BooleanValue());
2958}
2959
2960
ager@chromium.org8bb60582008-12-11 12:02:20 +00002961THREADED_TEST(APIThrowTryCatch) {
2962 v8::HandleScope scope;
2963 Local<ObjectTemplate> templ = ObjectTemplate::New();
2964 templ->Set(v8_str("ThrowFromC"),
2965 v8::FunctionTemplate::New(ThrowFromC));
2966 LocalContext context(0, templ);
2967 v8::TryCatch try_catch;
2968 CompileRun("ThrowFromC();");
2969 CHECK(try_catch.HasCaught());
2970}
2971
2972
2973// Test that a try-finally block doesn't shadow a try-catch block
2974// when setting up an external handler.
ager@chromium.org71daaf62009-04-01 07:22:49 +00002975//
2976// BUG(271): Some of the exception propagation does not work on the
2977// ARM simulator because the simulator separates the C++ stack and the
2978// JS stack. This test therefore fails on the simulator. The test is
2979// not threaded to allow the threading tests to run on the simulator.
2980TEST(TryCatchInTryFinally) {
ager@chromium.org8bb60582008-12-11 12:02:20 +00002981 v8::HandleScope scope;
2982 Local<ObjectTemplate> templ = ObjectTemplate::New();
2983 templ->Set(v8_str("CCatcher"),
2984 v8::FunctionTemplate::New(CCatcher));
2985 LocalContext context(0, templ);
2986 Local<Value> result = CompileRun("try {"
2987 " try {"
2988 " CCatcher('throw 7;');"
2989 " } finally {"
2990 " }"
2991 "} catch (e) {"
2992 "}");
2993 CHECK(result->IsTrue());
2994}
2995
2996
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002997static void check_reference_error_message(
2998 v8::Handle<v8::Message> message,
2999 v8::Handle<v8::Value> data) {
3000 const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
3001 CHECK(message->Get()->Equals(v8_str(reference_error)));
3002}
3003
3004
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003005static v8::Handle<Value> Fail(const v8::Arguments& args) {
3006 ApiTestFuzzer::Fuzz();
3007 CHECK(false);
3008 return v8::Undefined();
3009}
3010
3011
3012// Test that overwritten methods are not invoked on uncaught exception
3013// formatting. However, they are invoked when performing normal error
3014// string conversions.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003015TEST(APIThrowMessageOverwrittenToString) {
3016 v8::HandleScope scope;
3017 v8::V8::AddMessageListener(check_reference_error_message);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003018 Local<ObjectTemplate> templ = ObjectTemplate::New();
3019 templ->Set(v8_str("fail"), v8::FunctionTemplate::New(Fail));
3020 LocalContext context(NULL, templ);
3021 CompileRun("asdf;");
3022 CompileRun("var limit = {};"
3023 "limit.valueOf = fail;"
3024 "Error.stackTraceLimit = limit;");
3025 CompileRun("asdf");
3026 CompileRun("Array.prototype.pop = fail;");
3027 CompileRun("Object.prototype.hasOwnProperty = fail;");
3028 CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
whesse@chromium.org7a392b32011-01-31 11:30:36 +00003029 CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
3030 CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003031 CompileRun("ReferenceError.prototype.toString ="
3032 " function() { return 'Whoops' }");
3033 CompileRun("asdf;");
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003034 CompileRun("ReferenceError.prototype.constructor.name = void 0;");
3035 CompileRun("asdf;");
3036 CompileRun("ReferenceError.prototype.constructor = void 0;");
3037 CompileRun("asdf;");
ager@chromium.org0ee099b2011-01-25 14:06:47 +00003038 CompileRun("ReferenceError.prototype.__proto__ = new Object();");
3039 CompileRun("asdf;");
3040 CompileRun("ReferenceError.prototype = new Object();");
3041 CompileRun("asdf;");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003042 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
3043 CHECK(string->Equals(v8_str("Whoops")));
ager@chromium.org378b34e2011-01-28 08:04:38 +00003044 CompileRun("ReferenceError.prototype.constructor = new Object();"
3045 "ReferenceError.prototype.constructor.name = 1;"
3046 "Number.prototype.toString = function() { return 'Whoops'; };"
3047 "ReferenceError.prototype.toString = Object.prototype.toString;");
3048 CompileRun("asdf;");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003049 v8::V8::RemoveMessageListeners(check_message);
3050}
3051
3052
ager@chromium.org8bb60582008-12-11 12:02:20 +00003053static void receive_message(v8::Handle<v8::Message> message,
3054 v8::Handle<v8::Value> data) {
ager@chromium.org71daaf62009-04-01 07:22:49 +00003055 message->Get();
ager@chromium.org8bb60582008-12-11 12:02:20 +00003056 message_received = true;
3057}
3058
3059
3060TEST(APIThrowMessage) {
3061 message_received = false;
3062 v8::HandleScope scope;
3063 v8::V8::AddMessageListener(receive_message);
3064 Local<ObjectTemplate> templ = ObjectTemplate::New();
3065 templ->Set(v8_str("ThrowFromC"),
3066 v8::FunctionTemplate::New(ThrowFromC));
3067 LocalContext context(0, templ);
3068 CompileRun("ThrowFromC();");
3069 CHECK(message_received);
3070 v8::V8::RemoveMessageListeners(check_message);
3071}
3072
3073
3074TEST(APIThrowMessageAndVerboseTryCatch) {
3075 message_received = false;
3076 v8::HandleScope scope;
3077 v8::V8::AddMessageListener(receive_message);
3078 Local<ObjectTemplate> templ = ObjectTemplate::New();
3079 templ->Set(v8_str("ThrowFromC"),
3080 v8::FunctionTemplate::New(ThrowFromC));
3081 LocalContext context(0, templ);
3082 v8::TryCatch try_catch;
3083 try_catch.SetVerbose(true);
ager@chromium.org71daaf62009-04-01 07:22:49 +00003084 Local<Value> result = CompileRun("ThrowFromC();");
ager@chromium.org8bb60582008-12-11 12:02:20 +00003085 CHECK(try_catch.HasCaught());
ager@chromium.org71daaf62009-04-01 07:22:49 +00003086 CHECK(result.IsEmpty());
ager@chromium.org8bb60582008-12-11 12:02:20 +00003087 CHECK(message_received);
3088 v8::V8::RemoveMessageListeners(check_message);
3089}
3090
3091
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003092TEST(APIStackOverflowAndVerboseTryCatch) {
3093 message_received = false;
3094 v8::HandleScope scope;
3095 v8::V8::AddMessageListener(receive_message);
3096 LocalContext context;
3097 v8::TryCatch try_catch;
3098 try_catch.SetVerbose(true);
3099 Local<Value> result = CompileRun("function foo() { foo(); } foo();");
3100 CHECK(try_catch.HasCaught());
3101 CHECK(result.IsEmpty());
3102 CHECK(message_received);
3103 v8::V8::RemoveMessageListeners(receive_message);
3104}
3105
3106
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003107THREADED_TEST(ExternalScriptException) {
3108 v8::HandleScope scope;
3109 Local<ObjectTemplate> templ = ObjectTemplate::New();
3110 templ->Set(v8_str("ThrowFromC"),
3111 v8::FunctionTemplate::New(ThrowFromC));
3112 LocalContext context(0, templ);
3113
3114 v8::TryCatch try_catch;
3115 Local<Script> script
3116 = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
3117 Local<Value> result = script->Run();
3118 CHECK(result.IsEmpty());
3119 CHECK(try_catch.HasCaught());
3120 String::AsciiValue exception_value(try_catch.Exception());
3121 CHECK_EQ("konto", *exception_value);
3122}
3123
3124
3125
3126v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
3127 ApiTestFuzzer::Fuzz();
3128 CHECK_EQ(4, args.Length());
3129 int count = args[0]->Int32Value();
3130 int cInterval = args[2]->Int32Value();
3131 if (count == 0) {
3132 return v8::ThrowException(v8_str("FromC"));
3133 } else {
3134 Local<v8::Object> global = Context::GetCurrent()->Global();
3135 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
3136 v8::Handle<Value> argv[] = { v8_num(count - 1),
3137 args[1],
3138 args[2],
3139 args[3] };
3140 if (count % cInterval == 0) {
3141 v8::TryCatch try_catch;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003142 Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003143 int expected = args[3]->Int32Value();
3144 if (try_catch.HasCaught()) {
3145 CHECK_EQ(expected, count);
ager@chromium.org71daaf62009-04-01 07:22:49 +00003146 CHECK(result.IsEmpty());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003147 CHECK(!i::Isolate::Current()->has_scheduled_exception());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003148 } else {
3149 CHECK_NE(expected, count);
3150 }
3151 return result;
3152 } else {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003153 return fun.As<Function>()->Call(global, 4, argv);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003154 }
3155 }
3156}
3157
3158
3159v8::Handle<Value> JSCheck(const v8::Arguments& args) {
3160 ApiTestFuzzer::Fuzz();
3161 CHECK_EQ(3, args.Length());
3162 bool equality = args[0]->BooleanValue();
3163 int count = args[1]->Int32Value();
3164 int expected = args[2]->Int32Value();
3165 if (equality) {
3166 CHECK_EQ(count, expected);
3167 } else {
3168 CHECK_NE(count, expected);
3169 }
3170 return v8::Undefined();
3171}
3172
3173
ager@chromium.org8bb60582008-12-11 12:02:20 +00003174THREADED_TEST(EvalInTryFinally) {
3175 v8::HandleScope scope;
3176 LocalContext context;
3177 v8::TryCatch try_catch;
3178 CompileRun("(function() {"
3179 " try {"
3180 " eval('asldkf (*&^&*^');"
3181 " } finally {"
3182 " return;"
3183 " }"
3184 "})()");
3185 CHECK(!try_catch.HasCaught());
3186}
3187
3188
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003189// This test works by making a stack of alternating JavaScript and C
3190// activations. These activations set up exception handlers with regular
3191// intervals, one interval for C activations and another for JavaScript
3192// activations. When enough activations have been created an exception is
3193// thrown and we check that the right activation catches the exception and that
3194// no other activations do. The right activation is always the topmost one with
3195// a handler, regardless of whether it is in JavaScript or C.
3196//
3197// The notation used to describe a test case looks like this:
3198//
3199// *JS[4] *C[3] @JS[2] C[1] JS[0]
3200//
3201// Each entry is an activation, either JS or C. The index is the count at that
3202// level. Stars identify activations with exception handlers, the @ identifies
3203// the exception handler that should catch the exception.
ager@chromium.org71daaf62009-04-01 07:22:49 +00003204//
3205// BUG(271): Some of the exception propagation does not work on the
3206// ARM simulator because the simulator separates the C++ stack and the
3207// JS stack. This test therefore fails on the simulator. The test is
3208// not threaded to allow the threading tests to run on the simulator.
3209TEST(ExceptionOrder) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003210 v8::HandleScope scope;
3211 Local<ObjectTemplate> templ = ObjectTemplate::New();
3212 templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
3213 templ->Set(v8_str("CThrowCountDown"),
3214 v8::FunctionTemplate::New(CThrowCountDown));
3215 LocalContext context(0, templ);
3216 CompileRun(
3217 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
3218 " if (count == 0) throw 'FromJS';"
3219 " if (count % jsInterval == 0) {"
3220 " try {"
3221 " var value = CThrowCountDown(count - 1,"
3222 " jsInterval,"
3223 " cInterval,"
3224 " expected);"
3225 " check(false, count, expected);"
3226 " return value;"
3227 " } catch (e) {"
3228 " check(true, count, expected);"
3229 " }"
3230 " } else {"
3231 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
3232 " }"
3233 "}");
3234 Local<Function> fun =
3235 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
3236
3237 const int argc = 4;
3238 // count jsInterval cInterval expected
3239
3240 // *JS[4] *C[3] @JS[2] C[1] JS[0]
3241 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
3242 fun->Call(fun, argc, a0);
3243
3244 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
3245 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
3246 fun->Call(fun, argc, a1);
3247
3248 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
3249 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
3250 fun->Call(fun, argc, a2);
3251
3252 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
3253 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
3254 fun->Call(fun, argc, a3);
3255
3256 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
3257 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
3258 fun->Call(fun, argc, a4);
3259
3260 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
3261 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
3262 fun->Call(fun, argc, a5);
3263}
3264
3265
3266v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
3267 ApiTestFuzzer::Fuzz();
3268 CHECK_EQ(1, args.Length());
3269 return v8::ThrowException(args[0]);
3270}
3271
3272
3273THREADED_TEST(ThrowValues) {
3274 v8::HandleScope scope;
3275 Local<ObjectTemplate> templ = ObjectTemplate::New();
3276 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
3277 LocalContext context(0, templ);
3278 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
3279 "function Run(obj) {"
3280 " try {"
3281 " Throw(obj);"
3282 " } catch (e) {"
3283 " return e;"
3284 " }"
3285 " return 'no exception';"
3286 "}"
3287 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
3288 CHECK_EQ(5, result->Length());
3289 CHECK(result->Get(v8::Integer::New(0))->IsString());
3290 CHECK(result->Get(v8::Integer::New(1))->IsNumber());
3291 CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
3292 CHECK(result->Get(v8::Integer::New(2))->IsNumber());
3293 CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
3294 CHECK(result->Get(v8::Integer::New(3))->IsNull());
3295 CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
3296}
3297
3298
3299THREADED_TEST(CatchZero) {
3300 v8::HandleScope scope;
3301 LocalContext context;
3302 v8::TryCatch try_catch;
3303 CHECK(!try_catch.HasCaught());
3304 Script::Compile(v8_str("throw 10"))->Run();
3305 CHECK(try_catch.HasCaught());
3306 CHECK_EQ(10, try_catch.Exception()->Int32Value());
3307 try_catch.Reset();
3308 CHECK(!try_catch.HasCaught());
3309 Script::Compile(v8_str("throw 0"))->Run();
3310 CHECK(try_catch.HasCaught());
3311 CHECK_EQ(0, try_catch.Exception()->Int32Value());
3312}
3313
3314
3315THREADED_TEST(CatchExceptionFromWith) {
3316 v8::HandleScope scope;
3317 LocalContext context;
3318 v8::TryCatch try_catch;
3319 CHECK(!try_catch.HasCaught());
3320 Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
3321 CHECK(try_catch.HasCaught());
3322}
3323
3324
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003325THREADED_TEST(TryCatchAndFinallyHidingException) {
3326 v8::HandleScope scope;
3327 LocalContext context;
3328 v8::TryCatch try_catch;
3329 CHECK(!try_catch.HasCaught());
3330 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
3331 CompileRun("f({toString: function() { throw 42; }});");
3332 CHECK(!try_catch.HasCaught());
3333}
3334
3335
3336v8::Handle<v8::Value> WithTryCatch(const v8::Arguments& args) {
3337 v8::TryCatch try_catch;
3338 return v8::Undefined();
3339}
3340
3341
3342THREADED_TEST(TryCatchAndFinally) {
3343 v8::HandleScope scope;
3344 LocalContext context;
3345 context->Global()->Set(
3346 v8_str("native_with_try_catch"),
3347 v8::FunctionTemplate::New(WithTryCatch)->GetFunction());
3348 v8::TryCatch try_catch;
3349 CHECK(!try_catch.HasCaught());
3350 CompileRun(
3351 "try {\n"
3352 " throw new Error('a');\n"
3353 "} finally {\n"
3354 " native_with_try_catch();\n"
3355 "}\n");
3356 CHECK(try_catch.HasCaught());
3357}
3358
3359
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003360THREADED_TEST(Equality) {
3361 v8::HandleScope scope;
3362 LocalContext context;
3363 // Check that equality works at all before relying on CHECK_EQ
3364 CHECK(v8_str("a")->Equals(v8_str("a")));
3365 CHECK(!v8_str("a")->Equals(v8_str("b")));
3366
3367 CHECK_EQ(v8_str("a"), v8_str("a"));
3368 CHECK_NE(v8_str("a"), v8_str("b"));
3369 CHECK_EQ(v8_num(1), v8_num(1));
3370 CHECK_EQ(v8_num(1.00), v8_num(1));
3371 CHECK_NE(v8_num(1), v8_num(2));
3372
3373 // Assume String is not symbol.
3374 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
3375 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
3376 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
3377 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
3378 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
3379 CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
3380 Local<Value> not_a_number = v8_num(i::OS::nan_value());
3381 CHECK(!not_a_number->StrictEquals(not_a_number));
3382 CHECK(v8::False()->StrictEquals(v8::False()));
3383 CHECK(!v8::False()->StrictEquals(v8::Undefined()));
3384
3385 v8::Handle<v8::Object> obj = v8::Object::New();
3386 v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
3387 CHECK(alias->StrictEquals(obj));
3388 alias.Dispose();
3389}
3390
3391
3392THREADED_TEST(MultiRun) {
3393 v8::HandleScope scope;
3394 LocalContext context;
3395 Local<Script> script = Script::Compile(v8_str("x"));
3396 for (int i = 0; i < 10; i++)
3397 script->Run();
3398}
3399
3400
3401static v8::Handle<Value> GetXValue(Local<String> name,
3402 const AccessorInfo& info) {
3403 ApiTestFuzzer::Fuzz();
3404 CHECK_EQ(info.Data(), v8_str("donut"));
3405 CHECK_EQ(name, v8_str("x"));
3406 return name;
3407}
3408
3409
3410THREADED_TEST(SimplePropertyRead) {
3411 v8::HandleScope scope;
3412 Local<ObjectTemplate> templ = ObjectTemplate::New();
3413 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3414 LocalContext context;
3415 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3416 Local<Script> script = Script::Compile(v8_str("obj.x"));
3417 for (int i = 0; i < 10; i++) {
3418 Local<Value> result = script->Run();
3419 CHECK_EQ(result, v8_str("x"));
3420 }
3421}
3422
ager@chromium.org5c838252010-02-19 08:53:10 +00003423THREADED_TEST(DefinePropertyOnAPIAccessor) {
3424 v8::HandleScope scope;
3425 Local<ObjectTemplate> templ = ObjectTemplate::New();
3426 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3427 LocalContext context;
3428 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3429
3430 // Uses getOwnPropertyDescriptor to check the configurable status
3431 Local<Script> script_desc
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003432 = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
ager@chromium.org5c838252010-02-19 08:53:10 +00003433 "obj, 'x');"
3434 "prop.configurable;"));
3435 Local<Value> result = script_desc->Run();
3436 CHECK_EQ(result->BooleanValue(), true);
3437
3438 // Redefine get - but still configurable
3439 Local<Script> script_define
3440 = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
3441 " configurable: true };"
3442 "Object.defineProperty(obj, 'x', desc);"
3443 "obj.x"));
3444 result = script_define->Run();
3445 CHECK_EQ(result, v8_num(42));
3446
3447 // Check that the accessor is still configurable
3448 result = script_desc->Run();
3449 CHECK_EQ(result->BooleanValue(), true);
3450
3451 // Redefine to a non-configurable
3452 script_define
3453 = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
3454 " configurable: false };"
3455 "Object.defineProperty(obj, 'x', desc);"
3456 "obj.x"));
3457 result = script_define->Run();
3458 CHECK_EQ(result, v8_num(43));
3459 result = script_desc->Run();
3460 CHECK_EQ(result->BooleanValue(), false);
3461
3462 // Make sure that it is not possible to redefine again
3463 v8::TryCatch try_catch;
3464 result = script_define->Run();
3465 CHECK(try_catch.HasCaught());
3466 String::AsciiValue exception_value(try_catch.Exception());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003467 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
ager@chromium.org5c838252010-02-19 08:53:10 +00003468}
3469
3470THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
3471 v8::HandleScope scope;
3472 Local<ObjectTemplate> templ = ObjectTemplate::New();
3473 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3474 LocalContext context;
3475 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3476
3477 Local<Script> script_desc = Script::Compile(v8_str("var prop ="
3478 "Object.getOwnPropertyDescriptor( "
3479 "obj, 'x');"
3480 "prop.configurable;"));
3481 Local<Value> result = script_desc->Run();
3482 CHECK_EQ(result->BooleanValue(), true);
3483
3484 Local<Script> script_define =
3485 Script::Compile(v8_str("var desc = {get: function(){return 42; },"
3486 " configurable: true };"
3487 "Object.defineProperty(obj, 'x', desc);"
3488 "obj.x"));
3489 result = script_define->Run();
3490 CHECK_EQ(result, v8_num(42));
3491
3492
3493 result = script_desc->Run();
3494 CHECK_EQ(result->BooleanValue(), true);
3495
3496
3497 script_define =
3498 Script::Compile(v8_str("var desc = {get: function(){return 43; },"
3499 " configurable: false };"
3500 "Object.defineProperty(obj, 'x', desc);"
3501 "obj.x"));
3502 result = script_define->Run();
3503 CHECK_EQ(result, v8_num(43));
3504 result = script_desc->Run();
3505
3506 CHECK_EQ(result->BooleanValue(), false);
3507
3508 v8::TryCatch try_catch;
3509 result = script_define->Run();
3510 CHECK(try_catch.HasCaught());
3511 String::AsciiValue exception_value(try_catch.Exception());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003512 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
ager@chromium.org5c838252010-02-19 08:53:10 +00003513}
3514
3515
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003516static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
3517 char const* name) {
3518 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
3519}
ager@chromium.org5c838252010-02-19 08:53:10 +00003520
3521
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003522THREADED_TEST(DefineAPIAccessorOnObject) {
3523 v8::HandleScope scope;
3524 Local<ObjectTemplate> templ = ObjectTemplate::New();
3525 LocalContext context;
3526
3527 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3528 CompileRun("var obj2 = {};");
3529
3530 CHECK(CompileRun("obj1.x")->IsUndefined());
3531 CHECK(CompileRun("obj2.x")->IsUndefined());
3532
3533 CHECK(GetGlobalProperty(&context, "obj1")->
3534 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3535
3536 ExpectString("obj1.x", "x");
3537 CHECK(CompileRun("obj2.x")->IsUndefined());
3538
3539 CHECK(GetGlobalProperty(&context, "obj2")->
3540 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3541
3542 ExpectString("obj1.x", "x");
3543 ExpectString("obj2.x", "x");
3544
3545 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3546 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3547
3548 CompileRun("Object.defineProperty(obj1, 'x',"
3549 "{ get: function() { return 'y'; }, configurable: true })");
3550
3551 ExpectString("obj1.x", "y");
3552 ExpectString("obj2.x", "x");
3553
3554 CompileRun("Object.defineProperty(obj2, 'x',"
3555 "{ get: function() { return 'y'; }, configurable: true })");
3556
3557 ExpectString("obj1.x", "y");
3558 ExpectString("obj2.x", "y");
3559
3560 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3561 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3562
3563 CHECK(GetGlobalProperty(&context, "obj1")->
3564 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3565 CHECK(GetGlobalProperty(&context, "obj2")->
3566 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3567
3568 ExpectString("obj1.x", "x");
3569 ExpectString("obj2.x", "x");
3570
3571 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3572 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3573
3574 // Define getters/setters, but now make them not configurable.
3575 CompileRun("Object.defineProperty(obj1, 'x',"
3576 "{ get: function() { return 'z'; }, configurable: false })");
3577 CompileRun("Object.defineProperty(obj2, 'x',"
3578 "{ get: function() { return 'z'; }, configurable: false })");
3579
3580 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3581 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3582
3583 ExpectString("obj1.x", "z");
3584 ExpectString("obj2.x", "z");
3585
3586 CHECK(!GetGlobalProperty(&context, "obj1")->
3587 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3588 CHECK(!GetGlobalProperty(&context, "obj2")->
3589 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3590
3591 ExpectString("obj1.x", "z");
3592 ExpectString("obj2.x", "z");
3593}
3594
3595
3596THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
3597 v8::HandleScope scope;
3598 Local<ObjectTemplate> templ = ObjectTemplate::New();
3599 LocalContext context;
3600
3601 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3602 CompileRun("var obj2 = {};");
3603
3604 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3605 v8_str("x"),
3606 GetXValue, NULL,
3607 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3608 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3609 v8_str("x"),
3610 GetXValue, NULL,
3611 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3612
3613 ExpectString("obj1.x", "x");
3614 ExpectString("obj2.x", "x");
3615
3616 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3617 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3618
3619 CHECK(!GetGlobalProperty(&context, "obj1")->
3620 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3621 CHECK(!GetGlobalProperty(&context, "obj2")->
3622 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3623
3624 {
3625 v8::TryCatch try_catch;
3626 CompileRun("Object.defineProperty(obj1, 'x',"
3627 "{get: function() { return 'func'; }})");
3628 CHECK(try_catch.HasCaught());
3629 String::AsciiValue exception_value(try_catch.Exception());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003630 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003631 }
3632 {
3633 v8::TryCatch try_catch;
3634 CompileRun("Object.defineProperty(obj2, 'x',"
3635 "{get: function() { return 'func'; }})");
3636 CHECK(try_catch.HasCaught());
3637 String::AsciiValue exception_value(try_catch.Exception());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003638 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003639 }
3640}
3641
3642
3643static v8::Handle<Value> Get239Value(Local<String> name,
3644 const AccessorInfo& info) {
3645 ApiTestFuzzer::Fuzz();
3646 CHECK_EQ(info.Data(), v8_str("donut"));
3647 CHECK_EQ(name, v8_str("239"));
3648 return name;
3649}
3650
3651
3652THREADED_TEST(ElementAPIAccessor) {
3653 v8::HandleScope scope;
3654 Local<ObjectTemplate> templ = ObjectTemplate::New();
3655 LocalContext context;
3656
3657 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3658 CompileRun("var obj2 = {};");
3659
3660 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3661 v8_str("239"),
3662 Get239Value, NULL,
3663 v8_str("donut")));
3664 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3665 v8_str("239"),
3666 Get239Value, NULL,
3667 v8_str("donut")));
3668
3669 ExpectString("obj1[239]", "239");
3670 ExpectString("obj2[239]", "239");
3671 ExpectString("obj1['239']", "239");
3672 ExpectString("obj2['239']", "239");
3673}
3674
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003675
3676v8::Persistent<Value> xValue;
3677
3678
3679static void SetXValue(Local<String> name,
3680 Local<Value> value,
3681 const AccessorInfo& info) {
3682 CHECK_EQ(value, v8_num(4));
3683 CHECK_EQ(info.Data(), v8_str("donut"));
3684 CHECK_EQ(name, v8_str("x"));
3685 CHECK(xValue.IsEmpty());
3686 xValue = v8::Persistent<Value>::New(value);
3687}
3688
3689
3690THREADED_TEST(SimplePropertyWrite) {
3691 v8::HandleScope scope;
3692 Local<ObjectTemplate> templ = ObjectTemplate::New();
3693 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
3694 LocalContext context;
3695 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3696 Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
3697 for (int i = 0; i < 10; i++) {
3698 CHECK(xValue.IsEmpty());
3699 script->Run();
3700 CHECK_EQ(v8_num(4), xValue);
3701 xValue.Dispose();
3702 xValue = v8::Persistent<Value>();
3703 }
3704}
3705
3706
3707static v8::Handle<Value> XPropertyGetter(Local<String> property,
3708 const AccessorInfo& info) {
3709 ApiTestFuzzer::Fuzz();
3710 CHECK(info.Data()->IsUndefined());
3711 return property;
3712}
3713
3714
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003715THREADED_TEST(NamedInterceptorPropertyRead) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003716 v8::HandleScope scope;
3717 Local<ObjectTemplate> templ = ObjectTemplate::New();
3718 templ->SetNamedPropertyHandler(XPropertyGetter);
3719 LocalContext context;
3720 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3721 Local<Script> script = Script::Compile(v8_str("obj.x"));
3722 for (int i = 0; i < 10; i++) {
3723 Local<Value> result = script->Run();
3724 CHECK_EQ(result, v8_str("x"));
3725 }
3726}
3727
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003728
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00003729THREADED_TEST(NamedInterceptorDictionaryIC) {
3730 v8::HandleScope scope;
3731 Local<ObjectTemplate> templ = ObjectTemplate::New();
3732 templ->SetNamedPropertyHandler(XPropertyGetter);
3733 LocalContext context;
3734 // Create an object with a named interceptor.
3735 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
3736 Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
3737 for (int i = 0; i < 10; i++) {
3738 Local<Value> result = script->Run();
3739 CHECK_EQ(result, v8_str("x"));
3740 }
3741 // Create a slow case object and a function accessing a property in
3742 // that slow case object (with dictionary probing in generated
3743 // code). Then force object with a named interceptor into slow-case,
3744 // pass it to the function, and check that the interceptor is called
3745 // instead of accessing the local property.
3746 Local<Value> result =
3747 CompileRun("function get_x(o) { return o.x; };"
3748 "var obj = { x : 42, y : 0 };"
3749 "delete obj.y;"
3750 "for (var i = 0; i < 10; i++) get_x(obj);"
3751 "interceptor_obj.x = 42;"
3752 "interceptor_obj.y = 10;"
3753 "delete interceptor_obj.y;"
3754 "get_x(interceptor_obj)");
3755 CHECK_EQ(result, v8_str("x"));
3756}
3757
3758
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003759THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
3760 v8::HandleScope scope;
3761
3762 v8::Persistent<Context> context1 = Context::New();
3763
3764 context1->Enter();
3765 Local<ObjectTemplate> templ = ObjectTemplate::New();
3766 templ->SetNamedPropertyHandler(XPropertyGetter);
3767 // Create an object with a named interceptor.
3768 v8::Local<v8::Object> object = templ->NewInstance();
3769 context1->Global()->Set(v8_str("interceptor_obj"), object);
3770
3771 // Force the object into the slow case.
3772 CompileRun("interceptor_obj.y = 0;"
3773 "delete interceptor_obj.y;");
3774 context1->Exit();
3775
3776 {
3777 // Introduce the object into a different context.
3778 // Repeat named loads to exercise ICs.
3779 LocalContext context2;
3780 context2->Global()->Set(v8_str("interceptor_obj"), object);
3781 Local<Value> result =
3782 CompileRun("function get_x(o) { return o.x; }"
3783 "interceptor_obj.x = 42;"
3784 "for (var i=0; i != 10; i++) {"
3785 " get_x(interceptor_obj);"
3786 "}"
3787 "get_x(interceptor_obj)");
3788 // Check that the interceptor was actually invoked.
3789 CHECK_EQ(result, v8_str("x"));
3790 }
3791
3792 // Return to the original context and force some object to the slow case
3793 // to cause the NormalizedMapCache to verify.
3794 context1->Enter();
3795 CompileRun("var obj = { x : 0 }; delete obj.x;");
3796 context1->Exit();
3797
3798 context1.Dispose();
3799}
3800
3801
ager@chromium.org5c838252010-02-19 08:53:10 +00003802static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
3803 const AccessorInfo& info) {
3804 // Set x on the prototype object and do not handle the get request.
3805 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003806 proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
ager@chromium.org5c838252010-02-19 08:53:10 +00003807 return v8::Handle<Value>();
3808}
3809
3810
3811// This is a regression test for http://crbug.com/20104. Map
3812// transitions should not interfere with post interceptor lookup.
3813THREADED_TEST(NamedInterceptorMapTransitionRead) {
3814 v8::HandleScope scope;
3815 Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
3816 Local<v8::ObjectTemplate> instance_template
3817 = function_template->InstanceTemplate();
3818 instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
3819 LocalContext context;
3820 context->Global()->Set(v8_str("F"), function_template->GetFunction());
3821 // Create an instance of F and introduce a map transition for x.
3822 CompileRun("var o = new F(); o.x = 23;");
3823 // Create an instance of F and invoke the getter. The result should be 23.
3824 Local<Value> result = CompileRun("o = new F(); o.x");
3825 CHECK_EQ(result->Int32Value(), 23);
3826}
3827
3828
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003829static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
3830 const AccessorInfo& info) {
3831 ApiTestFuzzer::Fuzz();
3832 if (index == 37) {
3833 return v8::Handle<Value>(v8_num(625));
3834 }
3835 return v8::Handle<Value>();
3836}
3837
3838
3839static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
3840 Local<Value> value,
3841 const AccessorInfo& info) {
3842 ApiTestFuzzer::Fuzz();
3843 if (index == 39) {
3844 return value;
3845 }
3846 return v8::Handle<Value>();
3847}
3848
3849
3850THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
3851 v8::HandleScope scope;
3852 Local<ObjectTemplate> templ = ObjectTemplate::New();
3853 templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
3854 IndexedPropertySetter);
3855 LocalContext context;
3856 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3857 Local<Script> getter_script = Script::Compile(v8_str(
3858 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
3859 Local<Script> setter_script = Script::Compile(v8_str(
3860 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
3861 "obj[17] = 23;"
3862 "obj.foo;"));
3863 Local<Script> interceptor_setter_script = Script::Compile(v8_str(
3864 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
3865 "obj[39] = 47;"
3866 "obj.foo;")); // This setter should not run, due to the interceptor.
3867 Local<Script> interceptor_getter_script = Script::Compile(v8_str(
3868 "obj[37];"));
3869 Local<Value> result = getter_script->Run();
3870 CHECK_EQ(v8_num(5), result);
3871 result = setter_script->Run();
3872 CHECK_EQ(v8_num(23), result);
3873 result = interceptor_setter_script->Run();
3874 CHECK_EQ(v8_num(23), result);
3875 result = interceptor_getter_script->Run();
3876 CHECK_EQ(v8_num(625), result);
3877}
3878
3879
ricow@chromium.org9fa09672011-07-25 11:05:35 +00003880static v8::Handle<Value> UnboxedDoubleIndexedPropertyGetter(
3881 uint32_t index,
3882 const AccessorInfo& info) {
3883 ApiTestFuzzer::Fuzz();
3884 if (index < 25) {
3885 return v8::Handle<Value>(v8_num(index));
3886 }
3887 return v8::Handle<Value>();
3888}
3889
3890
3891static v8::Handle<Value> UnboxedDoubleIndexedPropertySetter(
3892 uint32_t index,
3893 Local<Value> value,
3894 const AccessorInfo& info) {
3895 ApiTestFuzzer::Fuzz();
3896 if (index < 25) {
3897 return v8::Handle<Value>(v8_num(index));
3898 }
3899 return v8::Handle<Value>();
3900}
3901
3902
3903Handle<v8::Array> UnboxedDoubleIndexedPropertyEnumerator(
3904 const AccessorInfo& info) {
3905 // Force the list of returned keys to be stored in a FastDoubleArray.
3906 Local<Script> indexed_property_names_script = Script::Compile(v8_str(
3907 "keys = new Array(); keys[125000] = 1;"
3908 "for(i = 0; i < 80000; i++) { keys[i] = i; };"
3909 "keys.length = 25; keys;"));
3910 Local<Value> result = indexed_property_names_script->Run();
3911 return Local<v8::Array>(::v8::Array::Cast(*result));
3912}
3913
3914
3915// Make sure that the the interceptor code in the runtime properly handles
3916// merging property name lists for double-array-backed arrays.
3917THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
3918 v8::HandleScope scope;
3919 Local<ObjectTemplate> templ = ObjectTemplate::New();
3920 templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
3921 UnboxedDoubleIndexedPropertySetter,
3922 0,
3923 0,
3924 UnboxedDoubleIndexedPropertyEnumerator);
3925 LocalContext context;
3926 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3927 // When obj is created, force it to be Stored in a FastDoubleArray.
3928 Local<Script> create_unboxed_double_script = Script::Compile(v8_str(
3929 "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
3930 "key_count = 0; "
3931 "for (x in obj) {key_count++;};"
3932 "obj;"));
3933 Local<Value> result = create_unboxed_double_script->Run();
3934 CHECK(result->ToObject()->HasRealIndexedProperty(2000));
3935 Local<Script> key_count_check = Script::Compile(v8_str(
3936 "key_count;"));
3937 result = key_count_check->Run();
3938 CHECK_EQ(v8_num(40013), result);
3939}
3940
3941
rossberg@chromium.org28a37082011-08-22 11:03:23 +00003942Handle<v8::Array> NonStrictArgsIndexedPropertyEnumerator(
3943 const AccessorInfo& info) {
3944 // Force the list of returned keys to be stored in a Arguments object.
3945 Local<Script> indexed_property_names_script = Script::Compile(v8_str(
3946 "function f(w,x) {"
3947 " return arguments;"
3948 "}"
3949 "keys = f(0, 1, 2, 3);"
3950 "keys;"));
3951 Local<Value> result = indexed_property_names_script->Run();
3952 return Local<v8::Array>(static_cast<v8::Array*>(::v8::Object::Cast(*result)));
3953}
3954
3955
3956static v8::Handle<Value> NonStrictIndexedPropertyGetter(
3957 uint32_t index,
3958 const AccessorInfo& info) {
3959 ApiTestFuzzer::Fuzz();
3960 if (index < 4) {
3961 return v8::Handle<Value>(v8_num(index));
3962 }
3963 return v8::Handle<Value>();
3964}
3965
3966
3967// Make sure that the the interceptor code in the runtime properly handles
3968// merging property name lists for non-string arguments arrays.
3969THREADED_TEST(IndexedInterceptorNonStrictArgsWithIndexedAccessor) {
3970 v8::HandleScope scope;
3971 Local<ObjectTemplate> templ = ObjectTemplate::New();
3972 templ->SetIndexedPropertyHandler(NonStrictIndexedPropertyGetter,
3973 0,
3974 0,
3975 0,
3976 NonStrictArgsIndexedPropertyEnumerator);
3977 LocalContext context;
3978 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3979 Local<Script> create_args_script =
3980 Script::Compile(v8_str(
3981 "var key_count = 0;"
3982 "for (x in obj) {key_count++;} key_count;"));
3983 Local<Value> result = create_args_script->Run();
3984 CHECK_EQ(v8_num(4), result);
3985}
3986
3987
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00003988static v8::Handle<Value> IdentityIndexedPropertyGetter(
3989 uint32_t index,
3990 const AccessorInfo& info) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003991 return v8::Integer::NewFromUnsigned(index);
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00003992}
3993
3994
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003995THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
3996 v8::HandleScope scope;
3997 Local<ObjectTemplate> templ = ObjectTemplate::New();
3998 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3999
4000 LocalContext context;
4001 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4002
4003 // Check fast object case.
4004 const char* fast_case_code =
4005 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
4006 ExpectString(fast_case_code, "0");
4007
4008 // Check slow case.
4009 const char* slow_case_code =
4010 "obj.x = 1; delete obj.x;"
4011 "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
4012 ExpectString(slow_case_code, "1");
4013}
4014
4015
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00004016THREADED_TEST(IndexedInterceptorWithNoSetter) {
4017 v8::HandleScope scope;
4018 Local<ObjectTemplate> templ = ObjectTemplate::New();
4019 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4020
4021 LocalContext context;
4022 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4023
4024 const char* code =
4025 "try {"
4026 " obj[0] = 239;"
4027 " for (var i = 0; i < 100; i++) {"
4028 " var v = obj[0];"
4029 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
4030 " }"
4031 " 'PASSED'"
4032 "} catch(e) {"
4033 " e"
4034 "}";
4035 ExpectString(code, "PASSED");
4036}
4037
4038
ager@chromium.org5c838252010-02-19 08:53:10 +00004039THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
4040 v8::HandleScope scope;
4041 Local<ObjectTemplate> templ = ObjectTemplate::New();
4042 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4043
4044 LocalContext context;
4045 Local<v8::Object> obj = templ->NewInstance();
4046 obj->TurnOnAccessCheck();
4047 context->Global()->Set(v8_str("obj"), obj);
4048
4049 const char* code =
4050 "try {"
4051 " for (var i = 0; i < 100; i++) {"
4052 " var v = obj[0];"
4053 " if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
4054 " }"
4055 " 'PASSED'"
4056 "} catch(e) {"
4057 " e"
4058 "}";
4059 ExpectString(code, "PASSED");
4060}
4061
4062
4063THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
4064 i::FLAG_allow_natives_syntax = true;
4065 v8::HandleScope scope;
4066 Local<ObjectTemplate> templ = ObjectTemplate::New();
4067 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4068
4069 LocalContext context;
4070 Local<v8::Object> obj = templ->NewInstance();
4071 context->Global()->Set(v8_str("obj"), obj);
4072
4073 const char* code =
4074 "try {"
4075 " for (var i = 0; i < 100; i++) {"
4076 " var expected = i;"
4077 " if (i == 5) {"
4078 " %EnableAccessChecks(obj);"
4079 " expected = undefined;"
4080 " }"
4081 " var v = obj[i];"
4082 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4083 " if (i == 5) %DisableAccessChecks(obj);"
4084 " }"
4085 " 'PASSED'"
4086 "} catch(e) {"
4087 " e"
4088 "}";
4089 ExpectString(code, "PASSED");
4090}
4091
4092
4093THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
4094 v8::HandleScope scope;
4095 Local<ObjectTemplate> templ = ObjectTemplate::New();
4096 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4097
4098 LocalContext context;
4099 Local<v8::Object> obj = templ->NewInstance();
4100 context->Global()->Set(v8_str("obj"), obj);
4101
4102 const char* code =
4103 "try {"
4104 " for (var i = 0; i < 100; i++) {"
4105 " var v = obj[i];"
4106 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
4107 " }"
4108 " 'PASSED'"
4109 "} catch(e) {"
4110 " e"
4111 "}";
4112 ExpectString(code, "PASSED");
4113}
4114
4115
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00004116THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
4117 v8::HandleScope scope;
4118 Local<ObjectTemplate> templ = ObjectTemplate::New();
4119 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4120
4121 LocalContext context;
4122 Local<v8::Object> obj = templ->NewInstance();
4123 context->Global()->Set(v8_str("obj"), obj);
4124
4125 const char* code =
4126 "try {"
4127 " for (var i = 0; i < 100; i++) {"
4128 " var expected = i;"
4129 " var key = i;"
4130 " if (i == 25) {"
4131 " key = -1;"
4132 " expected = undefined;"
4133 " }"
4134 " if (i == 50) {"
4135 " /* probe minimal Smi number on 32-bit platforms */"
4136 " key = -(1 << 30);"
4137 " expected = undefined;"
4138 " }"
4139 " if (i == 75) {"
4140 " /* probe minimal Smi number on 64-bit platforms */"
4141 " key = 1 << 31;"
4142 " expected = undefined;"
4143 " }"
4144 " var v = obj[key];"
4145 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4146 " }"
4147 " 'PASSED'"
4148 "} catch(e) {"
4149 " e"
4150 "}";
4151 ExpectString(code, "PASSED");
4152}
4153
4154
ager@chromium.org5c838252010-02-19 08:53:10 +00004155THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
4156 v8::HandleScope scope;
4157 Local<ObjectTemplate> templ = ObjectTemplate::New();
4158 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4159
4160 LocalContext context;
4161 Local<v8::Object> obj = templ->NewInstance();
4162 context->Global()->Set(v8_str("obj"), obj);
4163
4164 const char* code =
4165 "try {"
4166 " for (var i = 0; i < 100; i++) {"
4167 " var expected = i;"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00004168 " var key = i;"
ager@chromium.org5c838252010-02-19 08:53:10 +00004169 " if (i == 50) {"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00004170 " key = 'foobar';"
ager@chromium.org5c838252010-02-19 08:53:10 +00004171 " expected = undefined;"
4172 " }"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00004173 " var v = obj[key];"
ager@chromium.org5c838252010-02-19 08:53:10 +00004174 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4175 " }"
4176 " 'PASSED'"
4177 "} catch(e) {"
4178 " e"
4179 "}";
4180 ExpectString(code, "PASSED");
4181}
4182
4183
4184THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
4185 v8::HandleScope scope;
4186 Local<ObjectTemplate> templ = ObjectTemplate::New();
4187 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4188
4189 LocalContext context;
4190 Local<v8::Object> obj = templ->NewInstance();
4191 context->Global()->Set(v8_str("obj"), obj);
4192
4193 const char* code =
4194 "var original = obj;"
4195 "try {"
4196 " for (var i = 0; i < 100; i++) {"
4197 " var expected = i;"
4198 " if (i == 50) {"
4199 " obj = {50: 'foobar'};"
4200 " expected = 'foobar';"
4201 " }"
4202 " var v = obj[i];"
4203 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4204 " if (i == 50) obj = original;"
4205 " }"
4206 " 'PASSED'"
4207 "} catch(e) {"
4208 " e"
4209 "}";
4210 ExpectString(code, "PASSED");
4211}
4212
4213
4214THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
4215 v8::HandleScope scope;
4216 Local<ObjectTemplate> templ = ObjectTemplate::New();
4217 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4218
4219 LocalContext context;
4220 Local<v8::Object> obj = templ->NewInstance();
4221 context->Global()->Set(v8_str("obj"), obj);
4222
4223 const char* code =
4224 "var original = obj;"
4225 "try {"
4226 " for (var i = 0; i < 100; i++) {"
4227 " var expected = i;"
4228 " if (i == 5) {"
4229 " obj = 239;"
4230 " expected = undefined;"
4231 " }"
4232 " var v = obj[i];"
4233 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4234 " if (i == 5) obj = original;"
4235 " }"
4236 " 'PASSED'"
4237 "} catch(e) {"
4238 " e"
4239 "}";
4240 ExpectString(code, "PASSED");
4241}
4242
4243
4244THREADED_TEST(IndexedInterceptorOnProto) {
4245 v8::HandleScope scope;
4246 Local<ObjectTemplate> templ = ObjectTemplate::New();
4247 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4248
4249 LocalContext context;
4250 Local<v8::Object> obj = templ->NewInstance();
4251 context->Global()->Set(v8_str("obj"), obj);
4252
4253 const char* code =
4254 "var o = {__proto__: obj};"
4255 "try {"
4256 " for (var i = 0; i < 100; i++) {"
4257 " var v = o[i];"
4258 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
4259 " }"
4260 " 'PASSED'"
4261 "} catch(e) {"
4262 " e"
4263 "}";
4264 ExpectString(code, "PASSED");
4265}
4266
4267
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004268THREADED_TEST(MultiContexts) {
4269 v8::HandleScope scope;
4270 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
4271 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
4272
4273 Local<String> password = v8_str("Password");
4274
4275 // Create an environment
4276 LocalContext context0(0, templ);
4277 context0->SetSecurityToken(password);
4278 v8::Handle<v8::Object> global0 = context0->Global();
4279 global0->Set(v8_str("custom"), v8_num(1234));
4280 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
4281
4282 // Create an independent environment
4283 LocalContext context1(0, templ);
4284 context1->SetSecurityToken(password);
4285 v8::Handle<v8::Object> global1 = context1->Global();
4286 global1->Set(v8_str("custom"), v8_num(1234));
4287 CHECK_NE(global0, global1);
4288 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
4289 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
4290
4291 // Now create a new context with the old global
4292 LocalContext context2(0, templ, global1);
4293 context2->SetSecurityToken(password);
4294 v8::Handle<v8::Object> global2 = context2->Global();
4295 CHECK_EQ(global1, global2);
4296 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
4297 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
4298}
4299
4300
4301THREADED_TEST(FunctionPrototypeAcrossContexts) {
4302 // Make sure that functions created by cloning boilerplates cannot
4303 // communicate through their __proto__ field.
4304
4305 v8::HandleScope scope;
4306
4307 LocalContext env0;
4308 v8::Handle<v8::Object> global0 =
4309 env0->Global();
4310 v8::Handle<v8::Object> object0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004311 global0->Get(v8_str("Object")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004312 v8::Handle<v8::Object> tostring0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004313 object0->Get(v8_str("toString")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004314 v8::Handle<v8::Object> proto0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004315 tostring0->Get(v8_str("__proto__")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004316 proto0->Set(v8_str("custom"), v8_num(1234));
4317
4318 LocalContext env1;
4319 v8::Handle<v8::Object> global1 =
4320 env1->Global();
4321 v8::Handle<v8::Object> object1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004322 global1->Get(v8_str("Object")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004323 v8::Handle<v8::Object> tostring1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004324 object1->Get(v8_str("toString")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004325 v8::Handle<v8::Object> proto1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004326 tostring1->Get(v8_str("__proto__")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004327 CHECK(!proto1->Has(v8_str("custom")));
4328}
4329
4330
4331THREADED_TEST(Regress892105) {
4332 // Make sure that object and array literals created by cloning
4333 // boilerplates cannot communicate through their __proto__
4334 // field. This is rather difficult to check, but we try to add stuff
4335 // to Object.prototype and Array.prototype and create a new
4336 // environment. This should succeed.
4337
4338 v8::HandleScope scope;
4339
4340 Local<String> source = v8_str("Object.prototype.obj = 1234;"
4341 "Array.prototype.arr = 4567;"
4342 "8901");
4343
4344 LocalContext env0;
4345 Local<Script> script0 = Script::Compile(source);
4346 CHECK_EQ(8901.0, script0->Run()->NumberValue());
4347
4348 LocalContext env1;
4349 Local<Script> script1 = Script::Compile(source);
4350 CHECK_EQ(8901.0, script1->Run()->NumberValue());
4351}
4352
4353
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004354THREADED_TEST(UndetectableObject) {
4355 v8::HandleScope scope;
4356 LocalContext env;
4357
4358 Local<v8::FunctionTemplate> desc =
4359 v8::FunctionTemplate::New(0, v8::Handle<Value>());
4360 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4361
4362 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4363 env->Global()->Set(v8_str("undetectable"), obj);
4364
4365 ExpectString("undetectable.toString()", "[object Object]");
4366 ExpectString("typeof undetectable", "undefined");
4367 ExpectString("typeof(undetectable)", "undefined");
4368 ExpectBoolean("typeof undetectable == 'undefined'", true);
4369 ExpectBoolean("typeof undetectable == 'object'", false);
4370 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
4371 ExpectBoolean("!undetectable", true);
4372
4373 ExpectObject("true&&undetectable", obj);
4374 ExpectBoolean("false&&undetectable", false);
4375 ExpectBoolean("true||undetectable", true);
4376 ExpectObject("false||undetectable", obj);
4377
4378 ExpectObject("undetectable&&true", obj);
4379 ExpectObject("undetectable&&false", obj);
4380 ExpectBoolean("undetectable||true", true);
4381 ExpectBoolean("undetectable||false", false);
4382
4383 ExpectBoolean("undetectable==null", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004384 ExpectBoolean("null==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004385 ExpectBoolean("undetectable==undefined", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004386 ExpectBoolean("undefined==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004387 ExpectBoolean("undetectable==undetectable", true);
4388
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004389
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004390 ExpectBoolean("undetectable===null", false);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004391 ExpectBoolean("null===undetectable", false);
4392 ExpectBoolean("undetectable===undefined", false);
4393 ExpectBoolean("undefined===undetectable", false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004394 ExpectBoolean("undetectable===undetectable", true);
4395}
4396
4397
ager@chromium.org04921a82011-06-27 13:21:41 +00004398THREADED_TEST(VoidLiteral) {
4399 v8::HandleScope scope;
4400 LocalContext env;
4401
4402 Local<v8::FunctionTemplate> desc =
4403 v8::FunctionTemplate::New(0, v8::Handle<Value>());
4404 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4405
4406 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4407 env->Global()->Set(v8_str("undetectable"), obj);
4408
4409 ExpectBoolean("undefined == void 0", true);
4410 ExpectBoolean("undetectable == void 0", true);
4411 ExpectBoolean("null == void 0", true);
4412 ExpectBoolean("undefined === void 0", true);
4413 ExpectBoolean("undetectable === void 0", false);
4414 ExpectBoolean("null === void 0", false);
4415
4416 ExpectBoolean("void 0 == undefined", true);
4417 ExpectBoolean("void 0 == undetectable", true);
4418 ExpectBoolean("void 0 == null", true);
4419 ExpectBoolean("void 0 === undefined", true);
4420 ExpectBoolean("void 0 === undetectable", false);
4421 ExpectBoolean("void 0 === null", false);
4422
4423 ExpectString("(function() {"
4424 " try {"
4425 " return x === void 0;"
4426 " } catch(e) {"
4427 " return e.toString();"
4428 " }"
4429 "})()",
4430 "ReferenceError: x is not defined");
4431 ExpectString("(function() {"
4432 " try {"
4433 " return void 0 === x;"
4434 " } catch(e) {"
4435 " return e.toString();"
4436 " }"
4437 "})()",
4438 "ReferenceError: x is not defined");
4439}
4440
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00004441
4442THREADED_TEST(ExtensibleOnUndetectable) {
4443 v8::HandleScope scope;
4444 LocalContext env;
4445
4446 Local<v8::FunctionTemplate> desc =
4447 v8::FunctionTemplate::New(0, v8::Handle<Value>());
4448 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4449
4450 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4451 env->Global()->Set(v8_str("undetectable"), obj);
4452
4453 Local<String> source = v8_str("undetectable.x = 42;"
4454 "undetectable.x");
4455
4456 Local<Script> script = Script::Compile(source);
4457
4458 CHECK_EQ(v8::Integer::New(42), script->Run());
4459
4460 ExpectBoolean("Object.isExtensible(undetectable)", true);
4461
4462 source = v8_str("Object.preventExtensions(undetectable);");
4463 script = Script::Compile(source);
4464 script->Run();
4465 ExpectBoolean("Object.isExtensible(undetectable)", false);
4466
4467 source = v8_str("undetectable.y = 2000;");
4468 script = Script::Compile(source);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004469 Local<Value> result(script->Run());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004470 ExpectBoolean("undetectable.y == undefined", true);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00004471}
4472
4473
4474
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004475THREADED_TEST(UndetectableString) {
4476 v8::HandleScope scope;
4477 LocalContext env;
4478
4479 Local<String> obj = String::NewUndetectable("foo");
4480 env->Global()->Set(v8_str("undetectable"), obj);
4481
4482 ExpectString("undetectable", "foo");
4483 ExpectString("typeof undetectable", "undefined");
4484 ExpectString("typeof(undetectable)", "undefined");
4485 ExpectBoolean("typeof undetectable == 'undefined'", true);
4486 ExpectBoolean("typeof undetectable == 'string'", false);
4487 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
4488 ExpectBoolean("!undetectable", true);
4489
4490 ExpectObject("true&&undetectable", obj);
4491 ExpectBoolean("false&&undetectable", false);
4492 ExpectBoolean("true||undetectable", true);
4493 ExpectObject("false||undetectable", obj);
4494
4495 ExpectObject("undetectable&&true", obj);
4496 ExpectObject("undetectable&&false", obj);
4497 ExpectBoolean("undetectable||true", true);
4498 ExpectBoolean("undetectable||false", false);
4499
4500 ExpectBoolean("undetectable==null", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004501 ExpectBoolean("null==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004502 ExpectBoolean("undetectable==undefined", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004503 ExpectBoolean("undefined==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004504 ExpectBoolean("undetectable==undetectable", true);
4505
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004506
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004507 ExpectBoolean("undetectable===null", false);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004508 ExpectBoolean("null===undetectable", false);
4509 ExpectBoolean("undetectable===undefined", false);
4510 ExpectBoolean("undefined===undetectable", false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004511 ExpectBoolean("undetectable===undetectable", true);
4512}
4513
4514
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004515TEST(UndetectableOptimized) {
4516 i::FLAG_allow_natives_syntax = true;
4517 v8::HandleScope scope;
4518 LocalContext env;
4519
4520 Local<String> obj = String::NewUndetectable("foo");
4521 env->Global()->Set(v8_str("undetectable"), obj);
4522 env->Global()->Set(v8_str("detectable"), v8_str("bar"));
4523
4524 ExpectString(
4525 "function testBranch() {"
4526 " if (!%_IsUndetectableObject(undetectable)) throw 1;"
4527 " if (%_IsUndetectableObject(detectable)) throw 2;"
4528 "}\n"
4529 "function testBool() {"
4530 " var b1 = !%_IsUndetectableObject(undetectable);"
4531 " var b2 = %_IsUndetectableObject(detectable);"
4532 " if (b1) throw 3;"
4533 " if (b2) throw 4;"
4534 " return b1 == b2;"
4535 "}\n"
4536 "%OptimizeFunctionOnNextCall(testBranch);"
4537 "%OptimizeFunctionOnNextCall(testBool);"
4538 "for (var i = 0; i < 10; i++) {"
4539 " testBranch();"
4540 " testBool();"
4541 "}\n"
4542 "\"PASS\"",
4543 "PASS");
4544}
4545
4546
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004547template <typename T> static void USE(T) { }
4548
4549
4550// This test is not intended to be run, just type checked.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004551static inline void PersistentHandles() {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004552 USE(PersistentHandles);
4553 Local<String> str = v8_str("foo");
4554 v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
4555 USE(p_str);
4556 Local<Script> scr = Script::Compile(v8_str(""));
4557 v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
4558 USE(p_scr);
4559 Local<ObjectTemplate> templ = ObjectTemplate::New();
4560 v8::Persistent<ObjectTemplate> p_templ =
4561 v8::Persistent<ObjectTemplate>::New(templ);
4562 USE(p_templ);
4563}
4564
4565
4566static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
4567 ApiTestFuzzer::Fuzz();
4568 return v8::Undefined();
4569}
4570
4571
4572THREADED_TEST(GlobalObjectTemplate) {
4573 v8::HandleScope handle_scope;
4574 Local<ObjectTemplate> global_template = ObjectTemplate::New();
4575 global_template->Set(v8_str("JSNI_Log"),
4576 v8::FunctionTemplate::New(HandleLogDelegator));
4577 v8::Persistent<Context> context = Context::New(0, global_template);
4578 Context::Scope context_scope(context);
4579 Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
4580 context.Dispose();
4581}
4582
4583
4584static const char* kSimpleExtensionSource =
4585 "function Foo() {"
4586 " return 4;"
4587 "}";
4588
4589
4590THREADED_TEST(SimpleExtensions) {
4591 v8::HandleScope handle_scope;
4592 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
4593 const char* extension_names[] = { "simpletest" };
4594 v8::ExtensionConfiguration extensions(1, extension_names);
4595 v8::Handle<Context> context = Context::New(&extensions);
4596 Context::Scope lock(context);
4597 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
4598 CHECK_EQ(result, v8::Integer::New(4));
4599}
4600
4601
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004602static const char* kEmbeddedExtensionSource =
4603 "function Ret54321(){return 54321;}~~@@$"
4604 "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
4605static const int kEmbeddedExtensionSourceValidLen = 34;
4606
4607
4608THREADED_TEST(ExtensionMissingSourceLength) {
4609 v8::HandleScope handle_scope;
4610 v8::RegisterExtension(new Extension("srclentest_fail",
4611 kEmbeddedExtensionSource));
4612 const char* extension_names[] = { "srclentest_fail" };
4613 v8::ExtensionConfiguration extensions(1, extension_names);
4614 v8::Handle<Context> context = Context::New(&extensions);
4615 CHECK_EQ(0, *context);
4616}
4617
4618
4619THREADED_TEST(ExtensionWithSourceLength) {
4620 for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
4621 source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
4622 v8::HandleScope handle_scope;
4623 i::ScopedVector<char> extension_name(32);
4624 i::OS::SNPrintF(extension_name, "ext #%d", source_len);
4625 v8::RegisterExtension(new Extension(extension_name.start(),
4626 kEmbeddedExtensionSource, 0, 0,
4627 source_len));
4628 const char* extension_names[1] = { extension_name.start() };
4629 v8::ExtensionConfiguration extensions(1, extension_names);
4630 v8::Handle<Context> context = Context::New(&extensions);
4631 if (source_len == kEmbeddedExtensionSourceValidLen) {
4632 Context::Scope lock(context);
4633 v8::Handle<Value> result = Script::Compile(v8_str("Ret54321()"))->Run();
4634 CHECK_EQ(v8::Integer::New(54321), result);
4635 } else {
4636 // Anything but exactly the right length should fail to compile.
4637 CHECK_EQ(0, *context);
4638 }
4639 }
4640}
4641
4642
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004643static const char* kEvalExtensionSource1 =
4644 "function UseEval1() {"
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004645 " var x = 42;"
4646 " return eval('x');"
4647 "}";
4648
4649
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004650static const char* kEvalExtensionSource2 =
4651 "(function() {"
4652 " var x = 42;"
4653 " function e() {"
4654 " return eval('x');"
4655 " }"
4656 " this.UseEval2 = e;"
4657 "})()";
4658
4659
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004660THREADED_TEST(UseEvalFromExtension) {
4661 v8::HandleScope handle_scope;
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004662 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
4663 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
4664 const char* extension_names[] = { "evaltest1", "evaltest2" };
4665 v8::ExtensionConfiguration extensions(2, extension_names);
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004666 v8::Handle<Context> context = Context::New(&extensions);
4667 Context::Scope lock(context);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004668 v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
4669 CHECK_EQ(result, v8::Integer::New(42));
4670 result = Script::Compile(v8_str("UseEval2()"))->Run();
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004671 CHECK_EQ(result, v8::Integer::New(42));
4672}
4673
4674
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004675static const char* kWithExtensionSource1 =
4676 "function UseWith1() {"
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004677 " var x = 42;"
4678 " with({x:87}) { return x; }"
4679 "}";
4680
4681
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004682
4683static const char* kWithExtensionSource2 =
4684 "(function() {"
4685 " var x = 42;"
4686 " function e() {"
4687 " with ({x:87}) { return x; }"
4688 " }"
4689 " this.UseWith2 = e;"
4690 "})()";
4691
4692
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004693THREADED_TEST(UseWithFromExtension) {
4694 v8::HandleScope handle_scope;
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004695 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
4696 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
4697 const char* extension_names[] = { "withtest1", "withtest2" };
4698 v8::ExtensionConfiguration extensions(2, extension_names);
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004699 v8::Handle<Context> context = Context::New(&extensions);
4700 Context::Scope lock(context);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004701 v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
4702 CHECK_EQ(result, v8::Integer::New(87));
4703 result = Script::Compile(v8_str("UseWith2()"))->Run();
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004704 CHECK_EQ(result, v8::Integer::New(87));
4705}
4706
4707
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004708THREADED_TEST(AutoExtensions) {
4709 v8::HandleScope handle_scope;
4710 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
4711 extension->set_auto_enable(true);
4712 v8::RegisterExtension(extension);
4713 v8::Handle<Context> context = Context::New();
4714 Context::Scope lock(context);
4715 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
4716 CHECK_EQ(result, v8::Integer::New(4));
4717}
4718
4719
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004720static const char* kSyntaxErrorInExtensionSource =
4721 "[";
4722
4723
4724// Test that a syntax error in an extension does not cause a fatal
4725// error but results in an empty context.
4726THREADED_TEST(SyntaxErrorExtensions) {
4727 v8::HandleScope handle_scope;
4728 v8::RegisterExtension(new Extension("syntaxerror",
4729 kSyntaxErrorInExtensionSource));
4730 const char* extension_names[] = { "syntaxerror" };
4731 v8::ExtensionConfiguration extensions(1, extension_names);
4732 v8::Handle<Context> context = Context::New(&extensions);
4733 CHECK(context.IsEmpty());
4734}
4735
4736
4737static const char* kExceptionInExtensionSource =
4738 "throw 42";
4739
4740
4741// Test that an exception when installing an extension does not cause
4742// a fatal error but results in an empty context.
4743THREADED_TEST(ExceptionExtensions) {
4744 v8::HandleScope handle_scope;
4745 v8::RegisterExtension(new Extension("exception",
4746 kExceptionInExtensionSource));
4747 const char* extension_names[] = { "exception" };
4748 v8::ExtensionConfiguration extensions(1, extension_names);
4749 v8::Handle<Context> context = Context::New(&extensions);
4750 CHECK(context.IsEmpty());
4751}
4752
4753
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004754static const char* kNativeCallInExtensionSource =
4755 "function call_runtime_last_index_of(x) {"
4756 " return %StringLastIndexOf(x, 'bob', 10);"
4757 "}";
4758
4759
4760static const char* kNativeCallTest =
4761 "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
4762
4763// Test that a native runtime calls are supported in extensions.
4764THREADED_TEST(NativeCallInExtensions) {
4765 v8::HandleScope handle_scope;
4766 v8::RegisterExtension(new Extension("nativecall",
4767 kNativeCallInExtensionSource));
4768 const char* extension_names[] = { "nativecall" };
4769 v8::ExtensionConfiguration extensions(1, extension_names);
4770 v8::Handle<Context> context = Context::New(&extensions);
4771 Context::Scope lock(context);
4772 v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run();
4773 CHECK_EQ(result, v8::Integer::New(3));
4774}
4775
4776
whesse@chromium.org7b260152011-06-20 15:33:18 +00004777class NativeFunctionExtension : public Extension {
4778 public:
4779 NativeFunctionExtension(const char* name,
4780 const char* source,
4781 v8::InvocationCallback fun = &Echo)
4782 : Extension(name, source),
4783 function_(fun) { }
4784
4785 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
4786 v8::Handle<v8::String> name) {
4787 return v8::FunctionTemplate::New(function_);
4788 }
4789
4790 static v8::Handle<v8::Value> Echo(const v8::Arguments& args) {
4791 if (args.Length() >= 1) return (args[0]);
4792 return v8::Undefined();
4793 }
4794 private:
4795 v8::InvocationCallback function_;
4796};
4797
4798
4799THREADED_TEST(NativeFunctionDeclaration) {
4800 v8::HandleScope handle_scope;
4801 const char* name = "nativedecl";
4802 v8::RegisterExtension(new NativeFunctionExtension(name,
4803 "native function foo();"));
4804 const char* extension_names[] = { name };
4805 v8::ExtensionConfiguration extensions(1, extension_names);
4806 v8::Handle<Context> context = Context::New(&extensions);
4807 Context::Scope lock(context);
4808 v8::Handle<Value> result = Script::Compile(v8_str("foo(42);"))->Run();
4809 CHECK_EQ(result, v8::Integer::New(42));
4810}
4811
4812
4813THREADED_TEST(NativeFunctionDeclarationError) {
4814 v8::HandleScope handle_scope;
lrn@chromium.org67e236d2011-06-23 10:18:16 +00004815 const char* name = "nativedeclerr";
whesse@chromium.org7b260152011-06-20 15:33:18 +00004816 // Syntax error in extension code.
4817 v8::RegisterExtension(new NativeFunctionExtension(name,
4818 "native\nfunction foo();"));
4819 const char* extension_names[] = { name };
4820 v8::ExtensionConfiguration extensions(1, extension_names);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004821 v8::Handle<Context> context(Context::New(&extensions));
whesse@chromium.org7b260152011-06-20 15:33:18 +00004822 ASSERT(context.IsEmpty());
4823}
4824
4825THREADED_TEST(NativeFunctionDeclarationErrorEscape) {
4826 v8::HandleScope handle_scope;
lrn@chromium.org67e236d2011-06-23 10:18:16 +00004827 const char* name = "nativedeclerresc";
whesse@chromium.org7b260152011-06-20 15:33:18 +00004828 // Syntax error in extension code - escape code in "native" means that
4829 // it's not treated as a keyword.
4830 v8::RegisterExtension(new NativeFunctionExtension(
4831 name,
4832 "nativ\\u0065 function foo();"));
4833 const char* extension_names[] = { name };
4834 v8::ExtensionConfiguration extensions(1, extension_names);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004835 v8::Handle<Context> context(Context::New(&extensions));
whesse@chromium.org7b260152011-06-20 15:33:18 +00004836 ASSERT(context.IsEmpty());
4837}
4838
4839
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004840static void CheckDependencies(const char* name, const char* expected) {
4841 v8::HandleScope handle_scope;
4842 v8::ExtensionConfiguration config(1, &name);
4843 LocalContext context(&config);
4844 CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
4845}
4846
4847
4848/*
4849 * Configuration:
4850 *
4851 * /-- B <--\
4852 * A <- -- D <-- E
4853 * \-- C <--/
4854 */
4855THREADED_TEST(ExtensionDependency) {
4856 static const char* kEDeps[] = { "D" };
4857 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
4858 static const char* kDDeps[] = { "B", "C" };
4859 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
4860 static const char* kBCDeps[] = { "A" };
4861 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
4862 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
4863 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
4864 CheckDependencies("A", "undefinedA");
4865 CheckDependencies("B", "undefinedAB");
4866 CheckDependencies("C", "undefinedAC");
4867 CheckDependencies("D", "undefinedABCD");
4868 CheckDependencies("E", "undefinedABCDE");
4869 v8::HandleScope handle_scope;
4870 static const char* exts[2] = { "C", "E" };
4871 v8::ExtensionConfiguration config(2, exts);
4872 LocalContext context(&config);
4873 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
4874}
4875
4876
4877static const char* kExtensionTestScript =
4878 "native function A();"
4879 "native function B();"
4880 "native function C();"
4881 "function Foo(i) {"
4882 " if (i == 0) return A();"
4883 " if (i == 1) return B();"
4884 " if (i == 2) return C();"
4885 "}";
4886
4887
4888static v8::Handle<Value> CallFun(const v8::Arguments& args) {
4889 ApiTestFuzzer::Fuzz();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004890 if (args.IsConstructCall()) {
4891 args.This()->Set(v8_str("data"), args.Data());
4892 return v8::Null();
4893 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004894 return args.Data();
4895}
4896
4897
4898class FunctionExtension : public Extension {
4899 public:
4900 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
4901 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
4902 v8::Handle<String> name);
4903};
4904
4905
4906static int lookup_count = 0;
4907v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
4908 v8::Handle<String> name) {
4909 lookup_count++;
4910 if (name->Equals(v8_str("A"))) {
4911 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
4912 } else if (name->Equals(v8_str("B"))) {
4913 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
4914 } else if (name->Equals(v8_str("C"))) {
4915 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
4916 } else {
4917 return v8::Handle<v8::FunctionTemplate>();
4918 }
4919}
4920
4921
4922THREADED_TEST(FunctionLookup) {
4923 v8::RegisterExtension(new FunctionExtension());
4924 v8::HandleScope handle_scope;
4925 static const char* exts[1] = { "functiontest" };
4926 v8::ExtensionConfiguration config(1, exts);
4927 LocalContext context(&config);
4928 CHECK_EQ(3, lookup_count);
4929 CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
4930 CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
4931 CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
4932}
4933
4934
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004935THREADED_TEST(NativeFunctionConstructCall) {
4936 v8::RegisterExtension(new FunctionExtension());
4937 v8::HandleScope handle_scope;
4938 static const char* exts[1] = { "functiontest" };
4939 v8::ExtensionConfiguration config(1, exts);
4940 LocalContext context(&config);
4941 for (int i = 0; i < 10; i++) {
4942 // Run a few times to ensure that allocation of objects doesn't
4943 // change behavior of a constructor function.
4944 CHECK_EQ(v8::Integer::New(8),
4945 Script::Compile(v8_str("(new A()).data"))->Run());
4946 CHECK_EQ(v8::Integer::New(7),
4947 Script::Compile(v8_str("(new B()).data"))->Run());
4948 CHECK_EQ(v8::Integer::New(6),
4949 Script::Compile(v8_str("(new C()).data"))->Run());
4950 }
4951}
4952
4953
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004954static const char* last_location;
4955static const char* last_message;
4956void StoringErrorCallback(const char* location, const char* message) {
4957 if (last_location == NULL) {
4958 last_location = location;
4959 last_message = message;
4960 }
4961}
4962
4963
4964// ErrorReporting creates a circular extensions configuration and
4965// tests that the fatal error handler gets called. This renders V8
4966// unusable and therefore this test cannot be run in parallel.
4967TEST(ErrorReporting) {
4968 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
4969 static const char* aDeps[] = { "B" };
4970 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
4971 static const char* bDeps[] = { "A" };
4972 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
4973 last_location = NULL;
4974 v8::ExtensionConfiguration config(1, bDeps);
4975 v8::Handle<Context> context = Context::New(&config);
4976 CHECK(context.IsEmpty());
4977 CHECK_NE(last_location, NULL);
4978}
4979
4980
ager@chromium.org7c537e22008-10-16 08:43:32 +00004981static const char* js_code_causing_huge_string_flattening =
4982 "var str = 'X';"
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00004983 "for (var i = 0; i < 30; i++) {"
ager@chromium.org7c537e22008-10-16 08:43:32 +00004984 " str = str + str;"
4985 "}"
4986 "str.match(/X/);";
4987
4988
4989void OOMCallback(const char* location, const char* message) {
4990 exit(0);
4991}
4992
4993
4994TEST(RegexpOutOfMemory) {
4995 // Execute a script that causes out of memory when flattening a string.
4996 v8::HandleScope scope;
4997 v8::V8::SetFatalErrorHandler(OOMCallback);
4998 LocalContext context;
4999 Local<Script> script =
5000 Script::Compile(String::New(js_code_causing_huge_string_flattening));
5001 last_location = NULL;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005002 Local<Value> result(script->Run());
ager@chromium.org7c537e22008-10-16 08:43:32 +00005003
5004 CHECK(false); // Should not return.
5005}
5006
5007
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005008static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
5009 v8::Handle<Value> data) {
5010 CHECK_EQ(v8::Undefined(), data);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005011 CHECK(message->GetScriptResourceName()->IsUndefined());
5012 CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005013 message->GetLineNumber();
5014 message->GetSourceLine();
5015}
5016
5017
5018THREADED_TEST(ErrorWithMissingScriptInfo) {
5019 v8::HandleScope scope;
5020 LocalContext context;
5021 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
5022 Script::Compile(v8_str("throw Error()"))->Run();
5023 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
5024}
5025
5026
5027int global_index = 0;
5028
5029class Snorkel {
5030 public:
5031 Snorkel() { index_ = global_index++; }
5032 int index_;
5033};
5034
5035class Whammy {
5036 public:
5037 Whammy() {
5038 cursor_ = 0;
5039 }
5040 ~Whammy() {
5041 script_.Dispose();
5042 }
5043 v8::Handle<Script> getScript() {
5044 if (script_.IsEmpty())
5045 script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
5046 return Local<Script>(*script_);
5047 }
5048
5049 public:
5050 static const int kObjectCount = 256;
5051 int cursor_;
5052 v8::Persistent<v8::Object> objects_[kObjectCount];
5053 v8::Persistent<Script> script_;
5054};
5055
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005056static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005057 Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
5058 delete snorkel;
5059 obj.ClearWeak();
5060}
5061
5062v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
5063 const AccessorInfo& info) {
5064 Whammy* whammy =
5065 static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
5066
5067 v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
5068
5069 v8::Handle<v8::Object> obj = v8::Object::New();
5070 v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
5071 if (!prev.IsEmpty()) {
5072 prev->Set(v8_str("next"), obj);
5073 prev.MakeWeak(new Snorkel(), &HandleWeakReference);
5074 whammy->objects_[whammy->cursor_].Clear();
5075 }
5076 whammy->objects_[whammy->cursor_] = global;
5077 whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
5078 return whammy->getScript()->Run();
5079}
5080
5081THREADED_TEST(WeakReference) {
5082 v8::HandleScope handle_scope;
5083 v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005084 Whammy* whammy = new Whammy();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005085 templ->SetNamedPropertyHandler(WhammyPropertyGetter,
5086 0, 0, 0, 0,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005087 v8::External::New(whammy));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005088 const char* extension_list[] = { "v8/gc" };
5089 v8::ExtensionConfiguration extensions(1, extension_list);
5090 v8::Persistent<Context> context = Context::New(&extensions);
5091 Context::Scope context_scope(context);
5092
5093 v8::Handle<v8::Object> interceptor = templ->NewInstance();
5094 context->Global()->Set(v8_str("whammy"), interceptor);
5095 const char* code =
5096 "var last;"
5097 "for (var i = 0; i < 10000; i++) {"
5098 " var obj = whammy.length;"
5099 " if (last) last.next = obj;"
5100 " last = obj;"
5101 "}"
5102 "gc();"
5103 "4";
5104 v8::Handle<Value> result = CompileRun(code);
5105 CHECK_EQ(4.0, result->NumberValue());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005106 delete whammy;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005107 context.Dispose();
5108}
5109
5110
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005111static void DisposeAndSetFlag(v8::Persistent<v8::Value> obj, void* data) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005112 obj.Dispose();
5113 obj.Clear();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005114 *(reinterpret_cast<bool*>(data)) = true;
5115}
5116
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005117
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005118THREADED_TEST(IndependentWeakHandle) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005119 v8::Persistent<Context> context = Context::New();
5120 Context::Scope context_scope(context);
5121
5122 v8::Persistent<v8::Object> object_a;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005123
5124 {
5125 v8::HandleScope handle_scope;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005126 object_a = v8::Persistent<v8::Object>::New(v8::Object::New());
5127 }
5128
5129 bool object_a_disposed = false;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005130 object_a.MakeWeak(&object_a_disposed, &DisposeAndSetFlag);
5131 object_a.MarkIndependent();
5132 HEAP->PerformScavenge();
5133 CHECK(object_a_disposed);
5134}
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005135
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005136
5137static void InvokeScavenge() {
5138 HEAP->PerformScavenge();
5139}
5140
5141
5142static void InvokeMarkSweep() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005143 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005144}
5145
5146
5147static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
5148 obj.Dispose();
5149 obj.Clear();
5150 *(reinterpret_cast<bool*>(data)) = true;
5151 InvokeScavenge();
5152}
5153
5154
5155static void ForceMarkSweep(v8::Persistent<v8::Value> obj, void* data) {
5156 obj.Dispose();
5157 obj.Clear();
5158 *(reinterpret_cast<bool*>(data)) = true;
5159 InvokeMarkSweep();
5160}
5161
5162
5163THREADED_TEST(GCFromWeakCallbacks) {
5164 v8::Persistent<Context> context = Context::New();
5165 Context::Scope context_scope(context);
5166
5167 static const int kNumberOfGCTypes = 2;
5168 v8::WeakReferenceCallback gc_forcing_callback[kNumberOfGCTypes] =
5169 {&ForceScavenge, &ForceMarkSweep};
5170
5171 typedef void (*GCInvoker)();
5172 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
5173
5174 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
5175 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
5176 v8::Persistent<v8::Object> object;
5177 {
5178 v8::HandleScope handle_scope;
5179 object = v8::Persistent<v8::Object>::New(v8::Object::New());
5180 }
5181 bool disposed = false;
5182 object.MakeWeak(&disposed, gc_forcing_callback[inner_gc]);
5183 object.MarkIndependent();
5184 invoke_gc[outer_gc]();
5185 CHECK(disposed);
5186 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005187 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005188}
5189
5190
5191static void RevivingCallback(v8::Persistent<v8::Value> obj, void* data) {
5192 obj.ClearWeak();
5193 *(reinterpret_cast<bool*>(data)) = true;
5194}
5195
5196
5197THREADED_TEST(IndependentHandleRevival) {
5198 v8::Persistent<Context> context = Context::New();
5199 Context::Scope context_scope(context);
5200
5201 v8::Persistent<v8::Object> object;
5202 {
5203 v8::HandleScope handle_scope;
5204 object = v8::Persistent<v8::Object>::New(v8::Object::New());
5205 object->Set(v8_str("x"), v8::Integer::New(1));
5206 v8::Local<String> y_str = v8_str("y");
5207 object->Set(y_str, y_str);
5208 }
5209 bool revived = false;
5210 object.MakeWeak(&revived, &RevivingCallback);
5211 object.MarkIndependent();
5212 HEAP->PerformScavenge();
5213 CHECK(revived);
5214 HEAP->CollectAllGarbage(true);
5215 {
5216 v8::HandleScope handle_scope;
5217 v8::Local<String> y_str = v8_str("y");
5218 CHECK_EQ(v8::Integer::New(1), object->Get(v8_str("x")));
5219 CHECK(object->Get(y_str)->Equals(y_str));
5220 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005221}
5222
5223
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005224v8::Handle<Function> args_fun;
5225
5226
5227static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
5228 ApiTestFuzzer::Fuzz();
5229 CHECK_EQ(args_fun, args.Callee());
5230 CHECK_EQ(3, args.Length());
5231 CHECK_EQ(v8::Integer::New(1), args[0]);
5232 CHECK_EQ(v8::Integer::New(2), args[1]);
5233 CHECK_EQ(v8::Integer::New(3), args[2]);
5234 CHECK_EQ(v8::Undefined(), args[3]);
5235 v8::HandleScope scope;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005236 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005237 return v8::Undefined();
5238}
5239
5240
5241THREADED_TEST(Arguments) {
5242 v8::HandleScope scope;
5243 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
5244 global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
5245 LocalContext context(NULL, global);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005246 args_fun = context->Global()->Get(v8_str("f")).As<Function>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005247 v8_compile("f(1, 2, 3)")->Run();
5248}
5249
5250
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005251static v8::Handle<Value> NoBlockGetterX(Local<String> name,
5252 const AccessorInfo&) {
5253 return v8::Handle<Value>();
5254}
5255
5256
5257static v8::Handle<Value> NoBlockGetterI(uint32_t index,
5258 const AccessorInfo&) {
5259 return v8::Handle<Value>();
5260}
5261
5262
5263static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
5264 const AccessorInfo&) {
5265 if (!name->Equals(v8_str("foo"))) {
5266 return v8::Handle<v8::Boolean>(); // not intercepted
5267 }
5268
5269 return v8::False(); // intercepted, and don't delete the property
5270}
5271
5272
5273static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
5274 if (index != 2) {
5275 return v8::Handle<v8::Boolean>(); // not intercepted
5276 }
5277
5278 return v8::False(); // intercepted, and don't delete the property
5279}
5280
5281
5282THREADED_TEST(Deleter) {
5283 v8::HandleScope scope;
5284 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5285 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
5286 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
5287 LocalContext context;
5288 context->Global()->Set(v8_str("k"), obj->NewInstance());
5289 CompileRun(
5290 "k.foo = 'foo';"
5291 "k.bar = 'bar';"
5292 "k[2] = 2;"
5293 "k[4] = 4;");
5294 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
5295 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
5296
5297 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
5298 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
5299
5300 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
5301 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
5302
5303 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
5304 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
5305}
5306
5307
5308static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
5309 ApiTestFuzzer::Fuzz();
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005310 if (name->Equals(v8_str("foo")) ||
5311 name->Equals(v8_str("bar")) ||
5312 name->Equals(v8_str("baz"))) {
5313 return v8::Undefined();
5314 }
5315 return v8::Handle<Value>();
5316}
5317
5318
5319static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
5320 ApiTestFuzzer::Fuzz();
5321 if (index == 0 || index == 1) return v8::Undefined();
5322 return v8::Handle<Value>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005323}
5324
5325
5326static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
5327 ApiTestFuzzer::Fuzz();
5328 v8::Handle<v8::Array> result = v8::Array::New(3);
5329 result->Set(v8::Integer::New(0), v8_str("foo"));
5330 result->Set(v8::Integer::New(1), v8_str("bar"));
5331 result->Set(v8::Integer::New(2), v8_str("baz"));
5332 return result;
5333}
5334
5335
5336static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
5337 ApiTestFuzzer::Fuzz();
5338 v8::Handle<v8::Array> result = v8::Array::New(2);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005339 result->Set(v8::Integer::New(0), v8_str("0"));
5340 result->Set(v8::Integer::New(1), v8_str("1"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005341 return result;
5342}
5343
5344
5345THREADED_TEST(Enumerators) {
5346 v8::HandleScope scope;
5347 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5348 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005349 obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005350 LocalContext context;
5351 context->Global()->Set(v8_str("k"), obj->NewInstance());
5352 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005353 "k[10] = 0;"
5354 "k.a = 0;"
5355 "k[5] = 0;"
5356 "k.b = 0;"
5357 "k[4294967295] = 0;"
5358 "k.c = 0;"
5359 "k[4294967296] = 0;"
5360 "k.d = 0;"
5361 "k[140000] = 0;"
5362 "k.e = 0;"
5363 "k[30000000000] = 0;"
5364 "k.f = 0;"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005365 "var result = [];"
5366 "for (var prop in k) {"
5367 " result.push(prop);"
5368 "}"
5369 "result"));
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005370 // Check that we get all the property names returned including the
5371 // ones from the enumerators in the right order: indexed properties
5372 // in numerical order, indexed interceptor properties, named
5373 // properties in insertion order, named interceptor properties.
5374 // This order is not mandated by the spec, so this test is just
5375 // documenting our behavior.
5376 CHECK_EQ(17, result->Length());
5377 // Indexed properties in numerical order.
5378 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
5379 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
5380 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
5381 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
5382 // Indexed interceptor properties in the order they are returned
5383 // from the enumerator interceptor.
5384 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
5385 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
5386 // Named properties in insertion order.
5387 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
5388 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
5389 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
5390 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
5391 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
5392 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
5393 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
5394 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
5395 // Named interceptor properties.
5396 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
5397 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
5398 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005399}
5400
5401
5402int p_getter_count;
5403int p_getter_count2;
5404
5405
5406static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
5407 ApiTestFuzzer::Fuzz();
5408 p_getter_count++;
5409 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5410 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
5411 if (name->Equals(v8_str("p1"))) {
5412 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
5413 } else if (name->Equals(v8_str("p2"))) {
5414 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
5415 } else if (name->Equals(v8_str("p3"))) {
5416 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
5417 } else if (name->Equals(v8_str("p4"))) {
5418 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
5419 }
5420 return v8::Undefined();
5421}
5422
5423
5424static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
5425 ApiTestFuzzer::Fuzz();
5426 LocalContext context;
5427 context->Global()->Set(v8_str("o1"), obj->NewInstance());
5428 CompileRun(
5429 "o1.__proto__ = { };"
5430 "var o2 = { __proto__: o1 };"
5431 "var o3 = { __proto__: o2 };"
5432 "var o4 = { __proto__: o3 };"
5433 "for (var i = 0; i < 10; i++) o4.p4;"
5434 "for (var i = 0; i < 10; i++) o3.p3;"
5435 "for (var i = 0; i < 10; i++) o2.p2;"
5436 "for (var i = 0; i < 10; i++) o1.p1;");
5437}
5438
5439
5440static v8::Handle<Value> PGetter2(Local<String> name,
5441 const AccessorInfo& info) {
5442 ApiTestFuzzer::Fuzz();
5443 p_getter_count2++;
5444 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5445 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
5446 if (name->Equals(v8_str("p1"))) {
5447 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
5448 } else if (name->Equals(v8_str("p2"))) {
5449 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
5450 } else if (name->Equals(v8_str("p3"))) {
5451 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
5452 } else if (name->Equals(v8_str("p4"))) {
5453 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
5454 }
5455 return v8::Undefined();
5456}
5457
5458
5459THREADED_TEST(GetterHolders) {
5460 v8::HandleScope scope;
5461 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5462 obj->SetAccessor(v8_str("p1"), PGetter);
5463 obj->SetAccessor(v8_str("p2"), PGetter);
5464 obj->SetAccessor(v8_str("p3"), PGetter);
5465 obj->SetAccessor(v8_str("p4"), PGetter);
5466 p_getter_count = 0;
5467 RunHolderTest(obj);
5468 CHECK_EQ(40, p_getter_count);
5469}
5470
5471
5472THREADED_TEST(PreInterceptorHolders) {
5473 v8::HandleScope scope;
5474 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5475 obj->SetNamedPropertyHandler(PGetter2);
5476 p_getter_count2 = 0;
5477 RunHolderTest(obj);
5478 CHECK_EQ(40, p_getter_count2);
5479}
5480
5481
5482THREADED_TEST(ObjectInstantiation) {
5483 v8::HandleScope scope;
5484 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5485 templ->SetAccessor(v8_str("t"), PGetter2);
5486 LocalContext context;
5487 context->Global()->Set(v8_str("o"), templ->NewInstance());
5488 for (int i = 0; i < 100; i++) {
5489 v8::HandleScope inner_scope;
5490 v8::Handle<v8::Object> obj = templ->NewInstance();
5491 CHECK_NE(obj, context->Global()->Get(v8_str("o")));
5492 context->Global()->Set(v8_str("o2"), obj);
5493 v8::Handle<Value> value =
5494 Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
5495 CHECK_EQ(v8::True(), value);
5496 context->Global()->Set(v8_str("o"), obj);
5497 }
5498}
5499
5500
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005501static int StrCmp16(uint16_t* a, uint16_t* b) {
5502 while (true) {
5503 if (*a == 0 && *b == 0) return 0;
5504 if (*a != *b) return 0 + *a - *b;
5505 a++;
5506 b++;
5507 }
5508}
5509
5510
5511static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
5512 while (true) {
5513 if (n-- == 0) return 0;
5514 if (*a == 0 && *b == 0) return 0;
5515 if (*a != *b) return 0 + *a - *b;
5516 a++;
5517 b++;
5518 }
5519}
5520
5521
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005522THREADED_TEST(StringWrite) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005523 LocalContext context;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005524 v8::HandleScope scope;
5525 v8::Handle<String> str = v8_str("abcde");
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005526 // abc<Icelandic eth><Unicode snowman>.
5527 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005528 const int kStride = 4; // Must match stride in for loops in JS below.
5529 CompileRun(
5530 "var left = '';"
5531 "for (var i = 0; i < 0xd800; i += 4) {"
5532 " left = left + String.fromCharCode(i);"
5533 "}");
5534 CompileRun(
5535 "var right = '';"
5536 "for (var i = 0; i < 0xd800; i += 4) {"
5537 " right = String.fromCharCode(i) + right;"
5538 "}");
5539 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5540 Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
5541 Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005542
5543 CHECK_EQ(5, str2->Length());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005544 CHECK_EQ(0xd800 / kStride, left_tree->Length());
5545 CHECK_EQ(0xd800 / kStride, right_tree->Length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005546
5547 char buf[100];
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005548 char utf8buf[0xd800 * 3];
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005549 uint16_t wbuf[100];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005550 int len;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005551 int charlen;
5552
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005553 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005554 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005555 CHECK_EQ(9, len);
5556 CHECK_EQ(5, charlen);
5557 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005558
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005559 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005560 len = str2->WriteUtf8(utf8buf, 8, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005561 CHECK_EQ(8, len);
5562 CHECK_EQ(5, charlen);
5563 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005564
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005565 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005566 len = str2->WriteUtf8(utf8buf, 7, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005567 CHECK_EQ(5, len);
5568 CHECK_EQ(4, charlen);
5569 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005570
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005571 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005572 len = str2->WriteUtf8(utf8buf, 6, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005573 CHECK_EQ(5, len);
5574 CHECK_EQ(4, charlen);
5575 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005576
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005577 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005578 len = str2->WriteUtf8(utf8buf, 5, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005579 CHECK_EQ(5, len);
5580 CHECK_EQ(4, charlen);
5581 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005582
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005583 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005584 len = str2->WriteUtf8(utf8buf, 4, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005585 CHECK_EQ(3, len);
5586 CHECK_EQ(3, charlen);
5587 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005588
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005589 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005590 len = str2->WriteUtf8(utf8buf, 3, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005591 CHECK_EQ(3, len);
5592 CHECK_EQ(3, charlen);
5593 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005594
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005595 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005596 len = str2->WriteUtf8(utf8buf, 2, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005597 CHECK_EQ(2, len);
5598 CHECK_EQ(2, charlen);
5599 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005600
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005601 memset(utf8buf, 0x1, sizeof(utf8buf));
5602 len = left_tree->Utf8Length();
5603 int utf8_expected =
5604 (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
5605 CHECK_EQ(utf8_expected, len);
5606 len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
5607 CHECK_EQ(utf8_expected, len);
5608 CHECK_EQ(0xd800 / kStride, charlen);
5609 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
5610 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
5611 CHECK_EQ(0xc0 - kStride,
5612 static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
5613 CHECK_EQ(1, utf8buf[utf8_expected]);
5614
5615 memset(utf8buf, 0x1, sizeof(utf8buf));
5616 len = right_tree->Utf8Length();
5617 CHECK_EQ(utf8_expected, len);
5618 len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
5619 CHECK_EQ(utf8_expected, len);
5620 CHECK_EQ(0xd800 / kStride, charlen);
5621 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
5622 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
5623 CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
5624 CHECK_EQ(1, utf8buf[utf8_expected]);
5625
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005626 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005627 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005628 len = str->WriteAscii(buf);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005629 CHECK_EQ(5, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005630 len = str->Write(wbuf);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005631 CHECK_EQ(5, len);
5632 CHECK_EQ(0, strcmp("abcde", buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005633 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005634 CHECK_EQ(0, StrCmp16(answer1, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005635
5636 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005637 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005638 len = str->WriteAscii(buf, 0, 4);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005639 CHECK_EQ(4, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005640 len = str->Write(wbuf, 0, 4);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005641 CHECK_EQ(4, len);
5642 CHECK_EQ(0, strncmp("abcd\1", buf, 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005643 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005644 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005645
5646 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005647 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005648 len = str->WriteAscii(buf, 0, 5);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005649 CHECK_EQ(5, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005650 len = str->Write(wbuf, 0, 5);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005651 CHECK_EQ(5, len);
5652 CHECK_EQ(0, strncmp("abcde\1", buf, 6));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005653 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005654 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005655
5656 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005657 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005658 len = str->WriteAscii(buf, 0, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005659 CHECK_EQ(5, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005660 len = str->Write(wbuf, 0, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005661 CHECK_EQ(5, len);
5662 CHECK_EQ(0, strcmp("abcde", buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005663 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005664 CHECK_EQ(0, StrCmp16(answer4, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005665
5666 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005667 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005668 len = str->WriteAscii(buf, 4, -1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005669 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005670 len = str->Write(wbuf, 4, -1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005671 CHECK_EQ(1, len);
5672 CHECK_EQ(0, strcmp("e", buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005673 uint16_t answer5[] = {'e', '\0'};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005674 CHECK_EQ(0, StrCmp16(answer5, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005675
5676 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005677 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005678 len = str->WriteAscii(buf, 4, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005679 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005680 len = str->Write(wbuf, 4, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005681 CHECK_EQ(1, len);
5682 CHECK_EQ(0, strcmp("e", buf));
5683 CHECK_EQ(0, StrCmp16(answer5, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005684
5685 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005686 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005687 len = str->WriteAscii(buf, 4, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005688 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005689 len = str->Write(wbuf, 4, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005690 CHECK_EQ(1, len);
5691 CHECK_EQ(0, strncmp("e\1", buf, 2));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005692 uint16_t answer6[] = {'e', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005693 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005694
5695 memset(buf, 0x1, sizeof(buf));
5696 memset(wbuf, 0x1, sizeof(wbuf));
5697 len = str->WriteAscii(buf, 3, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005698 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005699 len = str->Write(wbuf, 3, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005700 CHECK_EQ(1, len);
5701 CHECK_EQ(0, strncmp("d\1", buf, 2));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005702 uint16_t answer7[] = {'d', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005703 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005704
5705 memset(wbuf, 0x1, sizeof(wbuf));
5706 wbuf[5] = 'X';
5707 len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
5708 CHECK_EQ(5, len);
5709 CHECK_EQ('X', wbuf[5]);
5710 uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
5711 uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
5712 CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
5713 CHECK_NE(0, StrCmp16(answer8b, wbuf));
5714 wbuf[5] = '\0';
5715 CHECK_EQ(0, StrCmp16(answer8b, wbuf));
5716
5717 memset(buf, 0x1, sizeof(buf));
5718 buf[5] = 'X';
5719 len = str->WriteAscii(buf, 0, 6, String::NO_NULL_TERMINATION);
5720 CHECK_EQ(5, len);
5721 CHECK_EQ('X', buf[5]);
5722 CHECK_EQ(0, strncmp("abcde", buf, 5));
5723 CHECK_NE(0, strcmp("abcde", buf));
5724 buf[5] = '\0';
5725 CHECK_EQ(0, strcmp("abcde", buf));
5726
5727 memset(utf8buf, 0x1, sizeof(utf8buf));
5728 utf8buf[8] = 'X';
5729 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
5730 String::NO_NULL_TERMINATION);
5731 CHECK_EQ(8, len);
5732 CHECK_EQ('X', utf8buf[8]);
5733 CHECK_EQ(5, charlen);
5734 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
5735 CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
5736 utf8buf[8] = '\0';
5737 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005738}
5739
5740
5741THREADED_TEST(ToArrayIndex) {
5742 v8::HandleScope scope;
5743 LocalContext context;
5744
5745 v8::Handle<String> str = v8_str("42");
5746 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
5747 CHECK(!index.IsEmpty());
5748 CHECK_EQ(42.0, index->Uint32Value());
5749 str = v8_str("42asdf");
5750 index = str->ToArrayIndex();
5751 CHECK(index.IsEmpty());
5752 str = v8_str("-42");
5753 index = str->ToArrayIndex();
5754 CHECK(index.IsEmpty());
5755 str = v8_str("4294967295");
5756 index = str->ToArrayIndex();
5757 CHECK(!index.IsEmpty());
5758 CHECK_EQ(4294967295.0, index->Uint32Value());
5759 v8::Handle<v8::Number> num = v8::Number::New(1);
5760 index = num->ToArrayIndex();
5761 CHECK(!index.IsEmpty());
5762 CHECK_EQ(1.0, index->Uint32Value());
5763 num = v8::Number::New(-1);
5764 index = num->ToArrayIndex();
5765 CHECK(index.IsEmpty());
5766 v8::Handle<v8::Object> obj = v8::Object::New();
5767 index = obj->ToArrayIndex();
5768 CHECK(index.IsEmpty());
5769}
5770
5771
5772THREADED_TEST(ErrorConstruction) {
5773 v8::HandleScope scope;
5774 LocalContext context;
5775
5776 v8::Handle<String> foo = v8_str("foo");
5777 v8::Handle<String> message = v8_str("message");
5778 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
5779 CHECK(range_error->IsObject());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005780 v8::Handle<v8::Object> range_obj(range_error.As<v8::Object>());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005781 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005782 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
5783 CHECK(reference_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005784 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005785 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
5786 CHECK(syntax_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005787 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005788 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
5789 CHECK(type_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005790 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005791 v8::Handle<Value> error = v8::Exception::Error(foo);
5792 CHECK(error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005793 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005794}
5795
5796
5797static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
5798 ApiTestFuzzer::Fuzz();
5799 return v8_num(10);
5800}
5801
5802
5803static void YSetter(Local<String> name,
5804 Local<Value> value,
5805 const AccessorInfo& info) {
5806 if (info.This()->Has(name)) {
5807 info.This()->Delete(name);
5808 }
5809 info.This()->Set(name, value);
5810}
5811
5812
5813THREADED_TEST(DeleteAccessor) {
5814 v8::HandleScope scope;
5815 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5816 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
5817 LocalContext context;
5818 v8::Handle<v8::Object> holder = obj->NewInstance();
5819 context->Global()->Set(v8_str("holder"), holder);
5820 v8::Handle<Value> result = CompileRun(
5821 "holder.y = 11; holder.y = 12; holder.y");
5822 CHECK_EQ(12, result->Uint32Value());
5823}
5824
5825
5826THREADED_TEST(TypeSwitch) {
5827 v8::HandleScope scope;
5828 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
5829 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
5830 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
5831 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
5832 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
5833 LocalContext context;
5834 v8::Handle<v8::Object> obj0 = v8::Object::New();
5835 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
5836 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
5837 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
5838 for (int i = 0; i < 10; i++) {
5839 CHECK_EQ(0, type_switch->match(obj0));
5840 CHECK_EQ(1, type_switch->match(obj1));
5841 CHECK_EQ(2, type_switch->match(obj2));
5842 CHECK_EQ(3, type_switch->match(obj3));
5843 CHECK_EQ(3, type_switch->match(obj3));
5844 CHECK_EQ(2, type_switch->match(obj2));
5845 CHECK_EQ(1, type_switch->match(obj1));
5846 CHECK_EQ(0, type_switch->match(obj0));
5847 }
5848}
5849
5850
5851// For use within the TestSecurityHandler() test.
5852static bool g_security_callback_result = false;
5853static bool NamedSecurityTestCallback(Local<v8::Object> global,
5854 Local<Value> name,
5855 v8::AccessType type,
5856 Local<Value> data) {
5857 // Always allow read access.
5858 if (type == v8::ACCESS_GET)
5859 return true;
5860
5861 // Sometimes allow other access.
5862 return g_security_callback_result;
5863}
5864
5865
5866static bool IndexedSecurityTestCallback(Local<v8::Object> global,
5867 uint32_t key,
5868 v8::AccessType type,
5869 Local<Value> data) {
5870 // Always allow read access.
5871 if (type == v8::ACCESS_GET)
5872 return true;
5873
5874 // Sometimes allow other access.
5875 return g_security_callback_result;
5876}
5877
5878
5879static int trouble_nesting = 0;
5880static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
5881 ApiTestFuzzer::Fuzz();
5882 trouble_nesting++;
5883
5884 // Call a JS function that throws an uncaught exception.
5885 Local<v8::Object> arg_this = Context::GetCurrent()->Global();
5886 Local<Value> trouble_callee = (trouble_nesting == 3) ?
5887 arg_this->Get(v8_str("trouble_callee")) :
5888 arg_this->Get(v8_str("trouble_caller"));
5889 CHECK(trouble_callee->IsFunction());
5890 return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
5891}
5892
5893
5894static int report_count = 0;
5895static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
5896 v8::Handle<Value>) {
5897 report_count++;
5898}
5899
5900
5901// Counts uncaught exceptions, but other tests running in parallel
5902// also have uncaught exceptions.
5903TEST(ApiUncaughtException) {
ager@chromium.org8bb60582008-12-11 12:02:20 +00005904 report_count = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005905 v8::HandleScope scope;
5906 LocalContext env;
5907 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
5908
5909 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
5910 v8::Local<v8::Object> global = env->Global();
5911 global->Set(v8_str("trouble"), fun->GetFunction());
5912
5913 Script::Compile(v8_str("function trouble_callee() {"
5914 " var x = null;"
5915 " return x.foo;"
5916 "};"
5917 "function trouble_caller() {"
5918 " trouble();"
5919 "};"))->Run();
5920 Local<Value> trouble = global->Get(v8_str("trouble"));
5921 CHECK(trouble->IsFunction());
5922 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
5923 CHECK(trouble_callee->IsFunction());
5924 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
5925 CHECK(trouble_caller->IsFunction());
5926 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
5927 CHECK_EQ(1, report_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00005928 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
5929}
5930
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005931static const char* script_resource_name = "ExceptionInNativeScript.js";
5932static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
5933 v8::Handle<Value>) {
5934 v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
5935 CHECK(!name_val.IsEmpty() && name_val->IsString());
5936 v8::String::AsciiValue name(message->GetScriptResourceName());
5937 CHECK_EQ(script_resource_name, *name);
5938 CHECK_EQ(3, message->GetLineNumber());
5939 v8::String::AsciiValue source_line(message->GetSourceLine());
5940 CHECK_EQ(" new o.foo();", *source_line);
5941}
5942
5943TEST(ExceptionInNativeScript) {
5944 v8::HandleScope scope;
5945 LocalContext env;
5946 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
5947
5948 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
5949 v8::Local<v8::Object> global = env->Global();
5950 global->Set(v8_str("trouble"), fun->GetFunction());
5951
5952 Script::Compile(v8_str("function trouble() {\n"
5953 " var o = {};\n"
5954 " new o.foo();\n"
5955 "};"), v8::String::New(script_resource_name))->Run();
5956 Local<Value> trouble = global->Get(v8_str("trouble"));
5957 CHECK(trouble->IsFunction());
5958 Function::Cast(*trouble)->Call(global, 0, NULL);
5959 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
5960}
5961
ager@chromium.org8bb60582008-12-11 12:02:20 +00005962
5963TEST(CompilationErrorUsingTryCatchHandler) {
5964 v8::HandleScope scope;
5965 LocalContext env;
5966 v8::TryCatch try_catch;
5967 Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
5968 CHECK_NE(NULL, *try_catch.Exception());
5969 CHECK(try_catch.HasCaught());
5970}
5971
5972
5973TEST(TryCatchFinallyUsingTryCatchHandler) {
5974 v8::HandleScope scope;
5975 LocalContext env;
5976 v8::TryCatch try_catch;
5977 Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
5978 CHECK(!try_catch.HasCaught());
5979 Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
5980 CHECK(try_catch.HasCaught());
5981 try_catch.Reset();
5982 Script::Compile(v8_str("(function() {"
5983 "try { throw ''; } finally { return; }"
5984 "})()"))->Run();
5985 CHECK(!try_catch.HasCaught());
5986 Script::Compile(v8_str("(function()"
5987 " { try { throw ''; } finally { throw 0; }"
5988 "})()"))->Run();
5989 CHECK(try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005990}
5991
5992
5993// SecurityHandler can't be run twice
5994TEST(SecurityHandler) {
5995 v8::HandleScope scope0;
5996 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
5997 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
5998 IndexedSecurityTestCallback);
5999 // Create an environment
6000 v8::Persistent<Context> context0 =
6001 Context::New(NULL, global_template);
6002 context0->Enter();
6003
6004 v8::Handle<v8::Object> global0 = context0->Global();
6005 v8::Handle<Script> script0 = v8_compile("foo = 111");
6006 script0->Run();
6007 global0->Set(v8_str("0"), v8_num(999));
6008 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
6009 CHECK_EQ(111, foo0->Int32Value());
6010 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
6011 CHECK_EQ(999, z0->Int32Value());
6012
6013 // Create another environment, should fail security checks.
6014 v8::HandleScope scope1;
6015
6016 v8::Persistent<Context> context1 =
6017 Context::New(NULL, global_template);
6018 context1->Enter();
6019
6020 v8::Handle<v8::Object> global1 = context1->Global();
6021 global1->Set(v8_str("othercontext"), global0);
6022 // This set will fail the security check.
6023 v8::Handle<Script> script1 =
6024 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
6025 script1->Run();
6026 // This read will pass the security check.
6027 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
6028 CHECK_EQ(111, foo1->Int32Value());
6029 // This read will pass the security check.
6030 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
6031 CHECK_EQ(999, z1->Int32Value());
6032
6033 // Create another environment, should pass security checks.
6034 { g_security_callback_result = true; // allow security handler to pass.
6035 v8::HandleScope scope2;
6036 LocalContext context2;
6037 v8::Handle<v8::Object> global2 = context2->Global();
6038 global2->Set(v8_str("othercontext"), global0);
6039 v8::Handle<Script> script2 =
6040 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
6041 script2->Run();
6042 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
6043 CHECK_EQ(333, foo2->Int32Value());
6044 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
6045 CHECK_EQ(888, z2->Int32Value());
6046 }
6047
6048 context1->Exit();
6049 context1.Dispose();
6050
6051 context0->Exit();
6052 context0.Dispose();
6053}
6054
6055
6056THREADED_TEST(SecurityChecks) {
6057 v8::HandleScope handle_scope;
6058 LocalContext env1;
6059 v8::Persistent<Context> env2 = Context::New();
6060
6061 Local<Value> foo = v8_str("foo");
6062 Local<Value> bar = v8_str("bar");
6063
6064 // Set to the same domain.
6065 env1->SetSecurityToken(foo);
6066
6067 // Create a function in env1.
6068 Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
6069 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
6070 CHECK(spy->IsFunction());
6071
6072 // Create another function accessing global objects.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006073 Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006074 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
6075 CHECK(spy2->IsFunction());
6076
6077 // Switch to env2 in the same domain and invoke spy on env2.
6078 {
6079 env2->SetSecurityToken(foo);
6080 // Enter env2
6081 Context::Scope scope_env2(env2);
6082 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
6083 CHECK(result->IsFunction());
6084 }
6085
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006086 {
6087 env2->SetSecurityToken(bar);
6088 Context::Scope scope_env2(env2);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006089
6090 // Call cross_domain_call, it should throw an exception
6091 v8::TryCatch try_catch;
6092 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
6093 CHECK(try_catch.HasCaught());
6094 }
6095
6096 env2.Dispose();
6097}
6098
6099
6100// Regression test case for issue 1183439.
6101THREADED_TEST(SecurityChecksForPrototypeChain) {
6102 v8::HandleScope scope;
6103 LocalContext current;
6104 v8::Persistent<Context> other = Context::New();
6105
6106 // Change context to be able to get to the Object function in the
6107 // other context without hitting the security checks.
6108 v8::Local<Value> other_object;
6109 { Context::Scope scope(other);
6110 other_object = other->Global()->Get(v8_str("Object"));
6111 other->Global()->Set(v8_num(42), v8_num(87));
6112 }
6113
6114 current->Global()->Set(v8_str("other"), other->Global());
6115 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
6116
6117 // Make sure the security check fails here and we get an undefined
6118 // result instead of getting the Object function. Repeat in a loop
6119 // to make sure to exercise the IC code.
6120 v8::Local<Script> access_other0 = v8_compile("other.Object");
6121 v8::Local<Script> access_other1 = v8_compile("other[42]");
6122 for (int i = 0; i < 5; i++) {
6123 CHECK(!access_other0->Run()->Equals(other_object));
6124 CHECK(access_other0->Run()->IsUndefined());
6125 CHECK(!access_other1->Run()->Equals(v8_num(87)));
6126 CHECK(access_other1->Run()->IsUndefined());
6127 }
6128
6129 // Create an object that has 'other' in its prototype chain and make
6130 // sure we cannot access the Object function indirectly through
6131 // that. Repeat in a loop to make sure to exercise the IC code.
6132 v8_compile("function F() { };"
6133 "F.prototype = other;"
6134 "var f = new F();")->Run();
6135 v8::Local<Script> access_f0 = v8_compile("f.Object");
6136 v8::Local<Script> access_f1 = v8_compile("f[42]");
6137 for (int j = 0; j < 5; j++) {
6138 CHECK(!access_f0->Run()->Equals(other_object));
6139 CHECK(access_f0->Run()->IsUndefined());
6140 CHECK(!access_f1->Run()->Equals(v8_num(87)));
6141 CHECK(access_f1->Run()->IsUndefined());
6142 }
6143
6144 // Now it gets hairy: Set the prototype for the other global object
6145 // to be the current global object. The prototype chain for 'f' now
6146 // goes through 'other' but ends up in the current global object.
6147 { Context::Scope scope(other);
6148 other->Global()->Set(v8_str("__proto__"), current->Global());
6149 }
6150 // Set a named and an index property on the current global
6151 // object. To force the lookup to go through the other global object,
6152 // the properties must not exist in the other global object.
6153 current->Global()->Set(v8_str("foo"), v8_num(100));
6154 current->Global()->Set(v8_num(99), v8_num(101));
6155 // Try to read the properties from f and make sure that the access
6156 // gets stopped by the security checks on the other global object.
6157 Local<Script> access_f2 = v8_compile("f.foo");
6158 Local<Script> access_f3 = v8_compile("f[99]");
6159 for (int k = 0; k < 5; k++) {
6160 CHECK(!access_f2->Run()->Equals(v8_num(100)));
6161 CHECK(access_f2->Run()->IsUndefined());
6162 CHECK(!access_f3->Run()->Equals(v8_num(101)));
6163 CHECK(access_f3->Run()->IsUndefined());
6164 }
6165 other.Dispose();
6166}
6167
6168
6169THREADED_TEST(CrossDomainDelete) {
6170 v8::HandleScope handle_scope;
6171 LocalContext env1;
6172 v8::Persistent<Context> env2 = Context::New();
6173
6174 Local<Value> foo = v8_str("foo");
6175 Local<Value> bar = v8_str("bar");
6176
6177 // Set to the same domain.
6178 env1->SetSecurityToken(foo);
6179 env2->SetSecurityToken(foo);
6180
6181 env1->Global()->Set(v8_str("prop"), v8_num(3));
6182 env2->Global()->Set(v8_str("env1"), env1->Global());
6183
6184 // Change env2 to a different domain and delete env1.prop.
6185 env2->SetSecurityToken(bar);
6186 {
6187 Context::Scope scope_env2(env2);
6188 Local<Value> result =
6189 Script::Compile(v8_str("delete env1.prop"))->Run();
6190 CHECK(result->IsFalse());
6191 }
6192
6193 // Check that env1.prop still exists.
6194 Local<Value> v = env1->Global()->Get(v8_str("prop"));
6195 CHECK(v->IsNumber());
6196 CHECK_EQ(3, v->Int32Value());
6197
6198 env2.Dispose();
6199}
6200
6201
ager@chromium.org870a0b62008-11-04 11:43:05 +00006202THREADED_TEST(CrossDomainIsPropertyEnumerable) {
6203 v8::HandleScope handle_scope;
6204 LocalContext env1;
6205 v8::Persistent<Context> env2 = Context::New();
6206
6207 Local<Value> foo = v8_str("foo");
6208 Local<Value> bar = v8_str("bar");
6209
6210 // Set to the same domain.
6211 env1->SetSecurityToken(foo);
6212 env2->SetSecurityToken(foo);
6213
6214 env1->Global()->Set(v8_str("prop"), v8_num(3));
6215 env2->Global()->Set(v8_str("env1"), env1->Global());
6216
6217 // env1.prop is enumerable in env2.
6218 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
6219 {
6220 Context::Scope scope_env2(env2);
6221 Local<Value> result = Script::Compile(test)->Run();
6222 CHECK(result->IsTrue());
6223 }
6224
6225 // Change env2 to a different domain and test again.
6226 env2->SetSecurityToken(bar);
6227 {
6228 Context::Scope scope_env2(env2);
6229 Local<Value> result = Script::Compile(test)->Run();
6230 CHECK(result->IsFalse());
6231 }
6232
6233 env2.Dispose();
6234}
6235
6236
ager@chromium.org236ad962008-09-25 09:45:57 +00006237THREADED_TEST(CrossDomainForIn) {
6238 v8::HandleScope handle_scope;
6239 LocalContext env1;
6240 v8::Persistent<Context> env2 = Context::New();
6241
6242 Local<Value> foo = v8_str("foo");
6243 Local<Value> bar = v8_str("bar");
6244
6245 // Set to the same domain.
6246 env1->SetSecurityToken(foo);
6247 env2->SetSecurityToken(foo);
6248
6249 env1->Global()->Set(v8_str("prop"), v8_num(3));
6250 env2->Global()->Set(v8_str("env1"), env1->Global());
6251
6252 // Change env2 to a different domain and set env1's global object
6253 // as the __proto__ of an object in env2 and enumerate properties
6254 // in for-in. It shouldn't enumerate properties on env1's global
6255 // object.
6256 env2->SetSecurityToken(bar);
6257 {
6258 Context::Scope scope_env2(env2);
6259 Local<Value> result =
6260 CompileRun("(function(){var obj = {'__proto__':env1};"
6261 "for (var p in obj)"
6262 " if (p == 'prop') return false;"
6263 "return true;})()");
6264 CHECK(result->IsTrue());
6265 }
6266 env2.Dispose();
6267}
6268
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006269
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006270TEST(ContextDetachGlobal) {
6271 v8::HandleScope handle_scope;
6272 LocalContext env1;
6273 v8::Persistent<Context> env2 = Context::New();
6274
6275 Local<v8::Object> global1 = env1->Global();
6276
6277 Local<Value> foo = v8_str("foo");
6278
6279 // Set to the same domain.
6280 env1->SetSecurityToken(foo);
6281 env2->SetSecurityToken(foo);
6282
6283 // Enter env2
6284 env2->Enter();
6285
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00006286 // Create a function in env2 and add a reference to it in env1.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006287 Local<v8::Object> global2 = env2->Global();
6288 global2->Set(v8_str("prop"), v8::Integer::New(1));
6289 CompileRun("function getProp() {return prop;}");
6290
6291 env1->Global()->Set(v8_str("getProp"),
6292 global2->Get(v8_str("getProp")));
6293
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00006294 // Detach env2's global, and reuse the global object of env2
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006295 env2->Exit();
6296 env2->DetachGlobal();
6297 // env2 has a new global object.
6298 CHECK(!env2->Global()->Equals(global2));
6299
6300 v8::Persistent<Context> env3 =
6301 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
6302 env3->SetSecurityToken(v8_str("bar"));
6303 env3->Enter();
6304
6305 Local<v8::Object> global3 = env3->Global();
6306 CHECK_EQ(global2, global3);
6307 CHECK(global3->Get(v8_str("prop"))->IsUndefined());
6308 CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
6309 global3->Set(v8_str("prop"), v8::Integer::New(-1));
6310 global3->Set(v8_str("prop2"), v8::Integer::New(2));
6311 env3->Exit();
6312
6313 // Call getProp in env1, and it should return the value 1
6314 {
6315 Local<Value> get_prop = global1->Get(v8_str("getProp"));
6316 CHECK(get_prop->IsFunction());
6317 v8::TryCatch try_catch;
6318 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
6319 CHECK(!try_catch.HasCaught());
6320 CHECK_EQ(1, r->Int32Value());
6321 }
6322
6323 // Check that env3 is not accessible from env1
6324 {
6325 Local<Value> r = global3->Get(v8_str("prop2"));
6326 CHECK(r->IsUndefined());
6327 }
6328
6329 env2.Dispose();
6330 env3.Dispose();
6331}
6332
6333
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00006334TEST(DetachAndReattachGlobal) {
6335 v8::HandleScope scope;
6336 LocalContext env1;
6337
6338 // Create second environment.
6339 v8::Persistent<Context> env2 = Context::New();
6340
6341 Local<Value> foo = v8_str("foo");
6342
6343 // Set same security token for env1 and env2.
6344 env1->SetSecurityToken(foo);
6345 env2->SetSecurityToken(foo);
6346
6347 // Create a property on the global object in env2.
6348 {
6349 v8::Context::Scope scope(env2);
6350 env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
6351 }
6352
6353 // Create a reference to env2 global from env1 global.
6354 env1->Global()->Set(v8_str("other"), env2->Global());
6355
6356 // Check that we have access to other.p in env2 from env1.
6357 Local<Value> result = CompileRun("other.p");
6358 CHECK(result->IsInt32());
6359 CHECK_EQ(42, result->Int32Value());
6360
6361 // Hold on to global from env2 and detach global from env2.
6362 Local<v8::Object> global2 = env2->Global();
6363 env2->DetachGlobal();
6364
6365 // Check that the global has been detached. No other.p property can
6366 // be found.
6367 result = CompileRun("other.p");
6368 CHECK(result->IsUndefined());
6369
6370 // Reuse global2 for env3.
6371 v8::Persistent<Context> env3 =
6372 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
6373 CHECK_EQ(global2, env3->Global());
6374
6375 // Start by using the same security token for env3 as for env1 and env2.
6376 env3->SetSecurityToken(foo);
6377
6378 // Create a property on the global object in env3.
6379 {
6380 v8::Context::Scope scope(env3);
6381 env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
6382 }
6383
6384 // Check that other.p is now the property in env3 and that we have access.
6385 result = CompileRun("other.p");
6386 CHECK(result->IsInt32());
6387 CHECK_EQ(24, result->Int32Value());
6388
6389 // Change security token for env3 to something different from env1 and env2.
6390 env3->SetSecurityToken(v8_str("bar"));
6391
6392 // Check that we do not have access to other.p in env1. |other| is now
6393 // the global object for env3 which has a different security token,
6394 // so access should be blocked.
6395 result = CompileRun("other.p");
6396 CHECK(result->IsUndefined());
6397
6398 // Detach the global for env3 and reattach it to env2.
6399 env3->DetachGlobal();
6400 env2->ReattachGlobal(global2);
6401
6402 // Check that we have access to other.p again in env1. |other| is now
6403 // the global object for env2 which has the same security token as env1.
6404 result = CompileRun("other.p");
6405 CHECK(result->IsInt32());
6406 CHECK_EQ(42, result->Int32Value());
6407
6408 env2.Dispose();
6409 env3.Dispose();
6410}
6411
6412
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006413static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006414static bool NamedAccessBlocker(Local<v8::Object> global,
6415 Local<Value> name,
6416 v8::AccessType type,
6417 Local<Value> data) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006418 return Context::GetCurrent()->Global()->Equals(global) ||
6419 allowed_access_type[type];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006420}
6421
6422
6423static bool IndexedAccessBlocker(Local<v8::Object> global,
6424 uint32_t key,
6425 v8::AccessType type,
6426 Local<Value> data) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006427 return Context::GetCurrent()->Global()->Equals(global) ||
6428 allowed_access_type[type];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006429}
6430
6431
6432static int g_echo_value = -1;
6433static v8::Handle<Value> EchoGetter(Local<String> name,
6434 const AccessorInfo& info) {
6435 return v8_num(g_echo_value);
6436}
6437
6438
6439static void EchoSetter(Local<String> name,
6440 Local<Value> value,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006441 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006442 if (value->IsNumber())
6443 g_echo_value = value->Int32Value();
6444}
6445
6446
6447static v8::Handle<Value> UnreachableGetter(Local<String> name,
6448 const AccessorInfo& info) {
6449 CHECK(false); // This function should not be called..
6450 return v8::Undefined();
6451}
6452
6453
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006454static void UnreachableSetter(Local<String>, Local<Value>,
6455 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006456 CHECK(false); // This function should nto be called.
6457}
6458
6459
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006460TEST(AccessControl) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006461 v8::HandleScope handle_scope;
6462 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
6463
6464 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
6465 IndexedAccessBlocker);
6466
6467 // Add an accessor accessible by cross-domain JS code.
6468 global_template->SetAccessor(
6469 v8_str("accessible_prop"),
6470 EchoGetter, EchoSetter,
6471 v8::Handle<Value>(),
6472 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
6473
6474 // Add an accessor that is not accessible by cross-domain JS code.
ager@chromium.org870a0b62008-11-04 11:43:05 +00006475 global_template->SetAccessor(v8_str("blocked_prop"),
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006476 UnreachableGetter, UnreachableSetter,
6477 v8::Handle<Value>(),
6478 v8::DEFAULT);
6479
6480 // Create an environment
6481 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6482 context0->Enter();
6483
6484 v8::Handle<v8::Object> global0 = context0->Global();
6485
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006486 // Define a property with JS getter and setter.
6487 CompileRun(
6488 "function getter() { return 'getter'; };\n"
6489 "function setter() { return 'setter'; }\n"
6490 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
6491
6492 Local<Value> getter = global0->Get(v8_str("getter"));
6493 Local<Value> setter = global0->Get(v8_str("setter"));
6494
6495 // And define normal element.
6496 global0->Set(239, v8_str("239"));
6497
6498 // Define an element with JS getter and setter.
6499 CompileRun(
6500 "function el_getter() { return 'el_getter'; };\n"
6501 "function el_setter() { return 'el_setter'; };\n"
6502 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
6503
6504 Local<Value> el_getter = global0->Get(v8_str("el_getter"));
6505 Local<Value> el_setter = global0->Get(v8_str("el_setter"));
6506
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006507 v8::HandleScope scope1;
6508
6509 v8::Persistent<Context> context1 = Context::New();
6510 context1->Enter();
6511
6512 v8::Handle<v8::Object> global1 = context1->Global();
6513 global1->Set(v8_str("other"), global0);
6514
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006515 // Access blocked property.
6516 CompileRun("other.blocked_prop = 1");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006517
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006518 ExpectUndefined("other.blocked_prop");
6519 ExpectUndefined(
6520 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
6521 ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006522
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006523 // Enable ACCESS_HAS
6524 allowed_access_type[v8::ACCESS_HAS] = true;
6525 ExpectUndefined("other.blocked_prop");
6526 // ... and now we can get the descriptor...
6527 ExpectUndefined(
antonm@chromium.orgdca01352011-01-31 17:15:05 +00006528 "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006529 // ... and enumerate the property.
6530 ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
6531 allowed_access_type[v8::ACCESS_HAS] = false;
antonm@chromium.orgdca01352011-01-31 17:15:05 +00006532
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006533 // Access blocked element.
6534 CompileRun("other[239] = 1");
6535
6536 ExpectUndefined("other[239]");
6537 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
6538 ExpectFalse("propertyIsEnumerable.call(other, '239')");
6539
6540 // Enable ACCESS_HAS
6541 allowed_access_type[v8::ACCESS_HAS] = true;
6542 ExpectUndefined("other[239]");
6543 // ... and now we can get the descriptor...
6544 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
6545 // ... and enumerate the property.
6546 ExpectTrue("propertyIsEnumerable.call(other, '239')");
6547 allowed_access_type[v8::ACCESS_HAS] = false;
6548
6549 // Access a property with JS accessor.
6550 CompileRun("other.js_accessor_p = 2");
6551
6552 ExpectUndefined("other.js_accessor_p");
6553 ExpectUndefined(
6554 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
6555
6556 // Enable ACCESS_HAS.
6557 allowed_access_type[v8::ACCESS_HAS] = true;
6558 ExpectUndefined("other.js_accessor_p");
6559 ExpectUndefined(
6560 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
6561 ExpectUndefined(
6562 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
6563 ExpectUndefined(
6564 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6565 allowed_access_type[v8::ACCESS_HAS] = false;
6566
6567 // Enable both ACCESS_HAS and ACCESS_GET.
6568 allowed_access_type[v8::ACCESS_HAS] = true;
6569 allowed_access_type[v8::ACCESS_GET] = true;
6570
6571 ExpectString("other.js_accessor_p", "getter");
6572 ExpectObject(
6573 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
6574 ExpectUndefined(
6575 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
6576 ExpectUndefined(
6577 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6578
6579 allowed_access_type[v8::ACCESS_GET] = false;
6580 allowed_access_type[v8::ACCESS_HAS] = false;
6581
6582 // Enable both ACCESS_HAS and ACCESS_SET.
6583 allowed_access_type[v8::ACCESS_HAS] = true;
6584 allowed_access_type[v8::ACCESS_SET] = true;
6585
6586 ExpectUndefined("other.js_accessor_p");
6587 ExpectUndefined(
6588 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
6589 ExpectObject(
6590 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
6591 ExpectUndefined(
6592 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6593
6594 allowed_access_type[v8::ACCESS_SET] = false;
6595 allowed_access_type[v8::ACCESS_HAS] = false;
6596
6597 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
6598 allowed_access_type[v8::ACCESS_HAS] = true;
6599 allowed_access_type[v8::ACCESS_GET] = true;
6600 allowed_access_type[v8::ACCESS_SET] = true;
6601
6602 ExpectString("other.js_accessor_p", "getter");
6603 ExpectObject(
6604 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
6605 ExpectObject(
6606 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
6607 ExpectUndefined(
6608 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6609
6610 allowed_access_type[v8::ACCESS_SET] = false;
6611 allowed_access_type[v8::ACCESS_GET] = false;
6612 allowed_access_type[v8::ACCESS_HAS] = false;
6613
6614 // Access an element with JS accessor.
6615 CompileRun("other[42] = 2");
6616
6617 ExpectUndefined("other[42]");
6618 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
6619
6620 // Enable ACCESS_HAS.
6621 allowed_access_type[v8::ACCESS_HAS] = true;
6622 ExpectUndefined("other[42]");
6623 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
6624 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
6625 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6626 allowed_access_type[v8::ACCESS_HAS] = false;
6627
6628 // Enable both ACCESS_HAS and ACCESS_GET.
6629 allowed_access_type[v8::ACCESS_HAS] = true;
6630 allowed_access_type[v8::ACCESS_GET] = true;
6631
6632 ExpectString("other[42]", "el_getter");
6633 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
6634 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
6635 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6636
6637 allowed_access_type[v8::ACCESS_GET] = false;
6638 allowed_access_type[v8::ACCESS_HAS] = false;
6639
6640 // Enable both ACCESS_HAS and ACCESS_SET.
6641 allowed_access_type[v8::ACCESS_HAS] = true;
6642 allowed_access_type[v8::ACCESS_SET] = true;
6643
6644 ExpectUndefined("other[42]");
6645 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
6646 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
6647 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6648
6649 allowed_access_type[v8::ACCESS_SET] = false;
6650 allowed_access_type[v8::ACCESS_HAS] = false;
6651
6652 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
6653 allowed_access_type[v8::ACCESS_HAS] = true;
6654 allowed_access_type[v8::ACCESS_GET] = true;
6655 allowed_access_type[v8::ACCESS_SET] = true;
6656
6657 ExpectString("other[42]", "el_getter");
6658 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
6659 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
6660 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6661
6662 allowed_access_type[v8::ACCESS_SET] = false;
6663 allowed_access_type[v8::ACCESS_GET] = false;
6664 allowed_access_type[v8::ACCESS_HAS] = false;
6665
6666 v8::Handle<Value> value;
ager@chromium.org870a0b62008-11-04 11:43:05 +00006667
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006668 // Access accessible property
antonm@chromium.orgdca01352011-01-31 17:15:05 +00006669 value = CompileRun("other.accessible_prop = 3");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006670 CHECK(value->IsNumber());
6671 CHECK_EQ(3, value->Int32Value());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006672 CHECK_EQ(3, g_echo_value);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006673
antonm@chromium.orgdca01352011-01-31 17:15:05 +00006674 value = CompileRun("other.accessible_prop");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006675 CHECK(value->IsNumber());
6676 CHECK_EQ(3, value->Int32Value());
6677
antonm@chromium.orgdca01352011-01-31 17:15:05 +00006678 value = CompileRun(
6679 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
6680 CHECK(value->IsNumber());
6681 CHECK_EQ(3, value->Int32Value());
6682
6683 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
ager@chromium.org870a0b62008-11-04 11:43:05 +00006684 CHECK(value->IsTrue());
6685
6686 // Enumeration doesn't enumerate accessors from inaccessible objects in
6687 // the prototype chain even if the accessors are in themselves accessible.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00006688 value =
ager@chromium.org870a0b62008-11-04 11:43:05 +00006689 CompileRun("(function(){var obj = {'__proto__':other};"
6690 "for (var p in obj)"
6691 " if (p == 'accessible_prop' || p == 'blocked_prop') {"
6692 " return false;"
6693 " }"
6694 "return true;})()");
antonm@chromium.orgdca01352011-01-31 17:15:05 +00006695 CHECK(value->IsTrue());
ager@chromium.org870a0b62008-11-04 11:43:05 +00006696
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006697 context1->Exit();
6698 context0->Exit();
6699 context1.Dispose();
6700 context0.Dispose();
6701}
6702
6703
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006704TEST(AccessControlES5) {
ricow@chromium.org65001782011-02-15 13:36:41 +00006705 v8::HandleScope handle_scope;
6706 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
6707
6708 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
6709 IndexedAccessBlocker);
6710
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00006711 // Add accessible accessor.
6712 global_template->SetAccessor(
6713 v8_str("accessible_prop"),
6714 EchoGetter, EchoSetter,
6715 v8::Handle<Value>(),
6716 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
6717
6718
ricow@chromium.org65001782011-02-15 13:36:41 +00006719 // Add an accessor that is not accessible by cross-domain JS code.
6720 global_template->SetAccessor(v8_str("blocked_prop"),
6721 UnreachableGetter, UnreachableSetter,
6722 v8::Handle<Value>(),
6723 v8::DEFAULT);
6724
6725 // Create an environment
6726 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6727 context0->Enter();
6728
6729 v8::Handle<v8::Object> global0 = context0->Global();
6730
6731 v8::Persistent<Context> context1 = Context::New();
6732 context1->Enter();
6733 v8::Handle<v8::Object> global1 = context1->Global();
6734 global1->Set(v8_str("other"), global0);
6735
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006736 // Regression test for issue 1154.
ricow@chromium.org65001782011-02-15 13:36:41 +00006737 ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006738
6739 ExpectUndefined("other.blocked_prop");
6740
6741 // Regression test for issue 1027.
6742 CompileRun("Object.defineProperty(\n"
6743 " other, 'blocked_prop', {configurable: false})");
6744 ExpectUndefined("other.blocked_prop");
6745 ExpectUndefined(
6746 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
6747
6748 // Regression test for issue 1171.
6749 ExpectTrue("Object.isExtensible(other)");
6750 CompileRun("Object.preventExtensions(other)");
6751 ExpectTrue("Object.isExtensible(other)");
6752
6753 // Object.seal and Object.freeze.
6754 CompileRun("Object.freeze(other)");
6755 ExpectTrue("Object.isExtensible(other)");
6756
6757 CompileRun("Object.seal(other)");
6758 ExpectTrue("Object.isExtensible(other)");
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00006759
6760 // Regression test for issue 1250.
6761 // Make sure that we can set the accessible accessors value using normal
6762 // assignment.
6763 CompileRun("other.accessible_prop = 42");
6764 CHECK_EQ(42, g_echo_value);
6765
6766 v8::Handle<Value> value;
6767 // We follow Safari in ignoring assignments to host object accessors.
6768 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
6769 value = CompileRun("other.accessible_prop == 42");
6770 CHECK(value->IsTrue());
ricow@chromium.org65001782011-02-15 13:36:41 +00006771}
6772
6773
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006774static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
6775 Local<Value> name,
6776 v8::AccessType type,
6777 Local<Value> data) {
6778 return false;
6779}
6780
6781
6782static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
6783 uint32_t key,
6784 v8::AccessType type,
6785 Local<Value> data) {
6786 return false;
6787}
6788
6789
6790THREADED_TEST(AccessControlGetOwnPropertyNames) {
6791 v8::HandleScope handle_scope;
6792 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
6793
6794 obj_template->Set(v8_str("x"), v8::Integer::New(42));
6795 obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
6796 GetOwnPropertyNamesIndexedBlocker);
6797
6798 // Create an environment
6799 v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
6800 context0->Enter();
6801
6802 v8::Handle<v8::Object> global0 = context0->Global();
6803
6804 v8::HandleScope scope1;
6805
6806 v8::Persistent<Context> context1 = Context::New();
6807 context1->Enter();
6808
6809 v8::Handle<v8::Object> global1 = context1->Global();
6810 global1->Set(v8_str("other"), global0);
6811 global1->Set(v8_str("object"), obj_template->NewInstance());
6812
6813 v8::Handle<Value> value;
6814
6815 // Attempt to get the property names of the other global object and
6816 // of an object that requires access checks. Accessing the other
6817 // global object should be blocked by access checks on the global
6818 // proxy object. Accessing the object that requires access checks
6819 // is blocked by the access checks on the object itself.
6820 value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
6821 CHECK(value->IsTrue());
6822
6823 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
6824 CHECK(value->IsTrue());
6825
6826 context1->Exit();
6827 context0->Exit();
6828 context1.Dispose();
6829 context0.Dispose();
6830}
6831
6832
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00006833static v8::Handle<v8::Array> NamedPropertyEnumerator(const AccessorInfo& info) {
6834 v8::Handle<v8::Array> result = v8::Array::New(1);
6835 result->Set(0, v8_str("x"));
6836 return result;
6837}
6838
6839
6840THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
6841 v8::HandleScope handle_scope;
6842 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
6843
6844 obj_template->Set(v8_str("x"), v8::Integer::New(42));
6845 obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
6846 NamedPropertyEnumerator);
6847
6848 LocalContext context;
6849 v8::Handle<v8::Object> global = context->Global();
6850 global->Set(v8_str("object"), obj_template->NewInstance());
6851
6852 v8::Handle<Value> value =
6853 CompileRun("Object.getOwnPropertyNames(object).join(',')");
6854 CHECK_EQ(v8_str("x"), value);
6855}
6856
6857
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006858static v8::Handle<Value> ConstTenGetter(Local<String> name,
6859 const AccessorInfo& info) {
6860 return v8_num(10);
6861}
6862
6863
6864THREADED_TEST(CrossDomainAccessors) {
6865 v8::HandleScope handle_scope;
6866
6867 v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
6868
6869 v8::Handle<v8::ObjectTemplate> global_template =
6870 func_template->InstanceTemplate();
6871
6872 v8::Handle<v8::ObjectTemplate> proto_template =
6873 func_template->PrototypeTemplate();
6874
6875 // Add an accessor to proto that's accessible by cross-domain JS code.
6876 proto_template->SetAccessor(v8_str("accessible"),
6877 ConstTenGetter, 0,
6878 v8::Handle<Value>(),
6879 v8::ALL_CAN_READ);
6880
6881 // Add an accessor that is not accessible by cross-domain JS code.
6882 global_template->SetAccessor(v8_str("unreachable"),
6883 UnreachableGetter, 0,
6884 v8::Handle<Value>(),
6885 v8::DEFAULT);
6886
6887 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6888 context0->Enter();
6889
6890 Local<v8::Object> global = context0->Global();
6891 // Add a normal property that shadows 'accessible'
6892 global->Set(v8_str("accessible"), v8_num(11));
6893
6894 // Enter a new context.
6895 v8::HandleScope scope1;
6896 v8::Persistent<Context> context1 = Context::New();
6897 context1->Enter();
6898
6899 v8::Handle<v8::Object> global1 = context1->Global();
6900 global1->Set(v8_str("other"), global);
6901
6902 // Should return 10, instead of 11
6903 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
6904 CHECK(value->IsNumber());
6905 CHECK_EQ(10, value->Int32Value());
6906
6907 value = v8_compile("other.unreachable")->Run();
6908 CHECK(value->IsUndefined());
6909
6910 context1->Exit();
6911 context0->Exit();
6912 context1.Dispose();
6913 context0.Dispose();
6914}
6915
6916
6917static int named_access_count = 0;
6918static int indexed_access_count = 0;
6919
6920static bool NamedAccessCounter(Local<v8::Object> global,
6921 Local<Value> name,
6922 v8::AccessType type,
6923 Local<Value> data) {
6924 named_access_count++;
6925 return true;
6926}
6927
6928
6929static bool IndexedAccessCounter(Local<v8::Object> global,
6930 uint32_t key,
6931 v8::AccessType type,
6932 Local<Value> data) {
6933 indexed_access_count++;
6934 return true;
6935}
6936
6937
6938// This one is too easily disturbed by other tests.
6939TEST(AccessControlIC) {
6940 named_access_count = 0;
6941 indexed_access_count = 0;
6942
6943 v8::HandleScope handle_scope;
6944
6945 // Create an environment.
6946 v8::Persistent<Context> context0 = Context::New();
6947 context0->Enter();
6948
6949 // Create an object that requires access-check functions to be
6950 // called for cross-domain access.
6951 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
6952 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
6953 IndexedAccessCounter);
6954 Local<v8::Object> object = object_template->NewInstance();
6955
6956 v8::HandleScope scope1;
6957
6958 // Create another environment.
6959 v8::Persistent<Context> context1 = Context::New();
6960 context1->Enter();
6961
6962 // Make easy access to the object from the other environment.
6963 v8::Handle<v8::Object> global1 = context1->Global();
6964 global1->Set(v8_str("obj"), object);
6965
6966 v8::Handle<Value> value;
6967
6968 // Check that the named access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00006969 CompileRun("function testProp(obj) {"
6970 " for (var i = 0; i < 10; i++) obj.prop = 1;"
6971 " for (var j = 0; j < 10; j++) obj.prop;"
6972 " return obj.prop"
6973 "}");
6974 value = CompileRun("testProp(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006975 CHECK(value->IsNumber());
6976 CHECK_EQ(1, value->Int32Value());
6977 CHECK_EQ(21, named_access_count);
6978
6979 // Check that the named access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00006980 CompileRun("var p = 'prop';"
6981 "function testKeyed(obj) {"
6982 " for (var i = 0; i < 10; i++) obj[p] = 1;"
6983 " for (var j = 0; j < 10; j++) obj[p];"
6984 " return obj[p];"
6985 "}");
6986 // Use obj which requires access checks. No inline caching is used
6987 // in that case.
6988 value = CompileRun("testKeyed(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006989 CHECK(value->IsNumber());
6990 CHECK_EQ(1, value->Int32Value());
6991 CHECK_EQ(42, named_access_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00006992 // Force the inline caches into generic state and try again.
6993 CompileRun("testKeyed({ a: 0 })");
6994 CompileRun("testKeyed({ b: 0 })");
6995 value = CompileRun("testKeyed(obj)");
6996 CHECK(value->IsNumber());
6997 CHECK_EQ(1, value->Int32Value());
6998 CHECK_EQ(63, named_access_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006999
7000 // Check that the indexed access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00007001 CompileRun("function testIndexed(obj) {"
7002 " for (var i = 0; i < 10; i++) obj[0] = 1;"
7003 " for (var j = 0; j < 10; j++) obj[0];"
7004 " return obj[0]"
7005 "}");
7006 value = CompileRun("testIndexed(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007007 CHECK(value->IsNumber());
7008 CHECK_EQ(1, value->Int32Value());
7009 CHECK_EQ(21, indexed_access_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00007010 // Force the inline caches into generic state.
7011 CompileRun("testIndexed(new Array(1))");
7012 // Test that the indexed access check is called.
7013 value = CompileRun("testIndexed(obj)");
7014 CHECK(value->IsNumber());
7015 CHECK_EQ(1, value->Int32Value());
7016 CHECK_EQ(42, indexed_access_count);
7017
7018 // Check that the named access check is called when invoking
7019 // functions on an object that requires access checks.
7020 CompileRun("obj.f = function() {}");
7021 CompileRun("function testCallNormal(obj) {"
7022 " for (var i = 0; i < 10; i++) obj.f();"
7023 "}");
7024 CompileRun("testCallNormal(obj)");
7025 CHECK_EQ(74, named_access_count);
7026
7027 // Force obj into slow case.
7028 value = CompileRun("delete obj.prop");
7029 CHECK(value->BooleanValue());
7030 // Force inline caches into dictionary probing mode.
7031 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
7032 // Test that the named access check is called.
7033 value = CompileRun("testProp(obj);");
7034 CHECK(value->IsNumber());
7035 CHECK_EQ(1, value->Int32Value());
7036 CHECK_EQ(96, named_access_count);
7037
7038 // Force the call inline cache into dictionary probing mode.
7039 CompileRun("o.f = function() {}; testCallNormal(o)");
7040 // Test that the named access check is still called for each
7041 // invocation of the function.
7042 value = CompileRun("testCallNormal(obj)");
7043 CHECK_EQ(106, named_access_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007044
7045 context1->Exit();
7046 context0->Exit();
7047 context1.Dispose();
7048 context0.Dispose();
7049}
7050
7051
7052static bool NamedAccessFlatten(Local<v8::Object> global,
7053 Local<Value> name,
7054 v8::AccessType type,
7055 Local<Value> data) {
7056 char buf[100];
7057 int len;
7058
7059 CHECK(name->IsString());
7060
7061 memset(buf, 0x1, sizeof(buf));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007062 len = name.As<String>()->WriteAscii(buf);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007063 CHECK_EQ(4, len);
7064
7065 uint16_t buf2[100];
7066
7067 memset(buf, 0x1, sizeof(buf));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007068 len = name.As<String>()->Write(buf2);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007069 CHECK_EQ(4, len);
7070
7071 return true;
7072}
7073
7074
7075static bool IndexedAccessFlatten(Local<v8::Object> global,
7076 uint32_t key,
7077 v8::AccessType type,
7078 Local<Value> data) {
7079 return true;
7080}
7081
7082
7083// Regression test. In access checks, operations that may cause
7084// garbage collection are not allowed. It used to be the case that
7085// using the Write operation on a string could cause a garbage
7086// collection due to flattening of the string. This is no longer the
7087// case.
7088THREADED_TEST(AccessControlFlatten) {
7089 named_access_count = 0;
7090 indexed_access_count = 0;
7091
7092 v8::HandleScope handle_scope;
7093
7094 // Create an environment.
7095 v8::Persistent<Context> context0 = Context::New();
7096 context0->Enter();
7097
7098 // Create an object that requires access-check functions to be
7099 // called for cross-domain access.
7100 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
7101 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
7102 IndexedAccessFlatten);
7103 Local<v8::Object> object = object_template->NewInstance();
7104
7105 v8::HandleScope scope1;
7106
7107 // Create another environment.
7108 v8::Persistent<Context> context1 = Context::New();
7109 context1->Enter();
7110
7111 // Make easy access to the object from the other environment.
7112 v8::Handle<v8::Object> global1 = context1->Global();
7113 global1->Set(v8_str("obj"), object);
7114
7115 v8::Handle<Value> value;
7116
7117 value = v8_compile("var p = 'as' + 'df';")->Run();
7118 value = v8_compile("obj[p];")->Run();
7119
7120 context1->Exit();
7121 context0->Exit();
7122 context1.Dispose();
7123 context0.Dispose();
7124}
7125
7126
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007127static v8::Handle<Value> AccessControlNamedGetter(
7128 Local<String>, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007129 return v8::Integer::New(42);
7130}
7131
7132
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007133static v8::Handle<Value> AccessControlNamedSetter(
7134 Local<String>, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007135 return value;
7136}
7137
7138
7139static v8::Handle<Value> AccessControlIndexedGetter(
7140 uint32_t index,
7141 const AccessorInfo& info) {
7142 return v8_num(42);
7143}
7144
7145
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007146static v8::Handle<Value> AccessControlIndexedSetter(
7147 uint32_t, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007148 return value;
7149}
7150
7151
7152THREADED_TEST(AccessControlInterceptorIC) {
7153 named_access_count = 0;
7154 indexed_access_count = 0;
7155
7156 v8::HandleScope handle_scope;
7157
7158 // Create an environment.
7159 v8::Persistent<Context> context0 = Context::New();
7160 context0->Enter();
7161
7162 // Create an object that requires access-check functions to be
7163 // called for cross-domain access. The object also has interceptors
7164 // interceptor.
7165 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
7166 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
7167 IndexedAccessCounter);
7168 object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
7169 AccessControlNamedSetter);
7170 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
7171 AccessControlIndexedSetter);
7172 Local<v8::Object> object = object_template->NewInstance();
7173
7174 v8::HandleScope scope1;
7175
7176 // Create another environment.
7177 v8::Persistent<Context> context1 = Context::New();
7178 context1->Enter();
7179
7180 // Make easy access to the object from the other environment.
7181 v8::Handle<v8::Object> global1 = context1->Global();
7182 global1->Set(v8_str("obj"), object);
7183
7184 v8::Handle<Value> value;
7185
7186 // Check that the named access-control function is called every time
7187 // eventhough there is an interceptor on the object.
7188 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
7189 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
7190 "obj.x")->Run();
7191 CHECK(value->IsNumber());
7192 CHECK_EQ(42, value->Int32Value());
7193 CHECK_EQ(21, named_access_count);
7194
7195 value = v8_compile("var p = 'x';")->Run();
7196 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
7197 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
7198 "obj[p]")->Run();
7199 CHECK(value->IsNumber());
7200 CHECK_EQ(42, value->Int32Value());
7201 CHECK_EQ(42, named_access_count);
7202
7203 // Check that the indexed access-control function is called every
7204 // time eventhough there is an interceptor on the object.
7205 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
7206 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
7207 "obj[0]")->Run();
7208 CHECK(value->IsNumber());
7209 CHECK_EQ(42, value->Int32Value());
7210 CHECK_EQ(21, indexed_access_count);
7211
7212 context1->Exit();
7213 context0->Exit();
7214 context1.Dispose();
7215 context0.Dispose();
7216}
7217
7218
7219THREADED_TEST(Version) {
7220 v8::V8::GetVersion();
7221}
7222
7223
7224static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
7225 ApiTestFuzzer::Fuzz();
7226 return v8_num(12);
7227}
7228
7229
7230THREADED_TEST(InstanceProperties) {
7231 v8::HandleScope handle_scope;
7232 LocalContext context;
7233
7234 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7235 Local<ObjectTemplate> instance = t->InstanceTemplate();
7236
7237 instance->Set(v8_str("x"), v8_num(42));
7238 instance->Set(v8_str("f"),
7239 v8::FunctionTemplate::New(InstanceFunctionCallback));
7240
7241 Local<Value> o = t->GetFunction()->NewInstance();
7242
7243 context->Global()->Set(v8_str("i"), o);
7244 Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
7245 CHECK_EQ(42, value->Int32Value());
7246
7247 value = Script::Compile(v8_str("i.f()"))->Run();
7248 CHECK_EQ(12, value->Int32Value());
7249}
7250
7251
7252static v8::Handle<Value>
7253GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
7254 ApiTestFuzzer::Fuzz();
7255 return v8::Handle<Value>();
7256}
7257
7258
7259THREADED_TEST(GlobalObjectInstanceProperties) {
7260 v8::HandleScope handle_scope;
7261
7262 Local<Value> global_object;
7263
7264 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7265 t->InstanceTemplate()->SetNamedPropertyHandler(
7266 GlobalObjectInstancePropertiesGet);
7267 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7268 instance_template->Set(v8_str("x"), v8_num(42));
7269 instance_template->Set(v8_str("f"),
7270 v8::FunctionTemplate::New(InstanceFunctionCallback));
7271
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007272 // The script to check how Crankshaft compiles missing global function
7273 // invocations. function g is not defined and should throw on call.
7274 const char* script =
7275 "function wrapper(call) {"
7276 " var x = 0, y = 1;"
7277 " for (var i = 0; i < 1000; i++) {"
7278 " x += i * 100;"
7279 " y += i * 100;"
7280 " }"
7281 " if (call) g();"
7282 "}"
7283 "for (var i = 0; i < 17; i++) wrapper(false);"
7284 "var thrown = 0;"
7285 "try { wrapper(true); } catch (e) { thrown = 1; };"
7286 "thrown";
7287
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007288 {
7289 LocalContext env(NULL, instance_template);
7290 // Hold on to the global object so it can be used again in another
7291 // environment initialization.
7292 global_object = env->Global();
7293
7294 Local<Value> value = Script::Compile(v8_str("x"))->Run();
7295 CHECK_EQ(42, value->Int32Value());
7296 value = Script::Compile(v8_str("f()"))->Run();
7297 CHECK_EQ(12, value->Int32Value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007298 value = Script::Compile(v8_str(script))->Run();
7299 CHECK_EQ(1, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007300 }
7301
7302 {
7303 // Create new environment reusing the global object.
7304 LocalContext env(NULL, instance_template, global_object);
7305 Local<Value> value = Script::Compile(v8_str("x"))->Run();
7306 CHECK_EQ(42, value->Int32Value());
7307 value = Script::Compile(v8_str("f()"))->Run();
7308 CHECK_EQ(12, value->Int32Value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007309 value = Script::Compile(v8_str(script))->Run();
7310 CHECK_EQ(1, value->Int32Value());
7311 }
7312}
7313
7314
7315THREADED_TEST(CallKnownGlobalReceiver) {
7316 v8::HandleScope handle_scope;
7317
7318 Local<Value> global_object;
7319
7320 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7321 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7322
7323 // The script to check that we leave global object not
7324 // global object proxy on stack when we deoptimize from inside
7325 // arguments evaluation.
7326 // To provoke error we need to both force deoptimization
7327 // from arguments evaluation and to force CallIC to take
7328 // CallIC_Miss code path that can't cope with global proxy.
7329 const char* script =
7330 "function bar(x, y) { try { } finally { } }"
7331 "function baz(x) { try { } finally { } }"
7332 "function bom(x) { try { } finally { } }"
7333 "function foo(x) { bar([x], bom(2)); }"
7334 "for (var i = 0; i < 10000; i++) foo(1);"
7335 "foo";
7336
7337 Local<Value> foo;
7338 {
7339 LocalContext env(NULL, instance_template);
7340 // Hold on to the global object so it can be used again in another
7341 // environment initialization.
7342 global_object = env->Global();
7343 foo = Script::Compile(v8_str(script))->Run();
7344 }
7345
7346 {
7347 // Create new environment reusing the global object.
7348 LocalContext env(NULL, instance_template, global_object);
7349 env->Global()->Set(v8_str("foo"), foo);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007350 Local<Value> value(Script::Compile(v8_str("foo()"))->Run());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007351 }
7352}
7353
7354
7355static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
7356 ApiTestFuzzer::Fuzz();
7357 return v8_num(42);
7358}
7359
7360
7361static int shadow_y;
7362static int shadow_y_setter_call_count;
7363static int shadow_y_getter_call_count;
7364
7365
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007366static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007367 shadow_y_setter_call_count++;
7368 shadow_y = 42;
7369}
7370
7371
7372static v8::Handle<Value> ShadowYGetter(Local<String> name,
7373 const AccessorInfo& info) {
7374 ApiTestFuzzer::Fuzz();
7375 shadow_y_getter_call_count++;
7376 return v8_num(shadow_y);
7377}
7378
7379
7380static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
7381 const AccessorInfo& info) {
7382 return v8::Handle<Value>();
7383}
7384
7385
7386static v8::Handle<Value> ShadowNamedGet(Local<String> key,
7387 const AccessorInfo&) {
7388 return v8::Handle<Value>();
7389}
7390
7391
7392THREADED_TEST(ShadowObject) {
7393 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
7394 v8::HandleScope handle_scope;
7395
7396 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
7397 LocalContext context(NULL, global_template);
7398
7399 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7400 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
7401 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
7402 Local<ObjectTemplate> proto = t->PrototypeTemplate();
7403 Local<ObjectTemplate> instance = t->InstanceTemplate();
7404
7405 // Only allow calls of f on instances of t.
7406 Local<v8::Signature> signature = v8::Signature::New(t);
7407 proto->Set(v8_str("f"),
7408 v8::FunctionTemplate::New(ShadowFunctionCallback,
7409 Local<Value>(),
7410 signature));
7411 proto->Set(v8_str("x"), v8_num(12));
7412
7413 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
7414
7415 Local<Value> o = t->GetFunction()->NewInstance();
7416 context->Global()->Set(v8_str("__proto__"), o);
7417
7418 Local<Value> value =
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00007419 Script::Compile(v8_str("this.propertyIsEnumerable(0)"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007420 CHECK(value->IsBoolean());
7421 CHECK(!value->BooleanValue());
7422
7423 value = Script::Compile(v8_str("x"))->Run();
7424 CHECK_EQ(12, value->Int32Value());
7425
7426 value = Script::Compile(v8_str("f()"))->Run();
7427 CHECK_EQ(42, value->Int32Value());
7428
7429 Script::Compile(v8_str("y = 42"))->Run();
7430 CHECK_EQ(1, shadow_y_setter_call_count);
7431 value = Script::Compile(v8_str("y"))->Run();
7432 CHECK_EQ(1, shadow_y_getter_call_count);
7433 CHECK_EQ(42, value->Int32Value());
7434}
7435
7436
7437THREADED_TEST(HiddenPrototype) {
7438 v8::HandleScope handle_scope;
7439 LocalContext context;
7440
7441 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
7442 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
7443 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
7444 t1->SetHiddenPrototype(true);
7445 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
7446 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
7447 t2->SetHiddenPrototype(true);
7448 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
7449 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
7450 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
7451
7452 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
7453 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
7454 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
7455 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
7456
7457 // Setting the prototype on an object skips hidden prototypes.
7458 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7459 o0->Set(v8_str("__proto__"), o1);
7460 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7461 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7462 o0->Set(v8_str("__proto__"), o2);
7463 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7464 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7465 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7466 o0->Set(v8_str("__proto__"), o3);
7467 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7468 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7469 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7470 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
7471
7472 // Getting the prototype of o0 should get the first visible one
7473 // which is o3. Therefore, z should not be defined on the prototype
7474 // object.
7475 Local<Value> proto = o0->Get(v8_str("__proto__"));
7476 CHECK(proto->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007477 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007478}
7479
7480
ager@chromium.org5c838252010-02-19 08:53:10 +00007481THREADED_TEST(SetPrototype) {
7482 v8::HandleScope handle_scope;
7483 LocalContext context;
7484
7485 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
7486 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
7487 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
7488 t1->SetHiddenPrototype(true);
7489 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
7490 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
7491 t2->SetHiddenPrototype(true);
7492 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
7493 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
7494 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
7495
7496 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
7497 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
7498 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
7499 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
7500
7501 // Setting the prototype on an object does not skip hidden prototypes.
7502 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7503 CHECK(o0->SetPrototype(o1));
7504 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7505 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7506 CHECK(o1->SetPrototype(o2));
7507 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7508 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7509 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7510 CHECK(o2->SetPrototype(o3));
7511 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7512 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7513 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7514 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
7515
7516 // Getting the prototype of o0 should get the first visible one
7517 // which is o3. Therefore, z should not be defined on the prototype
7518 // object.
7519 Local<Value> proto = o0->Get(v8_str("__proto__"));
7520 CHECK(proto->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007521 CHECK_EQ(proto.As<v8::Object>(), o3);
ager@chromium.org5c838252010-02-19 08:53:10 +00007522
7523 // However, Object::GetPrototype ignores hidden prototype.
7524 Local<Value> proto0 = o0->GetPrototype();
7525 CHECK(proto0->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007526 CHECK_EQ(proto0.As<v8::Object>(), o1);
ager@chromium.org5c838252010-02-19 08:53:10 +00007527
7528 Local<Value> proto1 = o1->GetPrototype();
7529 CHECK(proto1->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007530 CHECK_EQ(proto1.As<v8::Object>(), o2);
ager@chromium.org5c838252010-02-19 08:53:10 +00007531
7532 Local<Value> proto2 = o2->GetPrototype();
7533 CHECK(proto2->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007534 CHECK_EQ(proto2.As<v8::Object>(), o3);
ager@chromium.org5c838252010-02-19 08:53:10 +00007535}
7536
7537
ricow@chromium.org27bf2882011-11-17 08:34:43 +00007538// Getting property names of an object with a prototype chain that
7539// triggers dictionary elements in GetLocalPropertyNames() shouldn't
7540// crash the runtime.
7541THREADED_TEST(Regress91517) {
7542 i::FLAG_allow_natives_syntax = true;
7543 v8::HandleScope handle_scope;
7544 LocalContext context;
7545
7546 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
7547 t1->SetHiddenPrototype(true);
7548 t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
7549 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
7550 t2->SetHiddenPrototype(true);
7551 t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
7552 t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New());
7553 t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
7554 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
7555 t3->SetHiddenPrototype(true);
7556 t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
7557 Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New();
7558 t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
7559
7560 // Force dictionary-based properties.
7561 i::ScopedVector<char> name_buf(1024);
7562 for (int i = 1; i <= 1000; i++) {
7563 i::OS::SNPrintF(name_buf, "sdf%d", i);
7564 t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
7565 }
7566
7567 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
7568 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
7569 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
7570 Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
7571
7572 // Create prototype chain of hidden prototypes.
7573 CHECK(o4->SetPrototype(o3));
7574 CHECK(o3->SetPrototype(o2));
7575 CHECK(o2->SetPrototype(o1));
7576
7577 // Call the runtime version of GetLocalPropertyNames() on the natively
7578 // created object through JavaScript.
7579 context->Global()->Set(v8_str("obj"), o4);
7580 CompileRun("var names = %GetLocalPropertyNames(obj);");
7581
7582 ExpectInt32("names.length", 1006);
7583 ExpectTrue("names.indexOf(\"baz\") >= 0");
7584 ExpectTrue("names.indexOf(\"boo\") >= 0");
7585 ExpectTrue("names.indexOf(\"foo\") >= 0");
7586 ExpectTrue("names.indexOf(\"fuz1\") >= 0");
7587 ExpectTrue("names.indexOf(\"fuz2\") >= 0");
7588 ExpectFalse("names[1005] == undefined");
7589}
7590
7591
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007592THREADED_TEST(FunctionReadOnlyPrototype) {
ager@chromium.org04921a82011-06-27 13:21:41 +00007593 v8::HandleScope handle_scope;
7594 LocalContext context;
7595
7596 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007597 t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
7598 t1->ReadOnlyPrototype();
ager@chromium.org04921a82011-06-27 13:21:41 +00007599 context->Global()->Set(v8_str("func1"), t1->GetFunction());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007600 // Configured value of ReadOnly flag.
ager@chromium.org04921a82011-06-27 13:21:41 +00007601 CHECK(CompileRun(
7602 "(function() {"
7603 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007604 " return (descriptor['writable'] == false);"
ager@chromium.org04921a82011-06-27 13:21:41 +00007605 "})()")->BooleanValue());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007606 CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
7607 CHECK_EQ(42,
7608 CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
ager@chromium.org04921a82011-06-27 13:21:41 +00007609
7610 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007611 t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
ager@chromium.org04921a82011-06-27 13:21:41 +00007612 context->Global()->Set(v8_str("func2"), t2->GetFunction());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007613 // Default value of ReadOnly flag.
ager@chromium.org04921a82011-06-27 13:21:41 +00007614 CHECK(CompileRun(
7615 "(function() {"
7616 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007617 " return (descriptor['writable'] == true);"
ager@chromium.org04921a82011-06-27 13:21:41 +00007618 "})()")->BooleanValue());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007619 CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
ager@chromium.org04921a82011-06-27 13:21:41 +00007620}
7621
7622
ager@chromium.org5c838252010-02-19 08:53:10 +00007623THREADED_TEST(SetPrototypeThrows) {
7624 v8::HandleScope handle_scope;
7625 LocalContext context;
7626
7627 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7628
7629 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
7630 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
7631
7632 CHECK(o0->SetPrototype(o1));
7633 // If setting the prototype leads to the cycle, SetPrototype should
7634 // return false and keep VM in sane state.
7635 v8::TryCatch try_catch;
7636 CHECK(!o1->SetPrototype(o0));
7637 CHECK(!try_catch.HasCaught());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007638 ASSERT(!i::Isolate::Current()->has_pending_exception());
ager@chromium.org5c838252010-02-19 08:53:10 +00007639
7640 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
7641}
7642
7643
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007644THREADED_TEST(GetterSetterExceptions) {
7645 v8::HandleScope handle_scope;
7646 LocalContext context;
7647 CompileRun(
7648 "function Foo() { };"
7649 "function Throw() { throw 5; };"
7650 "var x = { };"
7651 "x.__defineSetter__('set', Throw);"
7652 "x.__defineGetter__('get', Throw);");
7653 Local<v8::Object> x =
7654 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
7655 v8::TryCatch try_catch;
7656 x->Set(v8_str("set"), v8::Integer::New(8));
7657 x->Get(v8_str("get"));
7658 x->Set(v8_str("set"), v8::Integer::New(8));
7659 x->Get(v8_str("get"));
7660 x->Set(v8_str("set"), v8::Integer::New(8));
7661 x->Get(v8_str("get"));
7662 x->Set(v8_str("set"), v8::Integer::New(8));
7663 x->Get(v8_str("get"));
7664}
7665
7666
7667THREADED_TEST(Constructor) {
7668 v8::HandleScope handle_scope;
7669 LocalContext context;
7670 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7671 templ->SetClassName(v8_str("Fun"));
7672 Local<Function> cons = templ->GetFunction();
7673 context->Global()->Set(v8_str("Fun"), cons);
7674 Local<v8::Object> inst = cons->NewInstance();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007675 i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007676 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
7677 CHECK(value->BooleanValue());
7678}
7679
lrn@chromium.org1c092762011-05-09 09:42:16 +00007680
7681static Handle<Value> ConstructorCallback(const Arguments& args) {
7682 ApiTestFuzzer::Fuzz();
7683 Local<Object> This;
7684
7685 if (args.IsConstructCall()) {
7686 Local<Object> Holder = args.Holder();
7687 This = Object::New();
7688 Local<Value> proto = Holder->GetPrototype();
7689 if (proto->IsObject()) {
7690 This->SetPrototype(proto);
7691 }
7692 } else {
7693 This = args.This();
7694 }
7695
7696 This->Set(v8_str("a"), args[0]);
7697 return This;
7698}
7699
7700
7701static Handle<Value> FakeConstructorCallback(const Arguments& args) {
7702 ApiTestFuzzer::Fuzz();
7703 return args[0];
7704}
7705
7706
7707THREADED_TEST(ConstructorForObject) {
7708 v8::HandleScope handle_scope;
7709 LocalContext context;
7710
7711 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7712 instance_template->SetCallAsFunctionHandler(ConstructorCallback);
7713 Local<Object> instance = instance_template->NewInstance();
7714 context->Global()->Set(v8_str("obj"), instance);
7715 v8::TryCatch try_catch;
7716 Local<Value> value;
7717 CHECK(!try_catch.HasCaught());
7718
7719 // Call the Object's constructor with a 32-bit signed integer.
7720 value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
7721 CHECK(!try_catch.HasCaught());
7722 CHECK(value->IsInt32());
7723 CHECK_EQ(28, value->Int32Value());
7724
7725 Local<Value> args1[] = { v8_num(28) };
7726 Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
7727 CHECK(value_obj1->IsObject());
7728 Local<Object> object1 = Local<Object>::Cast(value_obj1);
7729 value = object1->Get(v8_str("a"));
7730 CHECK(value->IsInt32());
7731 CHECK(!try_catch.HasCaught());
7732 CHECK_EQ(28, value->Int32Value());
7733
7734 // Call the Object's constructor with a String.
7735 value = CompileRun(
7736 "(function() { var o = new obj('tipli'); return o.a; })()");
7737 CHECK(!try_catch.HasCaught());
7738 CHECK(value->IsString());
7739 String::AsciiValue string_value1(value->ToString());
7740 CHECK_EQ("tipli", *string_value1);
7741
7742 Local<Value> args2[] = { v8_str("tipli") };
7743 Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
7744 CHECK(value_obj2->IsObject());
7745 Local<Object> object2 = Local<Object>::Cast(value_obj2);
7746 value = object2->Get(v8_str("a"));
7747 CHECK(!try_catch.HasCaught());
7748 CHECK(value->IsString());
7749 String::AsciiValue string_value2(value->ToString());
7750 CHECK_EQ("tipli", *string_value2);
7751
7752 // Call the Object's constructor with a Boolean.
7753 value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
7754 CHECK(!try_catch.HasCaught());
7755 CHECK(value->IsBoolean());
7756 CHECK_EQ(true, value->BooleanValue());
7757
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00007758 Handle<Value> args3[] = { v8::True() };
lrn@chromium.org1c092762011-05-09 09:42:16 +00007759 Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
7760 CHECK(value_obj3->IsObject());
7761 Local<Object> object3 = Local<Object>::Cast(value_obj3);
7762 value = object3->Get(v8_str("a"));
7763 CHECK(!try_catch.HasCaught());
7764 CHECK(value->IsBoolean());
7765 CHECK_EQ(true, value->BooleanValue());
7766
7767 // Call the Object's constructor with undefined.
7768 Handle<Value> args4[] = { v8::Undefined() };
7769 Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
7770 CHECK(value_obj4->IsObject());
7771 Local<Object> object4 = Local<Object>::Cast(value_obj4);
7772 value = object4->Get(v8_str("a"));
7773 CHECK(!try_catch.HasCaught());
7774 CHECK(value->IsUndefined());
7775
7776 // Call the Object's constructor with null.
7777 Handle<Value> args5[] = { v8::Null() };
7778 Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
7779 CHECK(value_obj5->IsObject());
7780 Local<Object> object5 = Local<Object>::Cast(value_obj5);
7781 value = object5->Get(v8_str("a"));
7782 CHECK(!try_catch.HasCaught());
7783 CHECK(value->IsNull());
7784 }
7785
7786 // Check exception handling when there is no constructor set for the Object.
7787 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7788 Local<Object> instance = instance_template->NewInstance();
7789 context->Global()->Set(v8_str("obj2"), instance);
7790 v8::TryCatch try_catch;
7791 Local<Value> value;
7792 CHECK(!try_catch.HasCaught());
7793
7794 value = CompileRun("new obj2(28)");
7795 CHECK(try_catch.HasCaught());
7796 String::AsciiValue exception_value1(try_catch.Exception());
7797 CHECK_EQ("TypeError: object is not a function", *exception_value1);
7798 try_catch.Reset();
7799
7800 Local<Value> args[] = { v8_num(29) };
7801 value = instance->CallAsConstructor(1, args);
7802 CHECK(try_catch.HasCaught());
7803 String::AsciiValue exception_value2(try_catch.Exception());
7804 CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
7805 try_catch.Reset();
7806 }
7807
7808 // Check the case when constructor throws exception.
7809 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7810 instance_template->SetCallAsFunctionHandler(ThrowValue);
7811 Local<Object> instance = instance_template->NewInstance();
7812 context->Global()->Set(v8_str("obj3"), instance);
7813 v8::TryCatch try_catch;
7814 Local<Value> value;
7815 CHECK(!try_catch.HasCaught());
7816
7817 value = CompileRun("new obj3(22)");
7818 CHECK(try_catch.HasCaught());
7819 String::AsciiValue exception_value1(try_catch.Exception());
7820 CHECK_EQ("22", *exception_value1);
7821 try_catch.Reset();
7822
7823 Local<Value> args[] = { v8_num(23) };
7824 value = instance->CallAsConstructor(1, args);
7825 CHECK(try_catch.HasCaught());
7826 String::AsciiValue exception_value2(try_catch.Exception());
7827 CHECK_EQ("23", *exception_value2);
7828 try_catch.Reset();
7829 }
7830
7831 // Check whether constructor returns with an object or non-object.
7832 { Local<FunctionTemplate> function_template =
7833 FunctionTemplate::New(FakeConstructorCallback);
7834 Local<Function> function = function_template->GetFunction();
7835 Local<Object> instance1 = function;
7836 context->Global()->Set(v8_str("obj4"), instance1);
7837 v8::TryCatch try_catch;
7838 Local<Value> value;
7839 CHECK(!try_catch.HasCaught());
7840
7841 CHECK(instance1->IsObject());
7842 CHECK(instance1->IsFunction());
7843
7844 value = CompileRun("new obj4(28)");
7845 CHECK(!try_catch.HasCaught());
7846 CHECK(value->IsObject());
7847
7848 Local<Value> args1[] = { v8_num(28) };
7849 value = instance1->CallAsConstructor(1, args1);
7850 CHECK(!try_catch.HasCaught());
7851 CHECK(value->IsObject());
7852
7853 Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7854 instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
7855 Local<Object> instance2 = instance_template->NewInstance();
7856 context->Global()->Set(v8_str("obj5"), instance2);
7857 CHECK(!try_catch.HasCaught());
7858
7859 CHECK(instance2->IsObject());
7860 CHECK(!instance2->IsFunction());
7861
7862 value = CompileRun("new obj5(28)");
7863 CHECK(!try_catch.HasCaught());
7864 CHECK(!value->IsObject());
7865
7866 Local<Value> args2[] = { v8_num(28) };
7867 value = instance2->CallAsConstructor(1, args2);
7868 CHECK(!try_catch.HasCaught());
7869 CHECK(!value->IsObject());
7870 }
7871}
7872
7873
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007874THREADED_TEST(FunctionDescriptorException) {
7875 v8::HandleScope handle_scope;
7876 LocalContext context;
7877 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7878 templ->SetClassName(v8_str("Fun"));
7879 Local<Function> cons = templ->GetFunction();
7880 context->Global()->Set(v8_str("Fun"), cons);
7881 Local<Value> value = CompileRun(
7882 "function test() {"
7883 " try {"
7884 " (new Fun()).blah()"
7885 " } catch (e) {"
7886 " var str = String(e);"
7887 " if (str.indexOf('TypeError') == -1) return 1;"
7888 " if (str.indexOf('[object Fun]') != -1) return 2;"
whesse@chromium.org7a392b32011-01-31 11:30:36 +00007889 " if (str.indexOf('#<Fun>') == -1) return 3;"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007890 " return 0;"
7891 " }"
7892 " return 4;"
7893 "}"
7894 "test();");
7895 CHECK_EQ(0, value->Int32Value());
7896}
7897
7898
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007899THREADED_TEST(EvalAliasedDynamic) {
7900 v8::HandleScope scope;
7901 LocalContext current;
7902
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007903 // Tests where aliased eval can only be resolved dynamically.
7904 Local<Script> script =
7905 Script::Compile(v8_str("function f(x) { "
7906 " var foo = 2;"
7907 " with (x) { return eval('foo'); }"
7908 "}"
7909 "foo = 0;"
7910 "result1 = f(new Object());"
ager@chromium.orge2902be2009-06-08 12:21:35 +00007911 "result2 = f(this);"
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007912 "var x = new Object();"
7913 "x.eval = function(x) { return 1; };"
7914 "result3 = f(x);"));
7915 script->Run();
7916 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
7917 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
7918 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
7919
7920 v8::TryCatch try_catch;
7921 script =
7922 Script::Compile(v8_str("function f(x) { "
7923 " var bar = 2;"
7924 " with (x) { return eval('bar'); }"
7925 "}"
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007926 "result4 = f(this)"));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007927 script->Run();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007928 CHECK(!try_catch.HasCaught());
7929 CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
7930
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007931 try_catch.Reset();
7932}
7933
7934
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007935THREADED_TEST(CrossEval) {
7936 v8::HandleScope scope;
7937 LocalContext other;
7938 LocalContext current;
7939
7940 Local<String> token = v8_str("<security token>");
7941 other->SetSecurityToken(token);
7942 current->SetSecurityToken(token);
7943
7944 // Setup reference from current to other.
7945 current->Global()->Set(v8_str("other"), other->Global());
7946
7947 // Check that new variables are introduced in other context.
7948 Local<Script> script =
7949 Script::Compile(v8_str("other.eval('var foo = 1234')"));
7950 script->Run();
7951 Local<Value> foo = other->Global()->Get(v8_str("foo"));
7952 CHECK_EQ(1234, foo->Int32Value());
7953 CHECK(!current->Global()->Has(v8_str("foo")));
7954
7955 // Check that writing to non-existing properties introduces them in
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007956 // the other context.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007957 script =
7958 Script::Compile(v8_str("other.eval('na = 1234')"));
7959 script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007960 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
7961 CHECK(!current->Global()->Has(v8_str("na")));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007962
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007963 // Check that global variables in current context are not visible in other
7964 // context.
7965 v8::TryCatch try_catch;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007966 script =
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007967 Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007968 Local<Value> result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007969 CHECK(try_catch.HasCaught());
7970 try_catch.Reset();
7971
7972 // Check that local variables in current context are not visible in other
7973 // context.
7974 script =
7975 Script::Compile(v8_str("(function() { "
7976 " var baz = 87;"
7977 " return other.eval('baz');"
7978 "})();"));
7979 result = script->Run();
7980 CHECK(try_catch.HasCaught());
7981 try_catch.Reset();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007982
7983 // Check that global variables in the other environment are visible
7984 // when evaluting code.
7985 other->Global()->Set(v8_str("bis"), v8_num(1234));
7986 script = Script::Compile(v8_str("other.eval('bis')"));
7987 CHECK_EQ(1234, script->Run()->Int32Value());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007988 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007989
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007990 // Check that the 'this' pointer points to the global object evaluating
7991 // code.
7992 other->Global()->Set(v8_str("t"), other->Global());
7993 script = Script::Compile(v8_str("other.eval('this == t')"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007994 result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007995 CHECK(result->IsTrue());
7996 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007997
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007998 // Check that variables introduced in with-statement are not visible in
7999 // other context.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008000 script =
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008001 Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008002 result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008003 CHECK(try_catch.HasCaught());
8004 try_catch.Reset();
ager@chromium.org3bf7b912008-11-17 09:09:45 +00008005
8006 // Check that you cannot use 'eval.call' with another object than the
8007 // current global object.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00008008 script =
8009 Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
8010 result = script->Run();
8011 CHECK(try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008012}
8013
8014
ager@chromium.orge2902be2009-06-08 12:21:35 +00008015// Test that calling eval in a context which has been detached from
8016// its global throws an exception. This behavior is consistent with
8017// other JavaScript implementations.
8018THREADED_TEST(EvalInDetachedGlobal) {
8019 v8::HandleScope scope;
8020
8021 v8::Persistent<Context> context0 = Context::New();
8022 v8::Persistent<Context> context1 = Context::New();
8023
8024 // Setup function in context0 that uses eval from context0.
8025 context0->Enter();
8026 v8::Handle<v8::Value> fun =
8027 CompileRun("var x = 42;"
8028 "(function() {"
8029 " var e = eval;"
8030 " return function(s) { return e(s); }"
8031 "})()");
8032 context0->Exit();
8033
8034 // Put the function into context1 and call it before and after
8035 // detaching the global. Before detaching, the call succeeds and
8036 // after detaching and exception is thrown.
8037 context1->Enter();
8038 context1->Global()->Set(v8_str("fun"), fun);
8039 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
8040 CHECK_EQ(42, x_value->Int32Value());
8041 context0->DetachGlobal();
8042 v8::TryCatch catcher;
8043 x_value = CompileRun("fun('x')");
8044 CHECK(x_value.IsEmpty());
8045 CHECK(catcher.HasCaught());
8046 context1->Exit();
8047
8048 context1.Dispose();
8049 context0.Dispose();
8050}
8051
8052
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008053THREADED_TEST(CrossLazyLoad) {
8054 v8::HandleScope scope;
8055 LocalContext other;
8056 LocalContext current;
8057
8058 Local<String> token = v8_str("<security token>");
8059 other->SetSecurityToken(token);
8060 current->SetSecurityToken(token);
8061
8062 // Setup reference from current to other.
8063 current->Global()->Set(v8_str("other"), other->Global());
8064
8065 // Trigger lazy loading in other context.
8066 Local<Script> script =
8067 Script::Compile(v8_str("other.eval('new Date(42)')"));
8068 Local<Value> value = script->Run();
8069 CHECK_EQ(42.0, value->NumberValue());
8070}
8071
8072
8073static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
8074 ApiTestFuzzer::Fuzz();
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008075 if (args.IsConstructCall()) {
8076 if (args[0]->IsInt32()) {
8077 return v8_num(-args[0]->Int32Value());
8078 }
8079 }
8080
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008081 return args[0];
8082}
8083
8084
8085// Test that a call handler can be set for objects which will allow
8086// non-function objects created through the API to be called as
8087// functions.
8088THREADED_TEST(CallAsFunction) {
8089 v8::HandleScope scope;
8090 LocalContext context;
8091
lrn@chromium.org1c092762011-05-09 09:42:16 +00008092 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8093 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
8094 instance_template->SetCallAsFunctionHandler(call_as_function);
8095 Local<v8::Object> instance = t->GetFunction()->NewInstance();
8096 context->Global()->Set(v8_str("obj"), instance);
8097 v8::TryCatch try_catch;
8098 Local<Value> value;
8099 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008100
lrn@chromium.org1c092762011-05-09 09:42:16 +00008101 value = CompileRun("obj(42)");
8102 CHECK(!try_catch.HasCaught());
8103 CHECK_EQ(42, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008104
lrn@chromium.org1c092762011-05-09 09:42:16 +00008105 value = CompileRun("(function(o){return o(49)})(obj)");
8106 CHECK(!try_catch.HasCaught());
8107 CHECK_EQ(49, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008108
lrn@chromium.org1c092762011-05-09 09:42:16 +00008109 // test special case of call as function
8110 value = CompileRun("[obj]['0'](45)");
8111 CHECK(!try_catch.HasCaught());
8112 CHECK_EQ(45, value->Int32Value());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008113
lrn@chromium.org1c092762011-05-09 09:42:16 +00008114 value = CompileRun("obj.call = Function.prototype.call;"
8115 "obj.call(null, 87)");
8116 CHECK(!try_catch.HasCaught());
8117 CHECK_EQ(87, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008118
lrn@chromium.org1c092762011-05-09 09:42:16 +00008119 // Regression tests for bug #1116356: Calling call through call/apply
8120 // must work for non-function receivers.
8121 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
8122 value = CompileRun(apply_99);
8123 CHECK(!try_catch.HasCaught());
8124 CHECK_EQ(99, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008125
lrn@chromium.org1c092762011-05-09 09:42:16 +00008126 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
8127 value = CompileRun(call_17);
8128 CHECK(!try_catch.HasCaught());
8129 CHECK_EQ(17, value->Int32Value());
ager@chromium.org9085a012009-05-11 19:22:57 +00008130
lrn@chromium.org1c092762011-05-09 09:42:16 +00008131 // Check that the call-as-function handler can be called through
8132 // new.
8133 value = CompileRun("new obj(43)");
8134 CHECK(!try_catch.HasCaught());
8135 CHECK_EQ(-43, value->Int32Value());
8136
8137 // Check that the call-as-function handler can be called through
8138 // the API.
8139 v8::Handle<Value> args[] = { v8_num(28) };
8140 value = instance->CallAsFunction(instance, 1, args);
8141 CHECK(!try_catch.HasCaught());
8142 CHECK_EQ(28, value->Int32Value());
8143 }
8144
8145 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008146 Local<ObjectTemplate> instance_template(t->InstanceTemplate());
lrn@chromium.org1c092762011-05-09 09:42:16 +00008147 Local<v8::Object> instance = t->GetFunction()->NewInstance();
8148 context->Global()->Set(v8_str("obj2"), instance);
8149 v8::TryCatch try_catch;
8150 Local<Value> value;
8151 CHECK(!try_catch.HasCaught());
8152
8153 // Call an object without call-as-function handler through the JS
8154 value = CompileRun("obj2(28)");
8155 CHECK(value.IsEmpty());
8156 CHECK(try_catch.HasCaught());
8157 String::AsciiValue exception_value1(try_catch.Exception());
8158 CHECK_EQ("TypeError: Property 'obj2' of object #<Object> is not a function",
8159 *exception_value1);
8160 try_catch.Reset();
8161
8162 // Call an object without call-as-function handler through the API
8163 value = CompileRun("obj2(28)");
8164 v8::Handle<Value> args[] = { v8_num(28) };
8165 value = instance->CallAsFunction(instance, 1, args);
8166 CHECK(value.IsEmpty());
8167 CHECK(try_catch.HasCaught());
8168 String::AsciiValue exception_value2(try_catch.Exception());
8169 CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
8170 try_catch.Reset();
8171 }
8172
8173 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8174 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
8175 instance_template->SetCallAsFunctionHandler(ThrowValue);
8176 Local<v8::Object> instance = t->GetFunction()->NewInstance();
8177 context->Global()->Set(v8_str("obj3"), instance);
8178 v8::TryCatch try_catch;
8179 Local<Value> value;
8180 CHECK(!try_catch.HasCaught());
8181
8182 // Catch the exception which is thrown by call-as-function handler
8183 value = CompileRun("obj3(22)");
8184 CHECK(try_catch.HasCaught());
8185 String::AsciiValue exception_value1(try_catch.Exception());
8186 CHECK_EQ("22", *exception_value1);
8187 try_catch.Reset();
8188
8189 v8::Handle<Value> args[] = { v8_num(23) };
8190 value = instance->CallAsFunction(instance, 1, args);
8191 CHECK(try_catch.HasCaught());
8192 String::AsciiValue exception_value2(try_catch.Exception());
8193 CHECK_EQ("23", *exception_value2);
8194 try_catch.Reset();
8195 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008196}
8197
8198
karlklose@chromium.org83a47282011-05-11 11:54:09 +00008199// Check whether a non-function object is callable.
8200THREADED_TEST(CallableObject) {
8201 v8::HandleScope scope;
8202 LocalContext context;
8203
8204 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8205 instance_template->SetCallAsFunctionHandler(call_as_function);
8206 Local<Object> instance = instance_template->NewInstance();
8207 v8::TryCatch try_catch;
8208
8209 CHECK(instance->IsCallable());
8210 CHECK(!try_catch.HasCaught());
8211 }
8212
8213 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8214 Local<Object> instance = instance_template->NewInstance();
8215 v8::TryCatch try_catch;
8216
8217 CHECK(!instance->IsCallable());
8218 CHECK(!try_catch.HasCaught());
8219 }
8220
8221 { Local<FunctionTemplate> function_template =
8222 FunctionTemplate::New(call_as_function);
8223 Local<Function> function = function_template->GetFunction();
8224 Local<Object> instance = function;
8225 v8::TryCatch try_catch;
8226
8227 CHECK(instance->IsCallable());
8228 CHECK(!try_catch.HasCaught());
8229 }
8230
8231 { Local<FunctionTemplate> function_template = FunctionTemplate::New();
8232 Local<Function> function = function_template->GetFunction();
8233 Local<Object> instance = function;
8234 v8::TryCatch try_catch;
8235
8236 CHECK(instance->IsCallable());
8237 CHECK(!try_catch.HasCaught());
8238 }
8239}
8240
8241
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008242static int CountHandles() {
8243 return v8::HandleScope::NumberOfHandles();
8244}
8245
8246
8247static int Recurse(int depth, int iterations) {
8248 v8::HandleScope scope;
8249 if (depth == 0) return CountHandles();
8250 for (int i = 0; i < iterations; i++) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008251 Local<v8::Number> n(v8::Integer::New(42));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008252 }
8253 return Recurse(depth - 1, iterations);
8254}
8255
8256
8257THREADED_TEST(HandleIteration) {
8258 static const int kIterations = 500;
8259 static const int kNesting = 200;
8260 CHECK_EQ(0, CountHandles());
8261 {
8262 v8::HandleScope scope1;
8263 CHECK_EQ(0, CountHandles());
8264 for (int i = 0; i < kIterations; i++) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008265 Local<v8::Number> n(v8::Integer::New(42));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008266 CHECK_EQ(i + 1, CountHandles());
8267 }
8268
8269 CHECK_EQ(kIterations, CountHandles());
8270 {
8271 v8::HandleScope scope2;
8272 for (int j = 0; j < kIterations; j++) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008273 Local<v8::Number> n(v8::Integer::New(42));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008274 CHECK_EQ(j + 1 + kIterations, CountHandles());
8275 }
8276 }
8277 CHECK_EQ(kIterations, CountHandles());
8278 }
8279 CHECK_EQ(0, CountHandles());
8280 CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
8281}
8282
8283
8284static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
8285 Local<String> name,
8286 const AccessorInfo& info) {
8287 ApiTestFuzzer::Fuzz();
8288 return v8::Handle<Value>();
8289}
8290
8291
8292THREADED_TEST(InterceptorHasOwnProperty) {
8293 v8::HandleScope scope;
8294 LocalContext context;
8295 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8296 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
8297 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
8298 Local<Function> function = fun_templ->GetFunction();
8299 context->Global()->Set(v8_str("constructor"), function);
8300 v8::Handle<Value> value = CompileRun(
8301 "var o = new constructor();"
8302 "o.hasOwnProperty('ostehaps');");
8303 CHECK_EQ(false, value->BooleanValue());
8304 value = CompileRun(
8305 "o.ostehaps = 42;"
8306 "o.hasOwnProperty('ostehaps');");
8307 CHECK_EQ(true, value->BooleanValue());
8308 value = CompileRun(
8309 "var p = new constructor();"
8310 "p.hasOwnProperty('ostehaps');");
8311 CHECK_EQ(false, value->BooleanValue());
8312}
8313
8314
ager@chromium.org9085a012009-05-11 19:22:57 +00008315static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
8316 Local<String> name,
8317 const AccessorInfo& info) {
8318 ApiTestFuzzer::Fuzz();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008319 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org9085a012009-05-11 19:22:57 +00008320 return v8::Handle<Value>();
8321}
8322
8323
8324THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
8325 v8::HandleScope scope;
8326 LocalContext context;
8327 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8328 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
8329 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
8330 Local<Function> function = fun_templ->GetFunction();
8331 context->Global()->Set(v8_str("constructor"), function);
8332 // Let's first make some stuff so we can be sure to get a good GC.
8333 CompileRun(
8334 "function makestr(size) {"
8335 " switch (size) {"
8336 " case 1: return 'f';"
8337 " case 2: return 'fo';"
8338 " case 3: return 'foo';"
8339 " }"
8340 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
8341 "}"
8342 "var x = makestr(12345);"
8343 "x = makestr(31415);"
8344 "x = makestr(23456);");
8345 v8::Handle<Value> value = CompileRun(
8346 "var o = new constructor();"
8347 "o.__proto__ = new String(x);"
8348 "o.hasOwnProperty('ostehaps');");
8349 CHECK_EQ(false, value->BooleanValue());
8350}
8351
8352
ager@chromium.orge2902be2009-06-08 12:21:35 +00008353typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
8354 const AccessorInfo& info);
8355
8356
8357static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
8358 const char* source,
8359 int expected) {
8360 v8::HandleScope scope;
8361 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008362 templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
ager@chromium.orge2902be2009-06-08 12:21:35 +00008363 LocalContext context;
8364 context->Global()->Set(v8_str("o"), templ->NewInstance());
8365 v8::Handle<Value> value = CompileRun(source);
8366 CHECK_EQ(expected, value->Int32Value());
8367}
8368
8369
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008370static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
8371 const AccessorInfo& info) {
8372 ApiTestFuzzer::Fuzz();
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008373 CHECK_EQ(v8_str("data"), info.Data());
8374 CHECK_EQ(v8_str("x"), name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008375 return v8::Integer::New(42);
8376}
8377
8378
8379// This test should hit the load IC for the interceptor case.
8380THREADED_TEST(InterceptorLoadIC) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00008381 CheckInterceptorLoadIC(InterceptorLoadICGetter,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008382 "var result = 0;"
8383 "for (var i = 0; i < 1000; i++) {"
8384 " result = o.x;"
ager@chromium.orge2902be2009-06-08 12:21:35 +00008385 "}",
8386 42);
8387}
8388
8389
8390// Below go several tests which verify that JITing for various
8391// configurations of interceptor and explicit fields works fine
8392// (those cases are special cased to get better performance).
8393
8394static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
8395 const AccessorInfo& info) {
8396 ApiTestFuzzer::Fuzz();
8397 return v8_str("x")->Equals(name)
8398 ? v8::Integer::New(42) : v8::Handle<v8::Value>();
8399}
8400
8401
8402THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
8403 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8404 "var result = 0;"
8405 "o.y = 239;"
8406 "for (var i = 0; i < 1000; i++) {"
8407 " result = o.y;"
8408 "}",
8409 239);
8410}
8411
8412
8413THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
8414 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8415 "var result = 0;"
8416 "o.__proto__ = { 'y': 239 };"
8417 "for (var i = 0; i < 1000; i++) {"
8418 " result = o.y + o.x;"
8419 "}",
8420 239 + 42);
8421}
8422
8423
8424THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
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(InterceptorLoadICUndefined) {
8436 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8437 "var result = 0;"
8438 "for (var i = 0; i < 1000; i++) {"
8439 " result = (o.y == undefined) ? 239 : 42;"
8440 "}",
8441 239);
8442}
8443
8444
8445THREADED_TEST(InterceptorLoadICWithOverride) {
8446 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8447 "fst = new Object(); fst.__proto__ = o;"
8448 "snd = new Object(); snd.__proto__ = fst;"
8449 "var result1 = 0;"
8450 "for (var i = 0; i < 1000; i++) {"
8451 " result1 = snd.x;"
8452 "}"
8453 "fst.x = 239;"
8454 "var result = 0;"
8455 "for (var i = 0; i < 1000; i++) {"
8456 " result = snd.x;"
8457 "}"
8458 "result + result1",
8459 239 + 42);
8460}
8461
8462
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008463// Test the case when we stored field into
8464// a stub, but interceptor produced value on its own.
8465THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
8466 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8467 "proto = new Object();"
8468 "o.__proto__ = proto;"
8469 "proto.x = 239;"
8470 "for (var i = 0; i < 1000; i++) {"
8471 " o.x;"
8472 // Now it should be ICed and keep a reference to x defined on proto
8473 "}"
8474 "var result = 0;"
8475 "for (var i = 0; i < 1000; i++) {"
8476 " result += o.x;"
8477 "}"
8478 "result;",
8479 42 * 1000);
8480}
8481
8482
8483// Test the case when we stored field into
8484// a stub, but it got invalidated later on.
8485THREADED_TEST(InterceptorLoadICInvalidatedField) {
8486 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8487 "proto1 = new Object();"
8488 "proto2 = new Object();"
8489 "o.__proto__ = proto1;"
8490 "proto1.__proto__ = proto2;"
8491 "proto2.y = 239;"
8492 "for (var i = 0; i < 1000; i++) {"
8493 " o.y;"
8494 // Now it should be ICed and keep a reference to y defined on proto2
8495 "}"
8496 "proto1.y = 42;"
8497 "var result = 0;"
8498 "for (var i = 0; i < 1000; i++) {"
8499 " result += o.y;"
8500 "}"
8501 "result;",
8502 42 * 1000);
8503}
8504
8505
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00008506static int interceptor_load_not_handled_calls = 0;
8507static v8::Handle<Value> InterceptorLoadNotHandled(Local<String> name,
8508 const AccessorInfo& info) {
8509 ++interceptor_load_not_handled_calls;
8510 return v8::Handle<v8::Value>();
8511}
8512
8513
8514// Test how post-interceptor lookups are done in the non-cacheable
8515// case: the interceptor should not be invoked during this lookup.
8516THREADED_TEST(InterceptorLoadICPostInterceptor) {
8517 interceptor_load_not_handled_calls = 0;
8518 CheckInterceptorLoadIC(InterceptorLoadNotHandled,
8519 "receiver = new Object();"
8520 "receiver.__proto__ = o;"
8521 "proto = new Object();"
8522 "/* Make proto a slow-case object. */"
8523 "for (var i = 0; i < 1000; i++) {"
8524 " proto[\"xxxxxxxx\" + i] = [];"
8525 "}"
8526 "proto.x = 17;"
8527 "o.__proto__ = proto;"
8528 "var result = 0;"
8529 "for (var i = 0; i < 1000; i++) {"
8530 " result += receiver.x;"
8531 "}"
8532 "result;",
8533 17 * 1000);
8534 CHECK_EQ(1000, interceptor_load_not_handled_calls);
8535}
8536
8537
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008538// Test the case when we stored field into
8539// a stub, but it got invalidated later on due to override on
8540// global object which is between interceptor and fields' holders.
8541THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
8542 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8543 "o.__proto__ = this;" // set a global to be a proto of o.
8544 "this.__proto__.y = 239;"
8545 "for (var i = 0; i < 10; i++) {"
8546 " if (o.y != 239) throw 'oops: ' + o.y;"
8547 // Now it should be ICed and keep a reference to y defined on field_holder.
8548 "}"
8549 "this.y = 42;" // Assign on a global.
8550 "var result = 0;"
8551 "for (var i = 0; i < 10; i++) {"
8552 " result += o.y;"
8553 "}"
8554 "result;",
8555 42 * 10);
8556}
8557
8558
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008559static void SetOnThis(Local<String> name,
8560 Local<Value> value,
8561 const AccessorInfo& info) {
8562 info.This()->ForceSet(name, value);
8563}
8564
8565
8566THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
8567 v8::HandleScope scope;
8568 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8569 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8570 templ->SetAccessor(v8_str("y"), Return239);
8571 LocalContext context;
8572 context->Global()->Set(v8_str("o"), templ->NewInstance());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008573
8574 // Check the case when receiver and interceptor's holder
8575 // are the same objects.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008576 v8::Handle<Value> value = CompileRun(
8577 "var result = 0;"
8578 "for (var i = 0; i < 7; i++) {"
8579 " result = o.y;"
8580 "}");
8581 CHECK_EQ(239, value->Int32Value());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008582
8583 // Check the case when interceptor's holder is in proto chain
8584 // of receiver.
8585 value = CompileRun(
8586 "r = { __proto__: o };"
8587 "var result = 0;"
8588 "for (var i = 0; i < 7; i++) {"
8589 " result = r.y;"
8590 "}");
8591 CHECK_EQ(239, value->Int32Value());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008592}
8593
8594
8595THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
8596 v8::HandleScope scope;
8597 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8598 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8599 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8600 templ_p->SetAccessor(v8_str("y"), Return239);
8601
8602 LocalContext context;
8603 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8604 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8605
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008606 // Check the case when receiver and interceptor's holder
8607 // are the same objects.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008608 v8::Handle<Value> value = CompileRun(
8609 "o.__proto__ = p;"
8610 "var result = 0;"
8611 "for (var i = 0; i < 7; i++) {"
8612 " result = o.x + o.y;"
8613 "}");
8614 CHECK_EQ(239 + 42, value->Int32Value());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008615
8616 // Check the case when interceptor's holder is in proto chain
8617 // of receiver.
8618 value = CompileRun(
8619 "r = { __proto__: o };"
8620 "var result = 0;"
8621 "for (var i = 0; i < 7; i++) {"
8622 " result = r.x + r.y;"
8623 "}");
8624 CHECK_EQ(239 + 42, value->Int32Value());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008625}
8626
8627
8628THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
8629 v8::HandleScope scope;
8630 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8631 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8632 templ->SetAccessor(v8_str("y"), Return239);
8633
8634 LocalContext context;
8635 context->Global()->Set(v8_str("o"), templ->NewInstance());
8636
8637 v8::Handle<Value> value = CompileRun(
8638 "fst = new Object(); fst.__proto__ = o;"
8639 "snd = new Object(); snd.__proto__ = fst;"
8640 "var result1 = 0;"
8641 "for (var i = 0; i < 7; i++) {"
8642 " result1 = snd.x;"
8643 "}"
8644 "fst.x = 239;"
8645 "var result = 0;"
8646 "for (var i = 0; i < 7; i++) {"
8647 " result = snd.x;"
8648 "}"
8649 "result + result1");
8650 CHECK_EQ(239 + 42, value->Int32Value());
8651}
8652
8653
8654// Test the case when we stored callback into
8655// a stub, but interceptor produced value on its own.
8656THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
8657 v8::HandleScope scope;
8658 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8659 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8660 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8661 templ_p->SetAccessor(v8_str("y"), Return239);
8662
8663 LocalContext context;
8664 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8665 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8666
8667 v8::Handle<Value> value = CompileRun(
8668 "o.__proto__ = p;"
8669 "for (var i = 0; i < 7; i++) {"
8670 " o.x;"
8671 // Now it should be ICed and keep a reference to x defined on p
8672 "}"
8673 "var result = 0;"
8674 "for (var i = 0; i < 7; i++) {"
8675 " result += o.x;"
8676 "}"
8677 "result");
8678 CHECK_EQ(42 * 7, value->Int32Value());
8679}
8680
8681
8682// Test the case when we stored callback into
8683// a stub, but it got invalidated later on.
8684THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
8685 v8::HandleScope scope;
8686 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8687 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8688 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8689 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
8690
8691 LocalContext context;
8692 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8693 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8694
8695 v8::Handle<Value> value = CompileRun(
8696 "inbetween = new Object();"
8697 "o.__proto__ = inbetween;"
8698 "inbetween.__proto__ = p;"
8699 "for (var i = 0; i < 10; i++) {"
8700 " o.y;"
8701 // Now it should be ICed and keep a reference to y defined on p
8702 "}"
8703 "inbetween.y = 42;"
8704 "var result = 0;"
8705 "for (var i = 0; i < 10; i++) {"
8706 " result += o.y;"
8707 "}"
8708 "result");
8709 CHECK_EQ(42 * 10, value->Int32Value());
8710}
8711
8712
8713// Test the case when we stored callback into
8714// a stub, but it got invalidated later on due to override on
8715// global object which is between interceptor and callbacks' holders.
8716THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
8717 v8::HandleScope scope;
8718 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8719 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8720 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8721 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
8722
8723 LocalContext context;
8724 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8725 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8726
8727 v8::Handle<Value> value = CompileRun(
8728 "o.__proto__ = this;"
8729 "this.__proto__ = p;"
8730 "for (var i = 0; i < 10; i++) {"
8731 " if (o.y != 239) throw 'oops: ' + o.y;"
8732 // Now it should be ICed and keep a reference to y defined on p
8733 "}"
8734 "this.y = 42;"
8735 "var result = 0;"
8736 "for (var i = 0; i < 10; i++) {"
8737 " result += o.y;"
8738 "}"
8739 "result");
8740 CHECK_EQ(42 * 10, value->Int32Value());
8741}
8742
8743
ager@chromium.orge2902be2009-06-08 12:21:35 +00008744static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
8745 const AccessorInfo& info) {
8746 ApiTestFuzzer::Fuzz();
8747 CHECK(v8_str("x")->Equals(name));
8748 return v8::Integer::New(0);
8749}
8750
8751
8752THREADED_TEST(InterceptorReturningZero) {
8753 CheckInterceptorLoadIC(InterceptorLoadICGetter0,
8754 "o.x == undefined ? 1 : 0",
8755 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008756}
8757
8758
8759static v8::Handle<Value> InterceptorStoreICSetter(
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008760 Local<String> key, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008761 CHECK(v8_str("x")->Equals(key));
8762 CHECK_EQ(42, value->Int32Value());
8763 return value;
8764}
8765
8766
8767// This test should hit the store IC for the interceptor case.
8768THREADED_TEST(InterceptorStoreIC) {
8769 v8::HandleScope scope;
8770 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8771 templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008772 InterceptorStoreICSetter,
8773 0, 0, 0, v8_str("data"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008774 LocalContext context;
8775 context->Global()->Set(v8_str("o"), templ->NewInstance());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008776 v8::Handle<Value> value(CompileRun(
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008777 "for (var i = 0; i < 1000; i++) {"
8778 " o.x = 42;"
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008779 "}"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008780}
8781
8782
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008783THREADED_TEST(InterceptorStoreICWithNoSetter) {
8784 v8::HandleScope scope;
8785 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8786 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8787 LocalContext context;
8788 context->Global()->Set(v8_str("o"), templ->NewInstance());
8789 v8::Handle<Value> value = CompileRun(
8790 "for (var i = 0; i < 1000; i++) {"
8791 " o.y = 239;"
8792 "}"
8793 "42 + o.y");
8794 CHECK_EQ(239 + 42, value->Int32Value());
8795}
8796
8797
8798
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008799
8800v8::Handle<Value> call_ic_function;
8801v8::Handle<Value> call_ic_function2;
8802v8::Handle<Value> call_ic_function3;
8803
8804static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
8805 const AccessorInfo& info) {
8806 ApiTestFuzzer::Fuzz();
8807 CHECK(v8_str("x")->Equals(name));
8808 return call_ic_function;
8809}
8810
8811
8812// This test should hit the call IC for the interceptor case.
8813THREADED_TEST(InterceptorCallIC) {
8814 v8::HandleScope scope;
8815 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8816 templ->SetNamedPropertyHandler(InterceptorCallICGetter);
8817 LocalContext context;
8818 context->Global()->Set(v8_str("o"), templ->NewInstance());
8819 call_ic_function =
8820 v8_compile("function f(x) { return x + 1; }; f")->Run();
8821 v8::Handle<Value> value = CompileRun(
8822 "var result = 0;"
8823 "for (var i = 0; i < 1000; i++) {"
8824 " result = o.x(41);"
8825 "}");
8826 CHECK_EQ(42, value->Int32Value());
8827}
8828
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008829
8830// This test checks that if interceptor doesn't provide
8831// a value, we can fetch regular value.
8832THREADED_TEST(InterceptorCallICSeesOthers) {
8833 v8::HandleScope scope;
8834 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8835 templ->SetNamedPropertyHandler(NoBlockGetterX);
8836 LocalContext context;
8837 context->Global()->Set(v8_str("o"), templ->NewInstance());
8838 v8::Handle<Value> value = CompileRun(
8839 "o.x = function f(x) { return x + 1; };"
8840 "var result = 0;"
8841 "for (var i = 0; i < 7; i++) {"
8842 " result = o.x(41);"
8843 "}");
8844 CHECK_EQ(42, value->Int32Value());
8845}
8846
8847
8848static v8::Handle<Value> call_ic_function4;
8849static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
8850 const AccessorInfo& info) {
8851 ApiTestFuzzer::Fuzz();
8852 CHECK(v8_str("x")->Equals(name));
8853 return call_ic_function4;
8854}
8855
8856
8857// This test checks that if interceptor provides a function,
8858// even if we cached shadowed variant, interceptor's function
8859// is invoked
8860THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
8861 v8::HandleScope scope;
8862 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8863 templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
8864 LocalContext context;
8865 context->Global()->Set(v8_str("o"), templ->NewInstance());
8866 call_ic_function4 =
8867 v8_compile("function f(x) { return x - 1; }; f")->Run();
8868 v8::Handle<Value> value = CompileRun(
8869 "o.__proto__.x = function(x) { return x + 1; };"
8870 "var result = 0;"
8871 "for (var i = 0; i < 1000; i++) {"
8872 " result = o.x(42);"
8873 "}");
8874 CHECK_EQ(41, value->Int32Value());
8875}
8876
8877
8878// Test the case when we stored cacheable lookup into
8879// a stub, but it got invalidated later on
8880THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
8881 v8::HandleScope scope;
8882 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8883 templ->SetNamedPropertyHandler(NoBlockGetterX);
8884 LocalContext context;
8885 context->Global()->Set(v8_str("o"), templ->NewInstance());
8886 v8::Handle<Value> value = CompileRun(
8887 "proto1 = new Object();"
8888 "proto2 = new Object();"
8889 "o.__proto__ = proto1;"
8890 "proto1.__proto__ = proto2;"
8891 "proto2.y = function(x) { return x + 1; };"
8892 // Invoke it many times to compile a stub
8893 "for (var i = 0; i < 7; i++) {"
8894 " o.y(42);"
8895 "}"
8896 "proto1.y = function(x) { return x - 1; };"
8897 "var result = 0;"
8898 "for (var i = 0; i < 7; i++) {"
8899 " result += o.y(42);"
8900 "}");
8901 CHECK_EQ(41 * 7, value->Int32Value());
8902}
8903
8904
8905static v8::Handle<Value> call_ic_function5;
8906static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
8907 const AccessorInfo& info) {
8908 ApiTestFuzzer::Fuzz();
8909 if (v8_str("x")->Equals(name))
8910 return call_ic_function5;
8911 else
8912 return Local<Value>();
8913}
8914
8915
8916// 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
8936// This test checks that if interceptor provides a function,
8937// even if we cached constant function, interceptor's function
8938// is invoked
8939THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
8940 v8::HandleScope scope;
8941 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8942 templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
8943 LocalContext context;
8944 context->Global()->Set(v8_str("o"), templ->NewInstance());
8945 call_ic_function5 =
8946 v8_compile("function f(x) { return x - 1; }; f")->Run();
8947 v8::Handle<Value> value = CompileRun(
8948 "function inc(x) { return x + 1; };"
8949 "inc(1);"
8950 "o.x = inc;"
8951 "var result = 0;"
8952 "for (var i = 0; i < 1000; i++) {"
8953 " result = o.x(42);"
8954 "}");
8955 CHECK_EQ(41, value->Int32Value());
8956}
8957
8958
8959// Test the case when we stored constant function into
8960// a stub, but it got invalidated later on
8961THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
8962 v8::HandleScope scope;
8963 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8964 templ->SetNamedPropertyHandler(NoBlockGetterX);
8965 LocalContext context;
8966 context->Global()->Set(v8_str("o"), templ->NewInstance());
8967 v8::Handle<Value> value = CompileRun(
8968 "function inc(x) { return x + 1; };"
8969 "inc(1);"
8970 "proto1 = new Object();"
8971 "proto2 = new Object();"
8972 "o.__proto__ = proto1;"
8973 "proto1.__proto__ = proto2;"
8974 "proto2.y = inc;"
8975 // Invoke it many times to compile a stub
8976 "for (var i = 0; i < 7; i++) {"
8977 " o.y(42);"
8978 "}"
8979 "proto1.y = function(x) { return x - 1; };"
8980 "var result = 0;"
8981 "for (var i = 0; i < 7; i++) {"
8982 " result += o.y(42);"
8983 "}");
8984 CHECK_EQ(41 * 7, value->Int32Value());
8985}
8986
8987
8988// Test the case when we stored constant function into
8989// a stub, but it got invalidated later on due to override on
8990// global object which is between interceptor and constant function' holders.
8991THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
8992 v8::HandleScope scope;
8993 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8994 templ->SetNamedPropertyHandler(NoBlockGetterX);
8995 LocalContext context;
8996 context->Global()->Set(v8_str("o"), templ->NewInstance());
8997 v8::Handle<Value> value = CompileRun(
8998 "function inc(x) { return x + 1; };"
8999 "inc(1);"
9000 "o.__proto__ = this;"
9001 "this.__proto__.y = inc;"
9002 // Invoke it many times to compile a stub
9003 "for (var i = 0; i < 7; i++) {"
9004 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
9005 "}"
9006 "this.y = function(x) { return x - 1; };"
9007 "var result = 0;"
9008 "for (var i = 0; i < 7; i++) {"
9009 " result += o.y(42);"
9010 "}");
9011 CHECK_EQ(41 * 7, value->Int32Value());
9012}
9013
9014
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009015// Test the case when actual function to call sits on global object.
9016THREADED_TEST(InterceptorCallICCachedFromGlobal) {
9017 v8::HandleScope scope;
9018 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9019 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9020
9021 LocalContext context;
9022 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9023
9024 v8::Handle<Value> value = CompileRun(
9025 "try {"
9026 " o.__proto__ = this;"
9027 " for (var i = 0; i < 10; i++) {"
9028 " var v = o.parseFloat('239');"
9029 " if (v != 239) throw v;"
9030 // Now it should be ICed and keep a reference to parseFloat.
9031 " }"
9032 " var result = 0;"
9033 " for (var i = 0; i < 10; i++) {"
9034 " result += o.parseFloat('239');"
9035 " }"
9036 " result"
9037 "} catch(e) {"
9038 " e"
9039 "};");
9040 CHECK_EQ(239 * 10, value->Int32Value());
9041}
9042
ager@chromium.org5c838252010-02-19 08:53:10 +00009043static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
9044 const AccessorInfo& info) {
9045 ApiTestFuzzer::Fuzz();
9046 int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data()));
9047 ++(*call_count);
9048 if ((*call_count) % 20 == 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009049 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org5c838252010-02-19 08:53:10 +00009050 }
9051 return v8::Handle<Value>();
9052}
9053
9054static v8::Handle<Value> FastApiCallback_TrivialSignature(
9055 const v8::Arguments& args) {
9056 ApiTestFuzzer::Fuzz();
9057 CHECK_EQ(args.This(), args.Holder());
9058 CHECK(args.Data()->Equals(v8_str("method_data")));
9059 return v8::Integer::New(args[0]->Int32Value() + 1);
9060}
9061
9062static v8::Handle<Value> FastApiCallback_SimpleSignature(
9063 const v8::Arguments& args) {
9064 ApiTestFuzzer::Fuzz();
9065 CHECK_EQ(args.This()->GetPrototype(), args.Holder());
9066 CHECK(args.Data()->Equals(v8_str("method_data")));
9067 // Note, we're using HasRealNamedProperty instead of Has to avoid
9068 // invoking the interceptor again.
9069 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
9070 return v8::Integer::New(args[0]->Int32Value() + 1);
9071}
9072
9073// Helper to maximize the odds of object moving.
9074static void GenerateSomeGarbage() {
9075 CompileRun(
9076 "var garbage;"
9077 "for (var i = 0; i < 1000; i++) {"
9078 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
9079 "}"
9080 "garbage = undefined;");
9081}
9082
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009083
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009084v8::Handle<v8::Value> DirectApiCallback(const v8::Arguments& args) {
9085 static int count = 0;
9086 if (count++ % 3 == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009087 HEAP-> CollectAllGarbage(true); // This should move the stub
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009088 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
9089 }
9090 return v8::Handle<v8::Value>();
9091}
9092
9093
9094THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
9095 v8::HandleScope scope;
9096 LocalContext context;
9097 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
9098 nativeobject_templ->Set("callback",
9099 v8::FunctionTemplate::New(DirectApiCallback));
9100 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
9101 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
9102 // call the api function multiple times to ensure direct call stub creation.
9103 CompileRun(
9104 "function f() {"
9105 " for (var i = 1; i <= 30; i++) {"
9106 " nativeobject.callback();"
9107 " }"
9108 "}"
9109 "f();");
9110}
9111
9112
9113v8::Handle<v8::Value> ThrowingDirectApiCallback(const v8::Arguments& args) {
9114 return v8::ThrowException(v8_str("g"));
9115}
9116
9117
9118THREADED_TEST(CallICFastApi_DirectCall_Throw) {
9119 v8::HandleScope scope;
9120 LocalContext context;
9121 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
9122 nativeobject_templ->Set("callback",
9123 v8::FunctionTemplate::New(ThrowingDirectApiCallback));
9124 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
9125 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
9126 // call the api function multiple times to ensure direct call stub creation.
9127 v8::Handle<Value> result = CompileRun(
9128 "var result = '';"
9129 "function f() {"
9130 " for (var i = 1; i <= 5; i++) {"
9131 " try { nativeobject.callback(); } catch (e) { result += e; }"
9132 " }"
9133 "}"
9134 "f(); result;");
9135 CHECK_EQ(v8_str("ggggg"), result);
9136}
9137
9138
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009139v8::Handle<v8::Value> DirectGetterCallback(Local<String> name,
9140 const v8::AccessorInfo& info) {
9141 if (++p_getter_count % 3 == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009142 HEAP->CollectAllGarbage(true);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009143 GenerateSomeGarbage();
9144 }
9145 return v8::Handle<v8::Value>();
9146}
9147
9148
9149THREADED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
9150 v8::HandleScope scope;
9151 LocalContext context;
9152 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
9153 obj->SetAccessor(v8_str("p1"), DirectGetterCallback);
9154 context->Global()->Set(v8_str("o1"), obj->NewInstance());
9155 p_getter_count = 0;
9156 CompileRun(
9157 "function f() {"
9158 " for (var i = 0; i < 30; i++) o1.p1;"
9159 "}"
9160 "f();");
9161 CHECK_EQ(30, p_getter_count);
9162}
9163
9164
9165v8::Handle<v8::Value> ThrowingDirectGetterCallback(
9166 Local<String> name, const v8::AccessorInfo& info) {
9167 return v8::ThrowException(v8_str("g"));
9168}
9169
9170
9171THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
9172 v8::HandleScope scope;
9173 LocalContext context;
9174 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
9175 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
9176 context->Global()->Set(v8_str("o1"), obj->NewInstance());
9177 v8::Handle<Value> result = CompileRun(
9178 "var result = '';"
9179 "for (var i = 0; i < 5; i++) {"
9180 " try { o1.p1; } catch (e) { result += e; }"
9181 "}"
9182 "result;");
9183 CHECK_EQ(v8_str("ggggg"), result);
9184}
9185
9186
ager@chromium.org5c838252010-02-19 08:53:10 +00009187THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
9188 int interceptor_call_count = 0;
9189 v8::HandleScope scope;
9190 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9191 v8::Handle<v8::FunctionTemplate> method_templ =
9192 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
9193 v8_str("method_data"),
9194 v8::Handle<v8::Signature>());
9195 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9196 proto_templ->Set(v8_str("method"), method_templ);
9197 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9198 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9199 NULL, NULL, NULL, NULL,
9200 v8::External::Wrap(&interceptor_call_count));
9201 LocalContext context;
9202 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9203 GenerateSomeGarbage();
9204 context->Global()->Set(v8_str("o"), fun->NewInstance());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009205 v8::Handle<Value> value(CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +00009206 "var result = 0;"
9207 "for (var i = 0; i < 100; i++) {"
9208 " result = o.method(41);"
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009209 "}"));
ager@chromium.org5c838252010-02-19 08:53:10 +00009210 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9211 CHECK_EQ(100, interceptor_call_count);
9212}
9213
9214THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
9215 int interceptor_call_count = 0;
9216 v8::HandleScope scope;
9217 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9218 v8::Handle<v8::FunctionTemplate> method_templ =
9219 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9220 v8_str("method_data"),
9221 v8::Signature::New(fun_templ));
9222 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9223 proto_templ->Set(v8_str("method"), method_templ);
9224 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9225 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9226 NULL, NULL, NULL, NULL,
9227 v8::External::Wrap(&interceptor_call_count));
9228 LocalContext context;
9229 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9230 GenerateSomeGarbage();
9231 context->Global()->Set(v8_str("o"), fun->NewInstance());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009232 v8::Handle<Value> value(CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +00009233 "o.foo = 17;"
9234 "var receiver = {};"
9235 "receiver.__proto__ = o;"
9236 "var result = 0;"
9237 "for (var i = 0; i < 100; i++) {"
9238 " result = receiver.method(41);"
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009239 "}"));
ager@chromium.org5c838252010-02-19 08:53:10 +00009240 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9241 CHECK_EQ(100, interceptor_call_count);
9242}
9243
9244THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
9245 int interceptor_call_count = 0;
9246 v8::HandleScope scope;
9247 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9248 v8::Handle<v8::FunctionTemplate> method_templ =
9249 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9250 v8_str("method_data"),
9251 v8::Signature::New(fun_templ));
9252 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9253 proto_templ->Set(v8_str("method"), method_templ);
9254 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9255 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9256 NULL, NULL, NULL, NULL,
9257 v8::External::Wrap(&interceptor_call_count));
9258 LocalContext context;
9259 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9260 GenerateSomeGarbage();
9261 context->Global()->Set(v8_str("o"), fun->NewInstance());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009262 v8::Handle<Value> value(CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +00009263 "o.foo = 17;"
9264 "var receiver = {};"
9265 "receiver.__proto__ = o;"
9266 "var result = 0;"
9267 "var saved_result = 0;"
9268 "for (var i = 0; i < 100; i++) {"
9269 " result = receiver.method(41);"
9270 " if (i == 50) {"
9271 " saved_result = result;"
9272 " receiver = {method: function(x) { return x - 1 }};"
9273 " }"
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009274 "}"));
ager@chromium.org5c838252010-02-19 08:53:10 +00009275 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
9276 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9277 CHECK_GE(interceptor_call_count, 50);
9278}
9279
9280THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
9281 int interceptor_call_count = 0;
9282 v8::HandleScope scope;
9283 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9284 v8::Handle<v8::FunctionTemplate> method_templ =
9285 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9286 v8_str("method_data"),
9287 v8::Signature::New(fun_templ));
9288 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9289 proto_templ->Set(v8_str("method"), method_templ);
9290 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9291 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9292 NULL, NULL, NULL, NULL,
9293 v8::External::Wrap(&interceptor_call_count));
9294 LocalContext context;
9295 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9296 GenerateSomeGarbage();
9297 context->Global()->Set(v8_str("o"), fun->NewInstance());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009298 v8::Handle<Value> value(CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +00009299 "o.foo = 17;"
9300 "var receiver = {};"
9301 "receiver.__proto__ = o;"
9302 "var result = 0;"
9303 "var saved_result = 0;"
9304 "for (var i = 0; i < 100; i++) {"
9305 " result = receiver.method(41);"
9306 " if (i == 50) {"
9307 " saved_result = result;"
9308 " o.method = function(x) { return x - 1 };"
9309 " }"
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009310 "}"));
ager@chromium.org5c838252010-02-19 08:53:10 +00009311 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
9312 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9313 CHECK_GE(interceptor_call_count, 50);
9314}
9315
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00009316THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
9317 int interceptor_call_count = 0;
9318 v8::HandleScope scope;
9319 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9320 v8::Handle<v8::FunctionTemplate> method_templ =
9321 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9322 v8_str("method_data"),
9323 v8::Signature::New(fun_templ));
9324 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9325 proto_templ->Set(v8_str("method"), method_templ);
9326 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9327 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9328 NULL, NULL, NULL, NULL,
9329 v8::External::Wrap(&interceptor_call_count));
9330 LocalContext context;
9331 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9332 GenerateSomeGarbage();
9333 context->Global()->Set(v8_str("o"), fun->NewInstance());
9334 v8::TryCatch try_catch;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009335 v8::Handle<Value> value(CompileRun(
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00009336 "o.foo = 17;"
9337 "var receiver = {};"
9338 "receiver.__proto__ = o;"
9339 "var result = 0;"
9340 "var saved_result = 0;"
9341 "for (var i = 0; i < 100; i++) {"
9342 " result = receiver.method(41);"
9343 " if (i == 50) {"
9344 " saved_result = result;"
9345 " receiver = 333;"
9346 " }"
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009347 "}"));
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00009348 CHECK(try_catch.HasCaught());
9349 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
9350 try_catch.Exception()->ToString());
9351 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9352 CHECK_GE(interceptor_call_count, 50);
9353}
9354
ager@chromium.org5c838252010-02-19 08:53:10 +00009355THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
9356 int interceptor_call_count = 0;
9357 v8::HandleScope scope;
9358 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9359 v8::Handle<v8::FunctionTemplate> method_templ =
9360 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9361 v8_str("method_data"),
9362 v8::Signature::New(fun_templ));
9363 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9364 proto_templ->Set(v8_str("method"), method_templ);
9365 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9366 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9367 NULL, NULL, NULL, NULL,
9368 v8::External::Wrap(&interceptor_call_count));
9369 LocalContext context;
9370 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9371 GenerateSomeGarbage();
9372 context->Global()->Set(v8_str("o"), fun->NewInstance());
9373 v8::TryCatch try_catch;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009374 v8::Handle<Value> value(CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +00009375 "o.foo = 17;"
9376 "var receiver = {};"
9377 "receiver.__proto__ = o;"
9378 "var result = 0;"
9379 "var saved_result = 0;"
9380 "for (var i = 0; i < 100; i++) {"
9381 " result = receiver.method(41);"
9382 " if (i == 50) {"
9383 " saved_result = result;"
9384 " receiver = {method: receiver.method};"
9385 " }"
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009386 "}"));
ager@chromium.org5c838252010-02-19 08:53:10 +00009387 CHECK(try_catch.HasCaught());
9388 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
9389 try_catch.Exception()->ToString());
9390 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9391 CHECK_GE(interceptor_call_count, 50);
9392}
9393
9394THREADED_TEST(CallICFastApi_TrivialSignature) {
9395 v8::HandleScope scope;
9396 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9397 v8::Handle<v8::FunctionTemplate> method_templ =
9398 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
9399 v8_str("method_data"),
9400 v8::Handle<v8::Signature>());
9401 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9402 proto_templ->Set(v8_str("method"), method_templ);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009403 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
ager@chromium.org5c838252010-02-19 08:53:10 +00009404 LocalContext context;
9405 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9406 GenerateSomeGarbage();
9407 context->Global()->Set(v8_str("o"), fun->NewInstance());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009408 v8::Handle<Value> value(CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +00009409 "var result = 0;"
9410 "for (var i = 0; i < 100; i++) {"
9411 " result = o.method(41);"
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009412 "}"));
ager@chromium.org5c838252010-02-19 08:53:10 +00009413
9414 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9415}
9416
9417THREADED_TEST(CallICFastApi_SimpleSignature) {
9418 v8::HandleScope scope;
9419 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9420 v8::Handle<v8::FunctionTemplate> method_templ =
9421 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9422 v8_str("method_data"),
9423 v8::Signature::New(fun_templ));
9424 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9425 proto_templ->Set(v8_str("method"), method_templ);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009426 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
ager@chromium.org5c838252010-02-19 08:53:10 +00009427 LocalContext context;
9428 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9429 GenerateSomeGarbage();
9430 context->Global()->Set(v8_str("o"), fun->NewInstance());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009431 v8::Handle<Value> value(CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +00009432 "o.foo = 17;"
9433 "var receiver = {};"
9434 "receiver.__proto__ = o;"
9435 "var result = 0;"
9436 "for (var i = 0; i < 100; i++) {"
9437 " result = receiver.method(41);"
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009438 "}"));
ager@chromium.org5c838252010-02-19 08:53:10 +00009439
9440 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9441}
9442
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00009443THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) {
ager@chromium.org5c838252010-02-19 08:53:10 +00009444 v8::HandleScope scope;
9445 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9446 v8::Handle<v8::FunctionTemplate> method_templ =
9447 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9448 v8_str("method_data"),
9449 v8::Signature::New(fun_templ));
9450 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9451 proto_templ->Set(v8_str("method"), method_templ);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009452 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
ager@chromium.org5c838252010-02-19 08:53:10 +00009453 LocalContext context;
9454 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9455 GenerateSomeGarbage();
9456 context->Global()->Set(v8_str("o"), fun->NewInstance());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009457 v8::Handle<Value> value(CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +00009458 "o.foo = 17;"
9459 "var receiver = {};"
9460 "receiver.__proto__ = o;"
9461 "var result = 0;"
9462 "var saved_result = 0;"
9463 "for (var i = 0; i < 100; i++) {"
9464 " result = receiver.method(41);"
9465 " if (i == 50) {"
9466 " saved_result = result;"
9467 " receiver = {method: function(x) { return x - 1 }};"
9468 " }"
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009469 "}"));
ager@chromium.org5c838252010-02-19 08:53:10 +00009470 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
9471 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9472}
9473
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00009474THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) {
9475 v8::HandleScope scope;
9476 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9477 v8::Handle<v8::FunctionTemplate> method_templ =
9478 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9479 v8_str("method_data"),
9480 v8::Signature::New(fun_templ));
9481 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9482 proto_templ->Set(v8_str("method"), method_templ);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009483 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00009484 LocalContext context;
9485 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9486 GenerateSomeGarbage();
9487 context->Global()->Set(v8_str("o"), fun->NewInstance());
9488 v8::TryCatch try_catch;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009489 v8::Handle<Value> value(CompileRun(
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00009490 "o.foo = 17;"
9491 "var receiver = {};"
9492 "receiver.__proto__ = o;"
9493 "var result = 0;"
9494 "var saved_result = 0;"
9495 "for (var i = 0; i < 100; i++) {"
9496 " result = receiver.method(41);"
9497 " if (i == 50) {"
9498 " saved_result = result;"
9499 " receiver = 333;"
9500 " }"
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009501 "}"));
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00009502 CHECK(try_catch.HasCaught());
9503 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
9504 try_catch.Exception()->ToString());
9505 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9506}
9507
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009508
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009509v8::Handle<Value> keyed_call_ic_function;
9510
9511static v8::Handle<Value> InterceptorKeyedCallICGetter(
9512 Local<String> name, const AccessorInfo& info) {
9513 ApiTestFuzzer::Fuzz();
9514 if (v8_str("x")->Equals(name)) {
9515 return keyed_call_ic_function;
9516 }
9517 return v8::Handle<Value>();
9518}
9519
9520
9521// Test the case when we stored cacheable lookup into
9522// a stub, but the function name changed (to another cacheable function).
9523THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
9524 v8::HandleScope scope;
9525 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9526 templ->SetNamedPropertyHandler(NoBlockGetterX);
9527 LocalContext context;
9528 context->Global()->Set(v8_str("o"), templ->NewInstance());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009529 v8::Handle<Value> value(CompileRun(
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009530 "proto = new Object();"
9531 "proto.y = function(x) { return x + 1; };"
9532 "proto.z = function(x) { return x - 1; };"
9533 "o.__proto__ = proto;"
9534 "var result = 0;"
9535 "var method = 'y';"
9536 "for (var i = 0; i < 10; i++) {"
9537 " if (i == 5) { method = 'z'; };"
9538 " result += o[method](41);"
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009539 "}"));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009540 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9541}
9542
9543
9544// Test the case when we stored cacheable lookup into
9545// a stub, but the function name changed (and the new function is present
9546// both before and after the interceptor in the prototype chain).
9547THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
9548 v8::HandleScope scope;
9549 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9550 templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
9551 LocalContext context;
9552 context->Global()->Set(v8_str("proto1"), templ->NewInstance());
9553 keyed_call_ic_function =
9554 v8_compile("function f(x) { return x - 1; }; f")->Run();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009555 v8::Handle<Value> value(CompileRun(
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009556 "o = new Object();"
9557 "proto2 = new Object();"
9558 "o.y = function(x) { return x + 1; };"
9559 "proto2.y = function(x) { return x + 2; };"
9560 "o.__proto__ = proto1;"
9561 "proto1.__proto__ = proto2;"
9562 "var result = 0;"
9563 "var method = 'x';"
9564 "for (var i = 0; i < 10; i++) {"
9565 " if (i == 5) { method = 'y'; };"
9566 " result += o[method](41);"
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009567 "}"));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009568 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9569}
9570
9571
9572// Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
9573// on the global object.
9574THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
9575 v8::HandleScope scope;
9576 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9577 templ->SetNamedPropertyHandler(NoBlockGetterX);
9578 LocalContext context;
9579 context->Global()->Set(v8_str("o"), templ->NewInstance());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009580 v8::Handle<Value> value(CompileRun(
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009581 "function inc(x) { return x + 1; };"
9582 "inc(1);"
9583 "function dec(x) { return x - 1; };"
9584 "dec(1);"
9585 "o.__proto__ = this;"
9586 "this.__proto__.x = inc;"
9587 "this.__proto__.y = dec;"
9588 "var result = 0;"
9589 "var method = 'x';"
9590 "for (var i = 0; i < 10; i++) {"
9591 " if (i == 5) { method = 'y'; };"
9592 " result += o[method](41);"
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009593 "}"));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009594 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9595}
9596
9597
9598// Test the case when actual function to call sits on global object.
9599THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
9600 v8::HandleScope scope;
9601 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9602 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9603 LocalContext context;
9604 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9605
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009606 v8::Handle<Value> value(CompileRun(
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009607 "function len(x) { return x.length; };"
9608 "o.__proto__ = this;"
9609 "var m = 'parseFloat';"
9610 "var result = 0;"
9611 "for (var i = 0; i < 10; i++) {"
9612 " if (i == 5) {"
9613 " m = 'len';"
9614 " saved_result = result;"
9615 " };"
9616 " result = o[m]('239');"
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009617 "}"));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009618 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
9619 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9620}
9621
9622// Test the map transition before the interceptor.
9623THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
9624 v8::HandleScope scope;
9625 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9626 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9627 LocalContext context;
9628 context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
9629
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009630 v8::Handle<Value> value(CompileRun(
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009631 "var o = new Object();"
9632 "o.__proto__ = proto;"
9633 "o.method = function(x) { return x + 1; };"
9634 "var m = 'method';"
9635 "var result = 0;"
9636 "for (var i = 0; i < 10; i++) {"
9637 " if (i == 5) { o.method = function(x) { return x - 1; }; };"
9638 " result += o[m](41);"
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009639 "}"));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009640 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9641}
9642
9643
9644// Test the map transition after the interceptor.
9645THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
9646 v8::HandleScope scope;
9647 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9648 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9649 LocalContext context;
9650 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9651
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009652 v8::Handle<Value> value(CompileRun(
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009653 "var proto = new Object();"
9654 "o.__proto__ = proto;"
9655 "proto.method = function(x) { return x + 1; };"
9656 "var m = 'method';"
9657 "var result = 0;"
9658 "for (var i = 0; i < 10; i++) {"
9659 " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
9660 " result += o[m](41);"
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009661 "}"));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009662 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9663}
9664
9665
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009666static int interceptor_call_count = 0;
9667
9668static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
9669 const AccessorInfo& info) {
9670 ApiTestFuzzer::Fuzz();
9671 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
9672 return call_ic_function2;
9673 }
9674 return v8::Handle<Value>();
9675}
9676
9677
9678// This test should hit load and call ICs for the interceptor case.
9679// Once in a while, the interceptor will reply that a property was not
9680// found in which case we should get a reference error.
9681THREADED_TEST(InterceptorICReferenceErrors) {
9682 v8::HandleScope scope;
9683 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9684 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
9685 LocalContext context(0, templ, v8::Handle<Value>());
9686 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
9687 v8::Handle<Value> value = CompileRun(
9688 "function f() {"
9689 " for (var i = 0; i < 1000; i++) {"
9690 " try { x; } catch(e) { return true; }"
9691 " }"
9692 " return false;"
9693 "};"
9694 "f();");
9695 CHECK_EQ(true, value->BooleanValue());
9696 interceptor_call_count = 0;
9697 value = CompileRun(
9698 "function g() {"
9699 " for (var i = 0; i < 1000; i++) {"
9700 " try { x(42); } catch(e) { return true; }"
9701 " }"
9702 " return false;"
9703 "};"
9704 "g();");
9705 CHECK_EQ(true, value->BooleanValue());
9706}
9707
9708
9709static int interceptor_ic_exception_get_count = 0;
9710
9711static v8::Handle<Value> InterceptorICExceptionGetter(
9712 Local<String> name,
9713 const AccessorInfo& info) {
9714 ApiTestFuzzer::Fuzz();
9715 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
9716 return call_ic_function3;
9717 }
9718 if (interceptor_ic_exception_get_count == 20) {
9719 return v8::ThrowException(v8_num(42));
9720 }
9721 // Do not handle get for properties other than x.
9722 return v8::Handle<Value>();
9723}
9724
9725// Test interceptor load/call IC where the interceptor throws an
9726// exception once in a while.
9727THREADED_TEST(InterceptorICGetterExceptions) {
9728 interceptor_ic_exception_get_count = 0;
9729 v8::HandleScope scope;
9730 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9731 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
9732 LocalContext context(0, templ, v8::Handle<Value>());
9733 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
9734 v8::Handle<Value> value = CompileRun(
9735 "function f() {"
9736 " for (var i = 0; i < 100; i++) {"
9737 " try { x; } catch(e) { return true; }"
9738 " }"
9739 " return false;"
9740 "};"
9741 "f();");
9742 CHECK_EQ(true, value->BooleanValue());
9743 interceptor_ic_exception_get_count = 0;
9744 value = CompileRun(
9745 "function f() {"
9746 " for (var i = 0; i < 100; i++) {"
9747 " try { x(42); } catch(e) { return true; }"
9748 " }"
9749 " return false;"
9750 "};"
9751 "f();");
9752 CHECK_EQ(true, value->BooleanValue());
9753}
9754
9755
9756static int interceptor_ic_exception_set_count = 0;
9757
9758static v8::Handle<Value> InterceptorICExceptionSetter(
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009759 Local<String> key, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009760 ApiTestFuzzer::Fuzz();
9761 if (++interceptor_ic_exception_set_count > 20) {
9762 return v8::ThrowException(v8_num(42));
9763 }
9764 // Do not actually handle setting.
9765 return v8::Handle<Value>();
9766}
9767
9768// Test interceptor store IC where the interceptor throws an exception
9769// once in a while.
9770THREADED_TEST(InterceptorICSetterExceptions) {
9771 interceptor_ic_exception_set_count = 0;
9772 v8::HandleScope scope;
9773 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9774 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
9775 LocalContext context(0, templ, v8::Handle<Value>());
9776 v8::Handle<Value> value = CompileRun(
9777 "function f() {"
9778 " for (var i = 0; i < 100; i++) {"
9779 " try { x = 42; } catch(e) { return true; }"
9780 " }"
9781 " return false;"
9782 "};"
9783 "f();");
9784 CHECK_EQ(true, value->BooleanValue());
9785}
9786
9787
9788// Test that we ignore null interceptors.
9789THREADED_TEST(NullNamedInterceptor) {
9790 v8::HandleScope scope;
9791 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9792 templ->SetNamedPropertyHandler(0);
9793 LocalContext context;
9794 templ->Set("x", v8_num(42));
9795 v8::Handle<v8::Object> obj = templ->NewInstance();
9796 context->Global()->Set(v8_str("obj"), obj);
9797 v8::Handle<Value> value = CompileRun("obj.x");
9798 CHECK(value->IsInt32());
9799 CHECK_EQ(42, value->Int32Value());
9800}
9801
9802
9803// Test that we ignore null interceptors.
9804THREADED_TEST(NullIndexedInterceptor) {
9805 v8::HandleScope scope;
9806 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9807 templ->SetIndexedPropertyHandler(0);
9808 LocalContext context;
9809 templ->Set("42", v8_num(42));
9810 v8::Handle<v8::Object> obj = templ->NewInstance();
9811 context->Global()->Set(v8_str("obj"), obj);
9812 v8::Handle<Value> value = CompileRun("obj[42]");
9813 CHECK(value->IsInt32());
9814 CHECK_EQ(42, value->Int32Value());
9815}
9816
9817
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009818THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
9819 v8::HandleScope scope;
9820 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9821 templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9822 LocalContext env;
9823 env->Global()->Set(v8_str("obj"),
9824 templ->GetFunction()->NewInstance());
9825 ExpectTrue("obj.x === 42");
9826 ExpectTrue("!obj.propertyIsEnumerable('x')");
9827}
9828
9829
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009830static Handle<Value> ThrowingGetter(Local<String> name,
9831 const AccessorInfo& info) {
9832 ApiTestFuzzer::Fuzz();
9833 ThrowException(Handle<Value>());
9834 return Undefined();
9835}
9836
9837
9838THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
9839 HandleScope scope;
9840 LocalContext context;
9841
9842 Local<FunctionTemplate> templ = FunctionTemplate::New();
9843 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
9844 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
9845
9846 Local<Object> instance = templ->GetFunction()->NewInstance();
9847
9848 Local<Object> another = Object::New();
9849 another->SetPrototype(instance);
9850
9851 Local<Object> with_js_getter = CompileRun(
9852 "o = {};\n"
9853 "o.__defineGetter__('f', function() { throw undefined; });\n"
9854 "o\n").As<Object>();
9855 CHECK(!with_js_getter.IsEmpty());
9856
9857 TryCatch try_catch;
9858
9859 Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
9860 CHECK(try_catch.HasCaught());
9861 try_catch.Reset();
9862 CHECK(result.IsEmpty());
9863
9864 result = another->GetRealNamedProperty(v8_str("f"));
9865 CHECK(try_catch.HasCaught());
9866 try_catch.Reset();
9867 CHECK(result.IsEmpty());
9868
9869 result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
9870 CHECK(try_catch.HasCaught());
9871 try_catch.Reset();
9872 CHECK(result.IsEmpty());
9873
9874 result = another->Get(v8_str("f"));
9875 CHECK(try_catch.HasCaught());
9876 try_catch.Reset();
9877 CHECK(result.IsEmpty());
9878
9879 result = with_js_getter->GetRealNamedProperty(v8_str("f"));
9880 CHECK(try_catch.HasCaught());
9881 try_catch.Reset();
9882 CHECK(result.IsEmpty());
9883
9884 result = with_js_getter->Get(v8_str("f"));
9885 CHECK(try_catch.HasCaught());
9886 try_catch.Reset();
9887 CHECK(result.IsEmpty());
9888}
9889
9890
9891static Handle<Value> ThrowingCallbackWithTryCatch(const Arguments& args) {
9892 TryCatch try_catch;
9893 // Verboseness is important: it triggers message delivery which can call into
9894 // external code.
9895 try_catch.SetVerbose(true);
9896 CompileRun("throw 'from JS';");
9897 CHECK(try_catch.HasCaught());
9898 CHECK(!i::Isolate::Current()->has_pending_exception());
9899 CHECK(!i::Isolate::Current()->has_scheduled_exception());
9900 return Undefined();
9901}
9902
9903
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009904static int call_depth;
9905
9906
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009907static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
9908 TryCatch try_catch;
9909}
9910
9911
9912static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009913 if (--call_depth) CompileRun("throw 'ThrowInJS';");
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009914}
9915
9916
9917static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009918 if (--call_depth) ThrowException(v8_str("ThrowViaApi"));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009919}
9920
9921
9922static void WebKitLike(Handle<Message> message, Handle<Value> data) {
9923 Handle<String> errorMessageString = message->Get();
9924 CHECK(!errorMessageString.IsEmpty());
9925 message->GetStackTrace();
9926 message->GetScriptResourceName();
9927}
9928
9929THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
9930 HandleScope scope;
9931 LocalContext context;
9932
9933 Local<Function> func =
9934 FunctionTemplate::New(ThrowingCallbackWithTryCatch)->GetFunction();
9935 context->Global()->Set(v8_str("func"), func);
9936
9937 MessageCallback callbacks[] =
9938 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
9939 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
9940 MessageCallback callback = callbacks[i];
9941 if (callback != NULL) {
9942 V8::AddMessageListener(callback);
9943 }
ricow@chromium.orgdcebac02011-04-20 09:44:50 +00009944 // Some small number to control number of times message handler should
9945 // throw an exception.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009946 call_depth = 5;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009947 ExpectFalse(
9948 "var thrown = false;\n"
9949 "try { func(); } catch(e) { thrown = true; }\n"
9950 "thrown\n");
9951 if (callback != NULL) {
9952 V8::RemoveMessageListeners(callback);
9953 }
9954 }
9955}
9956
9957
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009958static v8::Handle<Value> ParentGetter(Local<String> name,
9959 const AccessorInfo& info) {
9960 ApiTestFuzzer::Fuzz();
9961 return v8_num(1);
9962}
9963
9964
9965static v8::Handle<Value> ChildGetter(Local<String> name,
9966 const AccessorInfo& info) {
9967 ApiTestFuzzer::Fuzz();
9968 return v8_num(42);
9969}
9970
9971
9972THREADED_TEST(Overriding) {
9973 v8::HandleScope scope;
9974 LocalContext context;
9975
9976 // Parent template.
9977 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
9978 Local<ObjectTemplate> parent_instance_templ =
9979 parent_templ->InstanceTemplate();
9980 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
9981
9982 // Template that inherits from the parent template.
9983 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
9984 Local<ObjectTemplate> child_instance_templ =
9985 child_templ->InstanceTemplate();
9986 child_templ->Inherit(parent_templ);
9987 // Override 'f'. The child version of 'f' should get called for child
9988 // instances.
9989 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
9990 // Add 'g' twice. The 'g' added last should get called for instances.
9991 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
9992 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
9993
9994 // Add 'h' as an accessor to the proto template with ReadOnly attributes
9995 // so 'h' can be shadowed on the instance object.
9996 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
9997 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
9998 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
9999
10000 // Add 'i' as an accessor to the instance template with ReadOnly attributes
10001 // but the attribute does not have effect because it is duplicated with
10002 // NULL setter.
10003 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
10004 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
10005
10006
10007
10008 // Instantiate the child template.
10009 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
10010
10011 // Check that the child function overrides the parent one.
10012 context->Global()->Set(v8_str("o"), instance);
10013 Local<Value> value = v8_compile("o.f")->Run();
10014 // Check that the 'g' that was added last is hit.
10015 CHECK_EQ(42, value->Int32Value());
10016 value = v8_compile("o.g")->Run();
10017 CHECK_EQ(42, value->Int32Value());
10018
10019 // Check 'h' can be shadowed.
10020 value = v8_compile("o.h = 3; o.h")->Run();
10021 CHECK_EQ(3, value->Int32Value());
10022
10023 // Check 'i' is cannot be shadowed or changed.
10024 value = v8_compile("o.i = 3; o.i")->Run();
10025 CHECK_EQ(42, value->Int32Value());
10026}
10027
10028
10029static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
10030 ApiTestFuzzer::Fuzz();
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +000010031 return v8::Boolean::New(args.IsConstructCall());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010032}
10033
10034
10035THREADED_TEST(IsConstructCall) {
10036 v8::HandleScope scope;
10037
10038 // Function template with call handler.
10039 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
10040 templ->SetCallHandler(IsConstructHandler);
10041
10042 LocalContext context;
10043
10044 context->Global()->Set(v8_str("f"), templ->GetFunction());
10045 Local<Value> value = v8_compile("f()")->Run();
10046 CHECK(!value->BooleanValue());
10047 value = v8_compile("new f()")->Run();
10048 CHECK(value->BooleanValue());
10049}
10050
10051
10052THREADED_TEST(ObjectProtoToString) {
10053 v8::HandleScope scope;
10054 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
10055 templ->SetClassName(v8_str("MyClass"));
10056
10057 LocalContext context;
10058
10059 Local<String> customized_tostring = v8_str("customized toString");
10060
10061 // Replace Object.prototype.toString
10062 v8_compile("Object.prototype.toString = function() {"
10063 " return 'customized toString';"
10064 "}")->Run();
10065
10066 // Normal ToString call should call replaced Object.prototype.toString
10067 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
10068 Local<String> value = instance->ToString();
10069 CHECK(value->IsString() && value->Equals(customized_tostring));
10070
10071 // ObjectProtoToString should not call replace toString function.
10072 value = instance->ObjectProtoToString();
10073 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
10074
10075 // Check global
10076 value = context->Global()->ObjectProtoToString();
10077 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
10078
10079 // Check ordinary object
10080 Local<Value> object = v8_compile("new Object()")->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010081 value = object.As<v8::Object>()->ObjectProtoToString();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010082 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
10083}
10084
10085
ager@chromium.orgbeb25712010-11-29 08:02:25 +000010086THREADED_TEST(ObjectGetConstructorName) {
10087 v8::HandleScope scope;
10088 LocalContext context;
10089 v8_compile("function Parent() {};"
10090 "function Child() {};"
10091 "Child.prototype = new Parent();"
10092 "var outer = { inner: function() { } };"
10093 "var p = new Parent();"
10094 "var c = new Child();"
10095 "var x = new outer.inner();")->Run();
10096
10097 Local<v8::Value> p = context->Global()->Get(v8_str("p"));
10098 CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
10099 v8_str("Parent")));
10100
10101 Local<v8::Value> c = context->Global()->Get(v8_str("c"));
10102 CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
10103 v8_str("Child")));
10104
10105 Local<v8::Value> x = context->Global()->Get(v8_str("x"));
10106 CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
10107 v8_str("outer.inner")));
10108}
10109
10110
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010111bool ApiTestFuzzer::fuzzing_ = false;
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010112i::Semaphore* ApiTestFuzzer::all_tests_done_=
10113 i::OS::CreateSemaphore(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010114int ApiTestFuzzer::active_tests_;
10115int ApiTestFuzzer::tests_being_run_;
10116int ApiTestFuzzer::current_;
10117
10118
10119// We are in a callback and want to switch to another thread (if we
10120// are currently running the thread fuzzing test).
10121void ApiTestFuzzer::Fuzz() {
10122 if (!fuzzing_) return;
10123 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
10124 test->ContextSwitch();
10125}
10126
10127
10128// Let the next thread go. Since it is also waiting on the V8 lock it may
10129// not start immediately.
10130bool ApiTestFuzzer::NextThread() {
10131 int test_position = GetNextTestNumber();
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010132 const char* test_name = RegisterThreadedTest::nth(current_)->name();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010133 if (test_position == current_) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010134 if (kLogThreading)
10135 printf("Stay with %s\n", test_name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010136 return false;
10137 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010138 if (kLogThreading) {
10139 printf("Switch from %s to %s\n",
10140 test_name,
10141 RegisterThreadedTest::nth(test_position)->name());
10142 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010143 current_ = test_position;
10144 RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
10145 return true;
10146}
10147
10148
10149void ApiTestFuzzer::Run() {
10150 // When it is our turn...
10151 gate_->Wait();
10152 {
10153 // ... get the V8 lock and start running the test.
10154 v8::Locker locker;
10155 CallTest();
10156 }
10157 // This test finished.
10158 active_ = false;
10159 active_tests_--;
10160 // If it was the last then signal that fact.
10161 if (active_tests_ == 0) {
10162 all_tests_done_->Signal();
10163 } else {
10164 // Otherwise select a new test and start that.
10165 NextThread();
10166 }
10167}
10168
10169
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010170static unsigned linear_congruential_generator;
10171
10172
10173void ApiTestFuzzer::Setup(PartOfTest part) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000010174 linear_congruential_generator = i::FLAG_testing_prng_seed;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010175 fuzzing_ = true;
lrn@chromium.org1c092762011-05-09 09:42:16 +000010176 int count = RegisterThreadedTest::count();
10177 int start = count * part / (LAST_PART + 1);
10178 int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
10179 active_tests_ = tests_being_run_ = end - start + 1;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010180 for (int i = 0; i < tests_being_run_; i++) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010181 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010182 }
10183 for (int i = 0; i < active_tests_; i++) {
10184 RegisterThreadedTest::nth(i)->fuzzer_->Start();
10185 }
10186}
10187
10188
10189static void CallTestNumber(int test_number) {
10190 (RegisterThreadedTest::nth(test_number)->callback())();
10191}
10192
10193
10194void ApiTestFuzzer::RunAllTests() {
10195 // Set off the first test.
10196 current_ = -1;
10197 NextThread();
10198 // Wait till they are all done.
10199 all_tests_done_->Wait();
10200}
10201
10202
10203int ApiTestFuzzer::GetNextTestNumber() {
10204 int next_test;
10205 do {
10206 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
10207 linear_congruential_generator *= 1664525u;
10208 linear_congruential_generator += 1013904223u;
10209 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
10210 return next_test;
10211}
10212
10213
10214void ApiTestFuzzer::ContextSwitch() {
10215 // If the new thread is the same as the current thread there is nothing to do.
10216 if (NextThread()) {
10217 // Now it can start.
10218 v8::Unlocker unlocker;
10219 // Wait till someone starts us again.
10220 gate_->Wait();
10221 // And we're off.
10222 }
10223}
10224
10225
10226void ApiTestFuzzer::TearDown() {
10227 fuzzing_ = false;
ager@chromium.org41826e72009-03-30 13:30:57 +000010228 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
10229 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
10230 if (fuzzer != NULL) fuzzer->Join();
10231 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010232}
10233
10234
10235// Lets not be needlessly self-referential.
10236TEST(Threading) {
10237 ApiTestFuzzer::Setup(ApiTestFuzzer::FIRST_PART);
10238 ApiTestFuzzer::RunAllTests();
10239 ApiTestFuzzer::TearDown();
10240}
10241
10242TEST(Threading2) {
10243 ApiTestFuzzer::Setup(ApiTestFuzzer::SECOND_PART);
10244 ApiTestFuzzer::RunAllTests();
10245 ApiTestFuzzer::TearDown();
10246}
10247
lrn@chromium.org1c092762011-05-09 09:42:16 +000010248TEST(Threading3) {
10249 ApiTestFuzzer::Setup(ApiTestFuzzer::THIRD_PART);
10250 ApiTestFuzzer::RunAllTests();
10251 ApiTestFuzzer::TearDown();
10252}
10253
10254TEST(Threading4) {
10255 ApiTestFuzzer::Setup(ApiTestFuzzer::FOURTH_PART);
10256 ApiTestFuzzer::RunAllTests();
10257 ApiTestFuzzer::TearDown();
10258}
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010259
10260void ApiTestFuzzer::CallTest() {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010261 if (kLogThreading)
10262 printf("Start test %d\n", test_number_);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010263 CallTestNumber(test_number_);
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010264 if (kLogThreading)
10265 printf("End test %d\n", test_number_);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010266}
10267
10268
10269static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010270 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010271 ApiTestFuzzer::Fuzz();
10272 v8::Unlocker unlocker;
10273 const char* code = "throw 7;";
10274 {
10275 v8::Locker nested_locker;
10276 v8::HandleScope scope;
10277 v8::Handle<Value> exception;
10278 { v8::TryCatch try_catch;
10279 v8::Handle<Value> value = CompileRun(code);
10280 CHECK(value.IsEmpty());
10281 CHECK(try_catch.HasCaught());
10282 // Make sure to wrap the exception in a new handle because
10283 // the handle returned from the TryCatch is destroyed
10284 // when the TryCatch is destroyed.
10285 exception = Local<Value>::New(try_catch.Exception());
10286 }
10287 return v8::ThrowException(exception);
10288 }
10289}
10290
10291
10292static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010293 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010294 ApiTestFuzzer::Fuzz();
10295 v8::Unlocker unlocker;
10296 const char* code = "throw 7;";
10297 {
10298 v8::Locker nested_locker;
10299 v8::HandleScope scope;
10300 v8::Handle<Value> value = CompileRun(code);
10301 CHECK(value.IsEmpty());
10302 return v8_str("foo");
10303 }
10304}
10305
10306
10307// These are locking tests that don't need to be run again
10308// as part of the locking aggregation tests.
10309TEST(NestedLockers) {
10310 v8::Locker locker;
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010311 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010312 v8::HandleScope scope;
10313 LocalContext env;
10314 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
10315 Local<Function> fun = fun_templ->GetFunction();
10316 env->Global()->Set(v8_str("throw_in_js"), fun);
10317 Local<Script> script = v8_compile("(function () {"
10318 " try {"
10319 " throw_in_js();"
10320 " return 42;"
10321 " } catch (e) {"
10322 " return e * 13;"
10323 " }"
10324 "})();");
10325 CHECK_EQ(91, script->Run()->Int32Value());
10326}
10327
10328
10329// These are locking tests that don't need to be run again
10330// as part of the locking aggregation tests.
10331TEST(NestedLockersNoTryCatch) {
10332 v8::Locker locker;
10333 v8::HandleScope scope;
10334 LocalContext env;
10335 Local<v8::FunctionTemplate> fun_templ =
10336 v8::FunctionTemplate::New(ThrowInJSNoCatch);
10337 Local<Function> fun = fun_templ->GetFunction();
10338 env->Global()->Set(v8_str("throw_in_js"), fun);
10339 Local<Script> script = v8_compile("(function () {"
10340 " try {"
10341 " throw_in_js();"
10342 " return 42;"
10343 " } catch (e) {"
10344 " return e * 13;"
10345 " }"
10346 "})();");
10347 CHECK_EQ(91, script->Run()->Int32Value());
10348}
10349
10350
10351THREADED_TEST(RecursiveLocking) {
10352 v8::Locker locker;
10353 {
10354 v8::Locker locker2;
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010355 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010356 }
10357}
10358
10359
10360static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
10361 ApiTestFuzzer::Fuzz();
10362 v8::Unlocker unlocker;
10363 return v8::Undefined();
10364}
10365
10366
10367THREADED_TEST(LockUnlockLock) {
10368 {
10369 v8::Locker locker;
10370 v8::HandleScope scope;
10371 LocalContext env;
10372 Local<v8::FunctionTemplate> fun_templ =
10373 v8::FunctionTemplate::New(UnlockForAMoment);
10374 Local<Function> fun = fun_templ->GetFunction();
10375 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
10376 Local<Script> script = v8_compile("(function () {"
10377 " unlock_for_a_moment();"
10378 " return 42;"
10379 "})();");
10380 CHECK_EQ(42, script->Run()->Int32Value());
10381 }
10382 {
10383 v8::Locker locker;
10384 v8::HandleScope scope;
10385 LocalContext env;
10386 Local<v8::FunctionTemplate> fun_templ =
10387 v8::FunctionTemplate::New(UnlockForAMoment);
10388 Local<Function> fun = fun_templ->GetFunction();
10389 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
10390 Local<Script> script = v8_compile("(function () {"
10391 " unlock_for_a_moment();"
10392 " return 42;"
10393 "})();");
10394 CHECK_EQ(42, script->Run()->Int32Value());
10395 }
10396}
10397
10398
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010399static int GetGlobalObjectsCount() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010400 i::Isolate::Current()->heap()->EnsureHeapIsIterable();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010401 int count = 0;
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010402 i::HeapIterator it;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010403 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
10404 if (object->IsJSGlobalObject()) count++;
10405 return count;
10406}
10407
10408
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000010409static void CheckSurvivingGlobalObjectsCount(int expected) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000010410 // We need to collect all garbage twice to be sure that everything
10411 // has been collected. This is because inline caches are cleared in
10412 // the first garbage collection but some of the maps have already
10413 // been marked at that point. Therefore some of the maps are not
10414 // collected until the second garbage collection.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010415 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
10416 HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010417 int count = GetGlobalObjectsCount();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010418#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010419 if (count != expected) HEAP->TracePathToGlobal();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010420#endif
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000010421 CHECK_EQ(expected, count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010422}
10423
10424
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010425TEST(DontLeakGlobalObjects) {
10426 // Regression test for issues 1139850 and 1174891.
10427
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000010428 v8::V8::Initialize();
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010429
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010430 for (int i = 0; i < 5; i++) {
10431 { v8::HandleScope scope;
10432 LocalContext context;
10433 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000010434 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010435
10436 { v8::HandleScope scope;
10437 LocalContext context;
10438 v8_compile("Date")->Run();
10439 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000010440 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010441
10442 { v8::HandleScope scope;
10443 LocalContext context;
10444 v8_compile("/aaa/")->Run();
10445 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000010446 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010447
10448 { v8::HandleScope scope;
10449 const char* extension_list[] = { "v8/gc" };
10450 v8::ExtensionConfiguration extensions(1, extension_list);
10451 LocalContext context(&extensions);
10452 v8_compile("gc();")->Run();
10453 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000010454 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010455 }
10456}
10457
10458
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000010459v8::Persistent<v8::Object> some_object;
10460v8::Persistent<v8::Object> bad_handle;
10461
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +000010462void NewPersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) {
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000010463 v8::HandleScope scope;
10464 bad_handle = v8::Persistent<v8::Object>::New(some_object);
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +000010465 handle.Dispose();
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000010466}
10467
10468
10469THREADED_TEST(NewPersistentHandleFromWeakCallback) {
10470 LocalContext context;
10471
10472 v8::Persistent<v8::Object> handle1, handle2;
10473 {
10474 v8::HandleScope scope;
10475 some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
10476 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
10477 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
10478 }
10479 // Note: order is implementation dependent alas: currently
10480 // global handle nodes are processed by PostGarbageCollectionProcessing
10481 // in reverse allocation order, so if second allocated handle is deleted,
10482 // weak callback of the first handle would be able to 'reallocate' it.
10483 handle1.MakeWeak(NULL, NewPersistentHandleCallback);
10484 handle2.Dispose();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010485 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000010486}
10487
10488
10489v8::Persistent<v8::Object> to_be_disposed;
10490
10491void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
10492 to_be_disposed.Dispose();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010493 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +000010494 handle.Dispose();
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000010495}
10496
10497
10498THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
10499 LocalContext context;
10500
10501 v8::Persistent<v8::Object> handle1, handle2;
10502 {
10503 v8::HandleScope scope;
10504 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
10505 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
10506 }
10507 handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
10508 to_be_disposed = handle2;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010509 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000010510}
10511
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010512void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
10513 handle.Dispose();
10514}
10515
10516void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
10517 v8::HandleScope scope;
10518 v8::Persistent<v8::Object>::New(v8::Object::New());
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +000010519 handle.Dispose();
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010520}
10521
10522
10523THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
10524 LocalContext context;
10525
10526 v8::Persistent<v8::Object> handle1, handle2, handle3;
10527 {
10528 v8::HandleScope scope;
10529 handle3 = v8::Persistent<v8::Object>::New(v8::Object::New());
10530 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
10531 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
10532 }
10533 handle2.MakeWeak(NULL, DisposingCallback);
10534 handle3.MakeWeak(NULL, HandleCreatingCallback);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010535 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010536}
10537
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000010538
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010539THREADED_TEST(CheckForCrossContextObjectLiterals) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000010540 v8::V8::Initialize();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010541
10542 const int nof = 2;
10543 const char* sources[nof] = {
10544 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
10545 "Object()"
10546 };
10547
10548 for (int i = 0; i < nof; i++) {
10549 const char* source = sources[i];
10550 { v8::HandleScope scope;
10551 LocalContext context;
10552 CompileRun(source);
10553 }
10554 { v8::HandleScope scope;
10555 LocalContext context;
10556 CompileRun(source);
10557 }
10558 }
10559}
10560
10561
10562static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
10563 v8::HandleScope inner;
10564 env->Enter();
10565 v8::Handle<Value> three = v8_num(3);
10566 v8::Handle<Value> value = inner.Close(three);
10567 env->Exit();
10568 return value;
10569}
10570
10571
10572THREADED_TEST(NestedHandleScopeAndContexts) {
10573 v8::HandleScope outer;
10574 v8::Persistent<Context> env = Context::New();
10575 env->Enter();
10576 v8::Handle<Value> value = NestedScope(env);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010577 v8::Handle<String> str(value->ToString());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010578 env->Exit();
10579 env.Dispose();
10580}
10581
10582
10583THREADED_TEST(ExternalAllocatedMemory) {
10584 v8::HandleScope outer;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010585 v8::Persistent<Context> env(Context::New());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010586 const int kSize = 1024*1024;
10587 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
10588 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
10589}
10590
10591
10592THREADED_TEST(DisposeEnteredContext) {
10593 v8::HandleScope scope;
10594 LocalContext outer;
10595 { v8::Persistent<v8::Context> inner = v8::Context::New();
10596 inner->Enter();
10597 inner.Dispose();
10598 inner.Clear();
10599 inner->Exit();
10600 }
10601}
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010602
10603
10604// Regression test for issue 54, object templates with internal fields
10605// but no accessors or interceptors did not get their internal field
10606// count set on instances.
10607THREADED_TEST(Regress54) {
10608 v8::HandleScope outer;
10609 LocalContext context;
10610 static v8::Persistent<v8::ObjectTemplate> templ;
10611 if (templ.IsEmpty()) {
10612 v8::HandleScope inner;
10613 v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
10614 local->SetInternalFieldCount(1);
10615 templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
10616 }
10617 v8::Handle<v8::Object> result = templ->NewInstance();
10618 CHECK_EQ(1, result->InternalFieldCount());
10619}
10620
10621
10622// If part of the threaded tests, this test makes ThreadingTest fail
10623// on mac.
10624TEST(CatchStackOverflow) {
10625 v8::HandleScope scope;
10626 LocalContext context;
10627 v8::TryCatch try_catch;
10628 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
10629 "function f() {"
10630 " return f();"
10631 "}"
10632 ""
10633 "f();"));
10634 v8::Handle<v8::Value> result = script->Run();
10635 CHECK(result.IsEmpty());
10636}
10637
10638
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000010639static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
10640 const char* resource_name,
10641 int line_offset) {
10642 v8::HandleScope scope;
10643 v8::TryCatch try_catch;
10644 v8::Handle<v8::Value> result = script->Run();
10645 CHECK(result.IsEmpty());
10646 CHECK(try_catch.HasCaught());
10647 v8::Handle<v8::Message> message = try_catch.Message();
10648 CHECK(!message.IsEmpty());
10649 CHECK_EQ(10 + line_offset, message->GetLineNumber());
10650 CHECK_EQ(91, message->GetStartPosition());
10651 CHECK_EQ(92, message->GetEndPosition());
10652 CHECK_EQ(2, message->GetStartColumn());
10653 CHECK_EQ(3, message->GetEndColumn());
10654 v8::String::AsciiValue line(message->GetSourceLine());
10655 CHECK_EQ(" throw 'nirk';", *line);
10656 v8::String::AsciiValue name(message->GetScriptResourceName());
10657 CHECK_EQ(resource_name, *name);
10658}
10659
10660
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010661THREADED_TEST(TryCatchSourceInfo) {
10662 v8::HandleScope scope;
10663 LocalContext context;
10664 v8::Handle<v8::String> source = v8::String::New(
10665 "function Foo() {\n"
10666 " return Bar();\n"
10667 "}\n"
10668 "\n"
10669 "function Bar() {\n"
10670 " return Baz();\n"
10671 "}\n"
10672 "\n"
10673 "function Baz() {\n"
10674 " throw 'nirk';\n"
10675 "}\n"
10676 "\n"
10677 "Foo();\n");
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000010678
10679 const char* resource_name;
10680 v8::Handle<v8::Script> script;
10681 resource_name = "test.js";
10682 script = v8::Script::Compile(source, v8::String::New(resource_name));
10683 CheckTryCatchSourceInfo(script, resource_name, 0);
10684
10685 resource_name = "test1.js";
10686 v8::ScriptOrigin origin1(v8::String::New(resource_name));
10687 script = v8::Script::Compile(source, &origin1);
10688 CheckTryCatchSourceInfo(script, resource_name, 0);
10689
10690 resource_name = "test2.js";
10691 v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
10692 script = v8::Script::Compile(source, &origin2);
10693 CheckTryCatchSourceInfo(script, resource_name, 7);
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010694}
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000010695
10696
10697THREADED_TEST(CompilationCache) {
10698 v8::HandleScope scope;
10699 LocalContext context;
10700 v8::Handle<v8::String> source0 = v8::String::New("1234");
10701 v8::Handle<v8::String> source1 = v8::String::New("1234");
10702 v8::Handle<v8::Script> script0 =
10703 v8::Script::Compile(source0, v8::String::New("test.js"));
10704 v8::Handle<v8::Script> script1 =
10705 v8::Script::Compile(source1, v8::String::New("test.js"));
10706 v8::Handle<v8::Script> script2 =
10707 v8::Script::Compile(source0); // different origin
10708 CHECK_EQ(1234, script0->Run()->Int32Value());
10709 CHECK_EQ(1234, script1->Run()->Int32Value());
10710 CHECK_EQ(1234, script2->Run()->Int32Value());
10711}
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000010712
10713
10714static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
10715 ApiTestFuzzer::Fuzz();
10716 return v8_num(42);
10717}
10718
10719
10720THREADED_TEST(CallbackFunctionName) {
10721 v8::HandleScope scope;
10722 LocalContext context;
10723 Local<ObjectTemplate> t = ObjectTemplate::New();
10724 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
10725 context->Global()->Set(v8_str("obj"), t->NewInstance());
10726 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
10727 CHECK(value->IsString());
10728 v8::String::AsciiValue name(value);
10729 CHECK_EQ("asdf", *name);
10730}
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010731
10732
10733THREADED_TEST(DateAccess) {
10734 v8::HandleScope scope;
10735 LocalContext context;
10736 v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
10737 CHECK(date->IsDate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010738 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010739}
10740
10741
10742void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010743 v8::Handle<v8::Object> obj = val.As<v8::Object>();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010744 v8::Handle<v8::Array> props = obj->GetPropertyNames();
10745 CHECK_EQ(elmc, props->Length());
10746 for (int i = 0; i < elmc; i++) {
10747 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
10748 CHECK_EQ(elmv[i], *elm);
10749 }
10750}
10751
10752
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010753void CheckOwnProperties(v8::Handle<v8::Value> val,
10754 int elmc,
10755 const char* elmv[]) {
10756 v8::Handle<v8::Object> obj = val.As<v8::Object>();
10757 v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
10758 CHECK_EQ(elmc, props->Length());
10759 for (int i = 0; i < elmc; i++) {
10760 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
10761 CHECK_EQ(elmv[i], *elm);
10762 }
10763}
10764
10765
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010766THREADED_TEST(PropertyEnumeration) {
10767 v8::HandleScope scope;
10768 LocalContext context;
10769 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
10770 "var result = [];"
10771 "result[0] = {};"
10772 "result[1] = {a: 1, b: 2};"
10773 "result[2] = [1, 2, 3];"
10774 "var proto = {x: 1, y: 2, z: 3};"
10775 "var x = { __proto__: proto, w: 0, z: 1 };"
10776 "result[3] = x;"
10777 "result;"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010778 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010779 CHECK_EQ(4, elms->Length());
10780 int elmc0 = 0;
10781 const char** elmv0 = NULL;
10782 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010783 CheckOwnProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010784 int elmc1 = 2;
10785 const char* elmv1[] = {"a", "b"};
10786 CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010787 CheckOwnProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010788 int elmc2 = 3;
10789 const char* elmv2[] = {"0", "1", "2"};
10790 CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010791 CheckOwnProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010792 int elmc3 = 4;
10793 const char* elmv3[] = {"w", "z", "x", "y"};
10794 CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010795 int elmc4 = 2;
10796 const char* elmv4[] = {"w", "z"};
10797 CheckOwnProperties(elms->Get(v8::Integer::New(3)), elmc4, elmv4);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010798}
ager@chromium.org870a0b62008-11-04 11:43:05 +000010799
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010800THREADED_TEST(PropertyEnumeration2) {
10801 v8::HandleScope scope;
10802 LocalContext context;
10803 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
10804 "var result = [];"
10805 "result[0] = {};"
10806 "result[1] = {a: 1, b: 2};"
10807 "result[2] = [1, 2, 3];"
10808 "var proto = {x: 1, y: 2, z: 3};"
10809 "var x = { __proto__: proto, w: 0, z: 1 };"
10810 "result[3] = x;"
10811 "result;"))->Run();
10812 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
10813 CHECK_EQ(4, elms->Length());
10814 int elmc0 = 0;
10815 const char** elmv0 = NULL;
10816 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
10817
10818 v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(0));
10819 v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
10820 CHECK_EQ(0, props->Length());
10821 for (uint32_t i = 0; i < props->Length(); i++) {
10822 printf("p[%d]\n", i);
10823 }
10824}
ager@chromium.org870a0b62008-11-04 11:43:05 +000010825
ager@chromium.org870a0b62008-11-04 11:43:05 +000010826static bool NamedSetAccessBlocker(Local<v8::Object> obj,
10827 Local<Value> name,
10828 v8::AccessType type,
10829 Local<Value> data) {
10830 return type != v8::ACCESS_SET;
10831}
10832
10833
10834static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
10835 uint32_t key,
10836 v8::AccessType type,
10837 Local<Value> data) {
10838 return type != v8::ACCESS_SET;
10839}
10840
10841
10842THREADED_TEST(DisableAccessChecksWhileConfiguring) {
10843 v8::HandleScope scope;
10844 LocalContext context;
10845 Local<ObjectTemplate> templ = ObjectTemplate::New();
10846 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
10847 IndexedSetAccessBlocker);
10848 templ->Set(v8_str("x"), v8::True());
10849 Local<v8::Object> instance = templ->NewInstance();
10850 context->Global()->Set(v8_str("obj"), instance);
10851 Local<Value> value = CompileRun("obj.x");
10852 CHECK(value->BooleanValue());
10853}
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010854
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010855
ager@chromium.org32912102009-01-16 10:38:43 +000010856static bool NamedGetAccessBlocker(Local<v8::Object> obj,
10857 Local<Value> name,
10858 v8::AccessType type,
10859 Local<Value> data) {
10860 return false;
10861}
10862
10863
10864static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
10865 uint32_t key,
10866 v8::AccessType type,
10867 Local<Value> data) {
10868 return false;
10869}
10870
10871
10872
10873THREADED_TEST(AccessChecksReenabledCorrectly) {
10874 v8::HandleScope scope;
10875 LocalContext context;
10876 Local<ObjectTemplate> templ = ObjectTemplate::New();
10877 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
10878 IndexedGetAccessBlocker);
10879 templ->Set(v8_str("a"), v8_str("a"));
10880 // Add more than 8 (see kMaxFastProperties) properties
10881 // so that the constructor will force copying map.
10882 // Cannot sprintf, gcc complains unsafety.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010883 char buf[4];
ager@chromium.org32912102009-01-16 10:38:43 +000010884 for (char i = '0'; i <= '9' ; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010885 buf[0] = i;
ager@chromium.org32912102009-01-16 10:38:43 +000010886 for (char j = '0'; j <= '9'; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010887 buf[1] = j;
ager@chromium.org32912102009-01-16 10:38:43 +000010888 for (char k = '0'; k <= '9'; k++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010889 buf[2] = k;
10890 buf[3] = 0;
ager@chromium.org32912102009-01-16 10:38:43 +000010891 templ->Set(v8_str(buf), v8::Number::New(k));
10892 }
10893 }
10894 }
10895
10896 Local<v8::Object> instance_1 = templ->NewInstance();
10897 context->Global()->Set(v8_str("obj_1"), instance_1);
10898
10899 Local<Value> value_1 = CompileRun("obj_1.a");
10900 CHECK(value_1->IsUndefined());
10901
10902 Local<v8::Object> instance_2 = templ->NewInstance();
10903 context->Global()->Set(v8_str("obj_2"), instance_2);
10904
10905 Local<Value> value_2 = CompileRun("obj_2.a");
10906 CHECK(value_2->IsUndefined());
10907}
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010908
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010909
ager@chromium.org8bb60582008-12-11 12:02:20 +000010910// This tests that access check information remains on the global
10911// object template when creating contexts.
10912THREADED_TEST(AccessControlRepeatedContextCreation) {
10913 v8::HandleScope handle_scope;
10914 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
10915 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
10916 IndexedSetAccessBlocker);
10917 i::Handle<i::ObjectTemplateInfo> internal_template =
10918 v8::Utils::OpenHandle(*global_template);
10919 CHECK(!internal_template->constructor()->IsUndefined());
10920 i::Handle<i::FunctionTemplateInfo> constructor(
10921 i::FunctionTemplateInfo::cast(internal_template->constructor()));
10922 CHECK(!constructor->access_check_info()->IsUndefined());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010923 v8::Persistent<Context> context0(Context::New(NULL, global_template));
ager@chromium.org8bb60582008-12-11 12:02:20 +000010924 CHECK(!constructor->access_check_info()->IsUndefined());
10925}
10926
10927
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010928THREADED_TEST(TurnOnAccessCheck) {
10929 v8::HandleScope handle_scope;
10930
10931 // Create an environment with access check to the global object disabled by
10932 // default.
10933 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
10934 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
10935 IndexedGetAccessBlocker,
10936 v8::Handle<v8::Value>(),
10937 false);
10938 v8::Persistent<Context> context = Context::New(NULL, global_template);
10939 Context::Scope context_scope(context);
10940
10941 // Set up a property and a number of functions.
10942 context->Global()->Set(v8_str("a"), v8_num(1));
10943 CompileRun("function f1() {return a;}"
10944 "function f2() {return a;}"
10945 "function g1() {return h();}"
10946 "function g2() {return h();}"
10947 "function h() {return 1;}");
10948 Local<Function> f1 =
10949 Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
10950 Local<Function> f2 =
10951 Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
10952 Local<Function> g1 =
10953 Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
10954 Local<Function> g2 =
10955 Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
10956 Local<Function> h =
10957 Local<Function>::Cast(context->Global()->Get(v8_str("h")));
10958
10959 // Get the global object.
10960 v8::Handle<v8::Object> global = context->Global();
10961
10962 // Call f1 one time and f2 a number of times. This will ensure that f1 still
10963 // uses the runtime system to retreive property a whereas f2 uses global load
10964 // inline cache.
10965 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
10966 for (int i = 0; i < 4; i++) {
10967 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
10968 }
10969
10970 // Same for g1 and g2.
10971 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
10972 for (int i = 0; i < 4; i++) {
10973 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
10974 }
10975
10976 // Detach the global and turn on access check.
10977 context->DetachGlobal();
10978 context->Global()->TurnOnAccessCheck();
10979
10980 // Failing access check to property get results in undefined.
10981 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
10982 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
10983
10984 // Failing access check to function call results in exception.
10985 CHECK(g1->Call(global, 0, NULL).IsEmpty());
10986 CHECK(g2->Call(global, 0, NULL).IsEmpty());
10987
10988 // No failing access check when just returning a constant.
10989 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
10990}
10991
10992
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010993v8::Handle<v8::String> a;
10994v8::Handle<v8::String> h;
10995
10996static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
10997 Local<Value> name,
10998 v8::AccessType type,
10999 Local<Value> data) {
11000 return !(name->Equals(a) || name->Equals(h));
11001}
11002
11003
11004THREADED_TEST(TurnOnAccessCheckAndRecompile) {
11005 v8::HandleScope handle_scope;
11006
11007 // Create an environment with access check to the global object disabled by
11008 // default. When the registered access checker will block access to properties
11009 // a and h
11010 a = v8_str("a");
11011 h = v8_str("h");
11012 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
11013 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
11014 IndexedGetAccessBlocker,
11015 v8::Handle<v8::Value>(),
11016 false);
11017 v8::Persistent<Context> context = Context::New(NULL, global_template);
11018 Context::Scope context_scope(context);
11019
11020 // Set up a property and a number of functions.
11021 context->Global()->Set(v8_str("a"), v8_num(1));
11022 static const char* source = "function f1() {return a;}"
11023 "function f2() {return a;}"
11024 "function g1() {return h();}"
11025 "function g2() {return h();}"
11026 "function h() {return 1;}";
11027
11028 CompileRun(source);
11029 Local<Function> f1;
11030 Local<Function> f2;
11031 Local<Function> g1;
11032 Local<Function> g2;
11033 Local<Function> h;
11034 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
11035 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
11036 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
11037 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
11038 h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
11039
11040 // Get the global object.
11041 v8::Handle<v8::Object> global = context->Global();
11042
11043 // Call f1 one time and f2 a number of times. This will ensure that f1 still
11044 // uses the runtime system to retreive property a whereas f2 uses global load
11045 // inline cache.
11046 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
11047 for (int i = 0; i < 4; i++) {
11048 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
11049 }
11050
11051 // Same for g1 and g2.
11052 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
11053 for (int i = 0; i < 4; i++) {
11054 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
11055 }
11056
11057 // Detach the global and turn on access check now blocking access to property
11058 // a and function h.
11059 context->DetachGlobal();
11060 context->Global()->TurnOnAccessCheck();
11061
11062 // Failing access check to property get results in undefined.
11063 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
11064 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
11065
11066 // Failing access check to function call results in exception.
11067 CHECK(g1->Call(global, 0, NULL).IsEmpty());
11068 CHECK(g2->Call(global, 0, NULL).IsEmpty());
11069
11070 // No failing access check when just returning a constant.
11071 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
11072
11073 // Now compile the source again. And get the newly compiled functions, except
11074 // for h for which access is blocked.
11075 CompileRun(source);
11076 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
11077 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
11078 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
11079 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
11080 CHECK(context->Global()->Get(v8_str("h"))->IsUndefined());
11081
11082 // Failing access check to property get results in undefined.
11083 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
11084 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
11085
11086 // Failing access check to function call results in exception.
11087 CHECK(g1->Call(global, 0, NULL).IsEmpty());
11088 CHECK(g2->Call(global, 0, NULL).IsEmpty());
11089}
11090
11091
ager@chromium.orga74f0da2008-12-03 16:05:52 +000011092// This test verifies that pre-compilation (aka preparsing) can be called
11093// without initializing the whole VM. Thus we cannot run this test in a
11094// multi-threaded setup.
11095TEST(PreCompile) {
11096 // TODO(155): This test would break without the initialization of V8. This is
11097 // a workaround for now to make this test not fail.
11098 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011099 const char* script = "function foo(a) { return a+1; }";
11100 v8::ScriptData* sd =
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011101 v8::ScriptData::PreCompile(script, i::StrLength(script));
ager@chromium.orga74f0da2008-12-03 16:05:52 +000011102 CHECK_NE(sd->Length(), 0);
11103 CHECK_NE(sd->Data(), NULL);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000011104 CHECK(!sd->HasError());
11105 delete sd;
11106}
11107
11108
11109TEST(PreCompileWithError) {
11110 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011111 const char* script = "function foo(a) { return 1 * * 2; }";
11112 v8::ScriptData* sd =
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000011113 v8::ScriptData::PreCompile(script, i::StrLength(script));
11114 CHECK(sd->HasError());
11115 delete sd;
11116}
11117
11118
11119TEST(Regress31661) {
11120 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011121 const char* script = " The Definintive Guide";
11122 v8::ScriptData* sd =
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000011123 v8::ScriptData::PreCompile(script, i::StrLength(script));
11124 CHECK(sd->HasError());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011125 delete sd;
ager@chromium.orga74f0da2008-12-03 16:05:52 +000011126}
11127
11128
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011129// Tests that ScriptData can be serialized and deserialized.
11130TEST(PreCompileSerialization) {
11131 v8::V8::Initialize();
11132 const char* script = "function foo(a) { return a+1; }";
11133 v8::ScriptData* sd =
11134 v8::ScriptData::PreCompile(script, i::StrLength(script));
11135
11136 // Serialize.
11137 int serialized_data_length = sd->Length();
11138 char* serialized_data = i::NewArray<char>(serialized_data_length);
11139 memcpy(serialized_data, sd->Data(), serialized_data_length);
11140
11141 // Deserialize.
11142 v8::ScriptData* deserialized_sd =
11143 v8::ScriptData::New(serialized_data, serialized_data_length);
11144
11145 // Verify that the original is the same as the deserialized.
11146 CHECK_EQ(sd->Length(), deserialized_sd->Length());
11147 CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
11148 CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
11149
11150 delete sd;
11151 delete deserialized_sd;
11152}
11153
11154
11155// Attempts to deserialize bad data.
11156TEST(PreCompileDeserializationError) {
11157 v8::V8::Initialize();
11158 const char* data = "DONT CARE";
11159 int invalid_size = 3;
11160 v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
11161
11162 CHECK_EQ(0, sd->Length());
11163
11164 delete sd;
11165}
11166
11167
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000011168// Attempts to deserialize bad data.
11169TEST(PreCompileInvalidPreparseDataError) {
11170 v8::V8::Initialize();
11171 v8::HandleScope scope;
11172 LocalContext context;
11173
11174 const char* script = "function foo(){ return 5;}\n"
11175 "function bar(){ return 6 + 7;} foo();";
11176 v8::ScriptData* sd =
11177 v8::ScriptData::PreCompile(script, i::StrLength(script));
11178 CHECK(!sd->HasError());
11179 // ScriptDataImpl private implementation details
ager@chromium.orgbeb25712010-11-29 08:02:25 +000011180 const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
ager@chromium.org5b2fbee2010-09-08 06:38:15 +000011181 const int kFunctionEntrySize = i::FunctionEntry::kSize;
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000011182 const int kFunctionEntryStartOffset = 0;
11183 const int kFunctionEntryEndOffset = 1;
11184 unsigned* sd_data =
11185 reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000011186
11187 // Overwrite function bar's end position with 0.
11188 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
11189 v8::TryCatch try_catch;
11190
11191 Local<String> source = String::New(script);
11192 Local<Script> compiled_script = Script::New(source, NULL, sd);
11193 CHECK(try_catch.HasCaught());
11194 String::AsciiValue exception_value(try_catch.Message()->Get());
11195 CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
11196 *exception_value);
11197
11198 try_catch.Reset();
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000011199
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000011200 // Overwrite function bar's start position with 200. The function entry
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000011201 // will not be found when searching for it by position and we should fall
11202 // back on eager compilation.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +000011203 sd = v8::ScriptData::PreCompile(script, i::StrLength(script));
11204 sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000011205 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
11206 200;
11207 compiled_script = Script::New(source, NULL, sd);
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000011208 CHECK(!try_catch.HasCaught());
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000011209
11210 delete sd;
11211}
11212
11213
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000011214// Verifies that the Handle<String> and const char* versions of the API produce
11215// the same results (at least for one trivial case).
11216TEST(PreCompileAPIVariationsAreSame) {
11217 v8::V8::Initialize();
11218 v8::HandleScope scope;
11219
11220 const char* cstring = "function foo(a) { return a+1; }";
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011221
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000011222 v8::ScriptData* sd_from_cstring =
11223 v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
11224
11225 TestAsciiResource* resource = new TestAsciiResource(cstring);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011226 v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile(
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000011227 v8::String::NewExternal(resource));
11228
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011229 v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile(
11230 v8::String::New(cstring));
11231
11232 CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000011233 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011234 sd_from_external_string->Data(),
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000011235 sd_from_cstring->Length()));
11236
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011237 CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length());
11238 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
11239 sd_from_string->Data(),
11240 sd_from_cstring->Length()));
11241
11242
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000011243 delete sd_from_cstring;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011244 delete sd_from_external_string;
11245 delete sd_from_string;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000011246}
11247
11248
ager@chromium.orga74f0da2008-12-03 16:05:52 +000011249// This tests that we do not allow dictionary load/call inline caches
11250// to use functions that have not yet been compiled. The potential
11251// problem of loading a function that has not yet been compiled can
11252// arise because we share code between contexts via the compilation
11253// cache.
11254THREADED_TEST(DictionaryICLoadedFunction) {
11255 v8::HandleScope scope;
11256 // Test LoadIC.
11257 for (int i = 0; i < 2; i++) {
11258 LocalContext context;
11259 context->Global()->Set(v8_str("tmp"), v8::True());
11260 context->Global()->Delete(v8_str("tmp"));
11261 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
11262 }
11263 // Test CallIC.
11264 for (int i = 0; i < 2; i++) {
11265 LocalContext context;
11266 context->Global()->Set(v8_str("tmp"), v8::True());
11267 context->Global()->Delete(v8_str("tmp"));
11268 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
11269 }
11270}
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011271
11272
11273// Test that cross-context new calls use the context of the callee to
11274// create the new JavaScript object.
11275THREADED_TEST(CrossContextNew) {
11276 v8::HandleScope scope;
11277 v8::Persistent<Context> context0 = Context::New();
11278 v8::Persistent<Context> context1 = Context::New();
11279
11280 // Allow cross-domain access.
11281 Local<String> token = v8_str("<security token>");
11282 context0->SetSecurityToken(token);
11283 context1->SetSecurityToken(token);
11284
11285 // Set an 'x' property on the Object prototype and define a
11286 // constructor function in context0.
11287 context0->Enter();
11288 CompileRun("Object.prototype.x = 42; function C() {};");
11289 context0->Exit();
11290
11291 // Call the constructor function from context0 and check that the
11292 // result has the 'x' property.
11293 context1->Enter();
11294 context1->Global()->Set(v8_str("other"), context0->Global());
11295 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
11296 CHECK(value->IsInt32());
11297 CHECK_EQ(42, value->Int32Value());
11298 context1->Exit();
11299
11300 // Dispose the contexts to allow them to be garbage collected.
11301 context0.Dispose();
11302 context1.Dispose();
11303}
ager@chromium.org381abbb2009-02-25 13:23:22 +000011304
11305
11306class RegExpInterruptTest {
11307 public:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011308 RegExpInterruptTest() : block_(NULL) {}
11309 ~RegExpInterruptTest() { delete block_; }
ager@chromium.org381abbb2009-02-25 13:23:22 +000011310 void RunTest() {
11311 block_ = i::OS::CreateSemaphore(0);
11312 gc_count_ = 0;
11313 gc_during_regexp_ = 0;
11314 regexp_success_ = false;
11315 gc_success_ = false;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011316 GCThread gc_thread(this);
ager@chromium.org381abbb2009-02-25 13:23:22 +000011317 gc_thread.Start();
11318 v8::Locker::StartPreemption(1);
11319
11320 LongRunningRegExp();
11321 {
11322 v8::Unlocker unlock;
11323 gc_thread.Join();
11324 }
11325 v8::Locker::StopPreemption();
11326 CHECK(regexp_success_);
11327 CHECK(gc_success_);
11328 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000011329
ager@chromium.org381abbb2009-02-25 13:23:22 +000011330 private:
11331 // Number of garbage collections required.
11332 static const int kRequiredGCs = 5;
11333
11334 class GCThread : public i::Thread {
11335 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011336 explicit GCThread(RegExpInterruptTest* test)
11337 : Thread("GCThread"), test_(test) {}
ager@chromium.org381abbb2009-02-25 13:23:22 +000011338 virtual void Run() {
11339 test_->CollectGarbage();
11340 }
11341 private:
11342 RegExpInterruptTest* test_;
11343 };
11344
11345 void CollectGarbage() {
11346 block_->Wait();
11347 while (gc_during_regexp_ < kRequiredGCs) {
11348 {
11349 v8::Locker lock;
11350 // TODO(lrn): Perhaps create some garbage before collecting.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011351 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org381abbb2009-02-25 13:23:22 +000011352 gc_count_++;
11353 }
11354 i::OS::Sleep(1);
11355 }
11356 gc_success_ = true;
11357 }
11358
11359 void LongRunningRegExp() {
11360 block_->Signal(); // Enable garbage collection thread on next preemption.
11361 int rounds = 0;
11362 while (gc_during_regexp_ < kRequiredGCs) {
11363 int gc_before = gc_count_;
11364 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011365 // Match 15-30 "a"'s against 14 and a "b".
ager@chromium.org381abbb2009-02-25 13:23:22 +000011366 const char* c_source =
11367 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
11368 ".exec('aaaaaaaaaaaaaaab') === null";
11369 Local<String> source = String::New(c_source);
11370 Local<Script> script = Script::Compile(source);
11371 Local<Value> result = script->Run();
11372 if (!result->BooleanValue()) {
11373 gc_during_regexp_ = kRequiredGCs; // Allow gc thread to exit.
11374 return;
11375 }
11376 }
11377 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011378 // Match 15-30 "a"'s against 15 and a "b".
ager@chromium.org381abbb2009-02-25 13:23:22 +000011379 const char* c_source =
11380 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
11381 ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
11382 Local<String> source = String::New(c_source);
11383 Local<Script> script = Script::Compile(source);
11384 Local<Value> result = script->Run();
11385 if (!result->BooleanValue()) {
11386 gc_during_regexp_ = kRequiredGCs;
11387 return;
11388 }
11389 }
11390 int gc_after = gc_count_;
11391 gc_during_regexp_ += gc_after - gc_before;
11392 rounds++;
11393 i::OS::Sleep(1);
11394 }
11395 regexp_success_ = true;
11396 }
11397
11398 i::Semaphore* block_;
11399 int gc_count_;
11400 int gc_during_regexp_;
11401 bool regexp_success_;
11402 bool gc_success_;
11403};
11404
11405
11406// Test that a regular expression execution can be interrupted and
11407// survive a garbage collection.
11408TEST(RegExpInterruption) {
11409 v8::Locker lock;
11410 v8::V8::Initialize();
11411 v8::HandleScope scope;
11412 Local<Context> local_env;
11413 {
11414 LocalContext env;
11415 local_env = env.local();
11416 }
11417
11418 // Local context should still be live.
11419 CHECK(!local_env.IsEmpty());
11420 local_env->Enter();
11421
11422 // Should complete without problems.
11423 RegExpInterruptTest().RunTest();
11424
11425 local_env->Exit();
11426}
ager@chromium.org3b45ab52009-03-19 22:21:34 +000011427
11428
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011429class ApplyInterruptTest {
11430 public:
11431 ApplyInterruptTest() : block_(NULL) {}
11432 ~ApplyInterruptTest() { delete block_; }
11433 void RunTest() {
11434 block_ = i::OS::CreateSemaphore(0);
11435 gc_count_ = 0;
11436 gc_during_apply_ = 0;
11437 apply_success_ = false;
11438 gc_success_ = false;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011439 GCThread gc_thread(this);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011440 gc_thread.Start();
11441 v8::Locker::StartPreemption(1);
11442
11443 LongRunningApply();
11444 {
11445 v8::Unlocker unlock;
11446 gc_thread.Join();
11447 }
11448 v8::Locker::StopPreemption();
11449 CHECK(apply_success_);
11450 CHECK(gc_success_);
11451 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000011452
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011453 private:
11454 // Number of garbage collections required.
11455 static const int kRequiredGCs = 2;
11456
11457 class GCThread : public i::Thread {
11458 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011459 explicit GCThread(ApplyInterruptTest* test)
11460 : Thread("GCThread"), test_(test) {}
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011461 virtual void Run() {
11462 test_->CollectGarbage();
11463 }
11464 private:
11465 ApplyInterruptTest* test_;
11466 };
11467
11468 void CollectGarbage() {
11469 block_->Wait();
11470 while (gc_during_apply_ < kRequiredGCs) {
11471 {
11472 v8::Locker lock;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011473 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011474 gc_count_++;
11475 }
11476 i::OS::Sleep(1);
11477 }
11478 gc_success_ = true;
11479 }
11480
11481 void LongRunningApply() {
11482 block_->Signal();
11483 int rounds = 0;
11484 while (gc_during_apply_ < kRequiredGCs) {
11485 int gc_before = gc_count_;
11486 {
11487 const char* c_source =
11488 "function do_very_little(bar) {"
11489 " this.foo = bar;"
11490 "}"
11491 "for (var i = 0; i < 100000; i++) {"
11492 " do_very_little.apply(this, ['bar']);"
11493 "}";
11494 Local<String> source = String::New(c_source);
11495 Local<Script> script = Script::Compile(source);
11496 Local<Value> result = script->Run();
ager@chromium.org3a37e9b2009-04-27 09:26:21 +000011497 // Check that no exception was thrown.
11498 CHECK(!result.IsEmpty());
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011499 }
11500 int gc_after = gc_count_;
11501 gc_during_apply_ += gc_after - gc_before;
11502 rounds++;
11503 }
11504 apply_success_ = true;
11505 }
11506
11507 i::Semaphore* block_;
11508 int gc_count_;
11509 int gc_during_apply_;
11510 bool apply_success_;
11511 bool gc_success_;
11512};
11513
11514
11515// Test that nothing bad happens if we get a preemption just when we were
11516// about to do an apply().
11517TEST(ApplyInterruption) {
11518 v8::Locker lock;
11519 v8::V8::Initialize();
11520 v8::HandleScope scope;
11521 Local<Context> local_env;
11522 {
11523 LocalContext env;
11524 local_env = env.local();
11525 }
11526
11527 // Local context should still be live.
11528 CHECK(!local_env.IsEmpty());
11529 local_env->Enter();
11530
11531 // Should complete without problems.
11532 ApplyInterruptTest().RunTest();
11533
11534 local_env->Exit();
11535}
11536
11537
ager@chromium.org3b45ab52009-03-19 22:21:34 +000011538// Verify that we can clone an object
11539TEST(ObjectClone) {
11540 v8::HandleScope scope;
11541 LocalContext env;
11542
11543 const char* sample =
11544 "var rv = {};" \
11545 "rv.alpha = 'hello';" \
11546 "rv.beta = 123;" \
11547 "rv;";
11548
11549 // Create an object, verify basics.
11550 Local<Value> val = CompileRun(sample);
11551 CHECK(val->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011552 Local<v8::Object> obj = val.As<v8::Object>();
ager@chromium.org3b45ab52009-03-19 22:21:34 +000011553 obj->Set(v8_str("gamma"), v8_str("cloneme"));
11554
11555 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
11556 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
11557 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
11558
11559 // Clone it.
11560 Local<v8::Object> clone = obj->Clone();
11561 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
11562 CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
11563 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
11564
11565 // Set a property on the clone, verify each object.
11566 clone->Set(v8_str("beta"), v8::Integer::New(456));
11567 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
11568 CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
11569}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011570
11571
ager@chromium.org5ec48922009-05-05 07:25:34 +000011572class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
11573 public:
11574 explicit AsciiVectorResource(i::Vector<const char> vector)
11575 : data_(vector) {}
11576 virtual ~AsciiVectorResource() {}
11577 virtual size_t length() const { return data_.length(); }
11578 virtual const char* data() const { return data_.start(); }
11579 private:
11580 i::Vector<const char> data_;
11581};
11582
11583
11584class UC16VectorResource : public v8::String::ExternalStringResource {
11585 public:
11586 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
11587 : data_(vector) {}
11588 virtual ~UC16VectorResource() {}
11589 virtual size_t length() const { return data_.length(); }
11590 virtual const i::uc16* data() const { return data_.start(); }
11591 private:
11592 i::Vector<const i::uc16> data_;
11593};
11594
11595
11596static void MorphAString(i::String* string,
11597 AsciiVectorResource* ascii_resource,
11598 UC16VectorResource* uc16_resource) {
11599 CHECK(i::StringShape(string).IsExternal());
11600 if (string->IsAsciiRepresentation()) {
11601 // Check old map is not symbol or long.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011602 CHECK(string->map() == HEAP->external_ascii_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000011603 // Morph external string to be TwoByte string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011604 string->set_map(HEAP->external_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000011605 i::ExternalTwoByteString* morphed =
11606 i::ExternalTwoByteString::cast(string);
11607 morphed->set_resource(uc16_resource);
11608 } else {
11609 // Check old map is not symbol or long.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011610 CHECK(string->map() == HEAP->external_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000011611 // Morph external string to be ASCII string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011612 string->set_map(HEAP->external_ascii_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000011613 i::ExternalAsciiString* morphed =
11614 i::ExternalAsciiString::cast(string);
11615 morphed->set_resource(ascii_resource);
11616 }
11617}
11618
11619
11620// Test that we can still flatten a string if the components it is built up
11621// from have been turned into 16 bit strings in the mean time.
11622THREADED_TEST(MorphCompositeStringTest) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011623 char utf_buffer[129];
ager@chromium.org5ec48922009-05-05 07:25:34 +000011624 const char* c_string = "Now is the time for all good men"
11625 " to come to the aid of the party";
11626 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
11627 {
11628 v8::HandleScope scope;
11629 LocalContext env;
11630 AsciiVectorResource ascii_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011631 i::Vector<const char>(c_string, i::StrLength(c_string)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000011632 UC16VectorResource uc16_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011633 i::Vector<const uint16_t>(two_byte_string,
11634 i::StrLength(c_string)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000011635
11636 Local<String> lhs(v8::Utils::ToLocal(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011637 FACTORY->NewExternalStringFromAscii(&ascii_resource)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000011638 Local<String> rhs(v8::Utils::ToLocal(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011639 FACTORY->NewExternalStringFromAscii(&ascii_resource)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000011640
11641 env->Global()->Set(v8_str("lhs"), lhs);
11642 env->Global()->Set(v8_str("rhs"), rhs);
11643
11644 CompileRun(
11645 "var cons = lhs + rhs;"
11646 "var slice = lhs.substring(1, lhs.length - 1);"
11647 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
11648
11649 MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
11650 MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
11651
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011652 // This should UTF-8 without flattening, since everything is ASCII.
11653 Handle<String> cons = v8_compile("cons")->Run().As<String>();
11654 CHECK_EQ(128, cons->Utf8Length());
11655 int nchars = -1;
11656 CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
11657 CHECK_EQ(128, nchars);
11658 CHECK_EQ(0, strcmp(
11659 utf_buffer,
11660 "Now is the time for all good men to come to the aid of the party"
11661 "Now is the time for all good men to come to the aid of the party"));
11662
ager@chromium.org5ec48922009-05-05 07:25:34 +000011663 // Now do some stuff to make sure the strings are flattened, etc.
11664 CompileRun(
11665 "/[^a-z]/.test(cons);"
11666 "/[^a-z]/.test(slice);"
11667 "/[^a-z]/.test(slice_on_cons);");
11668 const char* expected_cons =
11669 "Now is the time for all good men to come to the aid of the party"
11670 "Now is the time for all good men to come to the aid of the party";
11671 const char* expected_slice =
11672 "ow is the time for all good men to come to the aid of the part";
11673 const char* expected_slice_on_cons =
11674 "ow is the time for all good men to come to the aid of the party"
11675 "Now is the time for all good men to come to the aid of the part";
11676 CHECK_EQ(String::New(expected_cons),
11677 env->Global()->Get(v8_str("cons")));
11678 CHECK_EQ(String::New(expected_slice),
11679 env->Global()->Get(v8_str("slice")));
11680 CHECK_EQ(String::New(expected_slice_on_cons),
11681 env->Global()->Get(v8_str("slice_on_cons")));
11682 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011683 i::DeleteArray(two_byte_string);
ager@chromium.org5ec48922009-05-05 07:25:34 +000011684}
11685
11686
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011687TEST(CompileExternalTwoByteSource) {
11688 v8::HandleScope scope;
11689 LocalContext context;
11690
11691 // This is a very short list of sources, which currently is to check for a
11692 // regression caused by r2703.
11693 const char* ascii_sources[] = {
11694 "0.5",
11695 "-0.5", // This mainly testes PushBack in the Scanner.
11696 "--0.5", // This mainly testes PushBack in the Scanner.
11697 NULL
11698 };
11699
11700 // Compile the sources as external two byte strings.
11701 for (int i = 0; ascii_sources[i] != NULL; i++) {
11702 uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
11703 UC16VectorResource uc16_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011704 i::Vector<const uint16_t>(two_byte_string,
11705 i::StrLength(ascii_sources[i])));
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011706 v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
11707 v8::Script::Compile(source);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011708 i::DeleteArray(two_byte_string);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011709 }
11710}
11711
11712
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011713class RegExpStringModificationTest {
11714 public:
11715 RegExpStringModificationTest()
11716 : block_(i::OS::CreateSemaphore(0)),
11717 morphs_(0),
11718 morphs_during_regexp_(0),
11719 ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
11720 uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
11721 ~RegExpStringModificationTest() { delete block_; }
11722 void RunTest() {
11723 regexp_success_ = false;
11724 morph_success_ = false;
11725
11726 // Initialize the contents of two_byte_content_ to be a uc16 representation
11727 // of "aaaaaaaaaaaaaab".
11728 for (int i = 0; i < 14; i++) {
11729 two_byte_content_[i] = 'a';
11730 }
11731 two_byte_content_[14] = 'b';
11732
11733 // Create the input string for the regexp - the one we are going to change
11734 // properties of.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011735 input_ = FACTORY->NewExternalStringFromAscii(&ascii_resource_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011736
11737 // Inject the input as a global variable.
11738 i::Handle<i::String> input_name =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011739 FACTORY->NewStringFromAscii(i::Vector<const char>("input", 5));
11740 i::Isolate::Current()->global_context()->global()->SetProperty(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011741 *input_name,
11742 *input_,
11743 NONE,
11744 i::kNonStrictMode)->ToObjectChecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011745
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011746 MorphThread morph_thread(this);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011747 morph_thread.Start();
11748 v8::Locker::StartPreemption(1);
11749 LongRunningRegExp();
11750 {
11751 v8::Unlocker unlock;
11752 morph_thread.Join();
11753 }
11754 v8::Locker::StopPreemption();
11755 CHECK(regexp_success_);
11756 CHECK(morph_success_);
11757 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011758
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000011759 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011760 // Number of string modifications required.
11761 static const int kRequiredModifications = 5;
11762 static const int kMaxModifications = 100;
11763
11764 class MorphThread : public i::Thread {
11765 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011766 explicit MorphThread(RegExpStringModificationTest* test)
11767 : Thread("MorphThread"), test_(test) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011768 virtual void Run() {
11769 test_->MorphString();
11770 }
11771 private:
11772 RegExpStringModificationTest* test_;
11773 };
11774
11775 void MorphString() {
11776 block_->Wait();
11777 while (morphs_during_regexp_ < kRequiredModifications &&
11778 morphs_ < kMaxModifications) {
11779 {
11780 v8::Locker lock;
11781 // Swap string between ascii and two-byte representation.
11782 i::String* string = *input_;
ager@chromium.org5ec48922009-05-05 07:25:34 +000011783 MorphAString(string, &ascii_resource_, &uc16_resource_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011784 morphs_++;
11785 }
11786 i::OS::Sleep(1);
11787 }
11788 morph_success_ = true;
11789 }
11790
11791 void LongRunningRegExp() {
11792 block_->Signal(); // Enable morphing thread on next preemption.
11793 while (morphs_during_regexp_ < kRequiredModifications &&
11794 morphs_ < kMaxModifications) {
11795 int morphs_before = morphs_;
11796 {
erik.corry@gmail.com145eff52010-08-23 11:36:18 +000011797 v8::HandleScope scope;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011798 // Match 15-30 "a"'s against 14 and a "b".
11799 const char* c_source =
11800 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
11801 ".exec(input) === null";
11802 Local<String> source = String::New(c_source);
11803 Local<Script> script = Script::Compile(source);
11804 Local<Value> result = script->Run();
11805 CHECK(result->IsTrue());
11806 }
11807 int morphs_after = morphs_;
11808 morphs_during_regexp_ += morphs_after - morphs_before;
11809 }
11810 regexp_success_ = true;
11811 }
11812
11813 i::uc16 two_byte_content_[15];
11814 i::Semaphore* block_;
11815 int morphs_;
11816 int morphs_during_regexp_;
11817 bool regexp_success_;
11818 bool morph_success_;
11819 i::Handle<i::String> input_;
11820 AsciiVectorResource ascii_resource_;
11821 UC16VectorResource uc16_resource_;
11822};
11823
11824
11825// Test that a regular expression execution can be interrupted and
11826// the string changed without failing.
11827TEST(RegExpStringModification) {
11828 v8::Locker lock;
11829 v8::V8::Initialize();
11830 v8::HandleScope scope;
11831 Local<Context> local_env;
11832 {
11833 LocalContext env;
11834 local_env = env.local();
11835 }
11836
11837 // Local context should still be live.
11838 CHECK(!local_env.IsEmpty());
11839 local_env->Enter();
11840
11841 // Should complete without problems.
11842 RegExpStringModificationTest().RunTest();
11843
11844 local_env->Exit();
11845}
11846
11847
11848// Test that we can set a property on the global object even if there
11849// is a read-only property in the prototype chain.
11850TEST(ReadOnlyPropertyInGlobalProto) {
11851 v8::HandleScope scope;
11852 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11853 LocalContext context(0, templ);
11854 v8::Handle<v8::Object> global = context->Global();
11855 v8::Handle<v8::Object> global_proto =
11856 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
11857 global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
11858 global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
11859 // Check without 'eval' or 'with'.
11860 v8::Handle<v8::Value> res =
11861 CompileRun("function f() { x = 42; return x; }; f()");
11862 // Check with 'eval'.
11863 res = CompileRun("function f() { eval('1'); y = 42; return y; }; f()");
11864 CHECK_EQ(v8::Integer::New(42), res);
11865 // Check with 'with'.
11866 res = CompileRun("function f() { with (this) { y = 42 }; return y; }; f()");
11867 CHECK_EQ(v8::Integer::New(42), res);
11868}
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011869
11870static int force_set_set_count = 0;
11871static int force_set_get_count = 0;
11872bool pass_on_get = false;
11873
11874static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
11875 const v8::AccessorInfo& info) {
11876 force_set_get_count++;
11877 if (pass_on_get) {
11878 return v8::Handle<v8::Value>();
11879 } else {
11880 return v8::Int32::New(3);
11881 }
11882}
11883
11884static void ForceSetSetter(v8::Local<v8::String> name,
11885 v8::Local<v8::Value> value,
11886 const v8::AccessorInfo& info) {
11887 force_set_set_count++;
11888}
11889
11890static v8::Handle<v8::Value> ForceSetInterceptSetter(
11891 v8::Local<v8::String> name,
11892 v8::Local<v8::Value> value,
11893 const v8::AccessorInfo& info) {
11894 force_set_set_count++;
11895 return v8::Undefined();
11896}
11897
11898TEST(ForceSet) {
11899 force_set_get_count = 0;
11900 force_set_set_count = 0;
11901 pass_on_get = false;
11902
11903 v8::HandleScope scope;
11904 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11905 v8::Handle<v8::String> access_property = v8::String::New("a");
11906 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
11907 LocalContext context(NULL, templ);
11908 v8::Handle<v8::Object> global = context->Global();
11909
11910 // Ordinary properties
11911 v8::Handle<v8::String> simple_property = v8::String::New("p");
11912 global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
11913 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11914 // This should fail because the property is read-only
11915 global->Set(simple_property, v8::Int32::New(5));
11916 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11917 // This should succeed even though the property is read-only
11918 global->ForceSet(simple_property, v8::Int32::New(6));
11919 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
11920
11921 // Accessors
11922 CHECK_EQ(0, force_set_set_count);
11923 CHECK_EQ(0, force_set_get_count);
11924 CHECK_EQ(3, global->Get(access_property)->Int32Value());
11925 // CHECK_EQ the property shouldn't override it, just call the setter
11926 // which in this case does nothing.
11927 global->Set(access_property, v8::Int32::New(7));
11928 CHECK_EQ(3, global->Get(access_property)->Int32Value());
11929 CHECK_EQ(1, force_set_set_count);
11930 CHECK_EQ(2, force_set_get_count);
11931 // Forcing the property to be set should override the accessor without
11932 // calling it
11933 global->ForceSet(access_property, v8::Int32::New(8));
11934 CHECK_EQ(8, global->Get(access_property)->Int32Value());
11935 CHECK_EQ(1, force_set_set_count);
11936 CHECK_EQ(2, force_set_get_count);
11937}
11938
11939TEST(ForceSetWithInterceptor) {
11940 force_set_get_count = 0;
11941 force_set_set_count = 0;
11942 pass_on_get = false;
11943
11944 v8::HandleScope scope;
11945 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11946 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
11947 LocalContext context(NULL, templ);
11948 v8::Handle<v8::Object> global = context->Global();
11949
11950 v8::Handle<v8::String> some_property = v8::String::New("a");
11951 CHECK_EQ(0, force_set_set_count);
11952 CHECK_EQ(0, force_set_get_count);
11953 CHECK_EQ(3, global->Get(some_property)->Int32Value());
11954 // Setting the property shouldn't override it, just call the setter
11955 // which in this case does nothing.
11956 global->Set(some_property, v8::Int32::New(7));
11957 CHECK_EQ(3, global->Get(some_property)->Int32Value());
11958 CHECK_EQ(1, force_set_set_count);
11959 CHECK_EQ(2, force_set_get_count);
11960 // Getting the property when the interceptor returns an empty handle
11961 // should yield undefined, since the property isn't present on the
11962 // object itself yet.
11963 pass_on_get = true;
11964 CHECK(global->Get(some_property)->IsUndefined());
11965 CHECK_EQ(1, force_set_set_count);
11966 CHECK_EQ(3, force_set_get_count);
11967 // Forcing the property to be set should cause the value to be
11968 // set locally without calling the interceptor.
11969 global->ForceSet(some_property, v8::Int32::New(8));
11970 CHECK_EQ(8, global->Get(some_property)->Int32Value());
11971 CHECK_EQ(1, force_set_set_count);
11972 CHECK_EQ(4, force_set_get_count);
11973 // Reenabling the interceptor should cause it to take precedence over
11974 // the property
11975 pass_on_get = false;
11976 CHECK_EQ(3, global->Get(some_property)->Int32Value());
11977 CHECK_EQ(1, force_set_set_count);
11978 CHECK_EQ(5, force_set_get_count);
11979 // The interceptor should also work for other properties
11980 CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
11981 CHECK_EQ(1, force_set_set_count);
11982 CHECK_EQ(6, force_set_get_count);
11983}
ager@chromium.org1bf0cd02009-05-20 11:34:19 +000011984
11985
ager@chromium.orge2902be2009-06-08 12:21:35 +000011986THREADED_TEST(ForceDelete) {
11987 v8::HandleScope scope;
11988 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11989 LocalContext context(NULL, templ);
11990 v8::Handle<v8::Object> global = context->Global();
11991
11992 // Ordinary properties
11993 v8::Handle<v8::String> simple_property = v8::String::New("p");
11994 global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
11995 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11996 // This should fail because the property is dont-delete.
11997 CHECK(!global->Delete(simple_property));
11998 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11999 // This should succeed even though the property is dont-delete.
12000 CHECK(global->ForceDelete(simple_property));
12001 CHECK(global->Get(simple_property)->IsUndefined());
12002}
12003
12004
12005static int force_delete_interceptor_count = 0;
12006static bool pass_on_delete = false;
12007
12008
12009static v8::Handle<v8::Boolean> ForceDeleteDeleter(
12010 v8::Local<v8::String> name,
12011 const v8::AccessorInfo& info) {
12012 force_delete_interceptor_count++;
12013 if (pass_on_delete) {
12014 return v8::Handle<v8::Boolean>();
12015 } else {
12016 return v8::True();
12017 }
12018}
12019
12020
12021THREADED_TEST(ForceDeleteWithInterceptor) {
12022 force_delete_interceptor_count = 0;
12023 pass_on_delete = false;
12024
12025 v8::HandleScope scope;
12026 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12027 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
12028 LocalContext context(NULL, templ);
12029 v8::Handle<v8::Object> global = context->Global();
12030
12031 v8::Handle<v8::String> some_property = v8::String::New("a");
12032 global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
12033
12034 // Deleting a property should get intercepted and nothing should
12035 // happen.
12036 CHECK_EQ(0, force_delete_interceptor_count);
12037 CHECK(global->Delete(some_property));
12038 CHECK_EQ(1, force_delete_interceptor_count);
12039 CHECK_EQ(42, global->Get(some_property)->Int32Value());
12040 // Deleting the property when the interceptor returns an empty
12041 // handle should not delete the property since it is DontDelete.
12042 pass_on_delete = true;
12043 CHECK(!global->Delete(some_property));
12044 CHECK_EQ(2, force_delete_interceptor_count);
12045 CHECK_EQ(42, global->Get(some_property)->Int32Value());
12046 // Forcing the property to be deleted should delete the value
12047 // without calling the interceptor.
12048 CHECK(global->ForceDelete(some_property));
12049 CHECK(global->Get(some_property)->IsUndefined());
12050 CHECK_EQ(2, force_delete_interceptor_count);
12051}
12052
12053
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000012054// Make sure that forcing a delete invalidates any IC stubs, so we
12055// don't read the hole value.
12056THREADED_TEST(ForceDeleteIC) {
12057 v8::HandleScope scope;
12058 LocalContext context;
12059 // Create a DontDelete variable on the global object.
12060 CompileRun("this.__proto__ = { foo: 'horse' };"
12061 "var foo = 'fish';"
12062 "function f() { return foo.length; }");
12063 // Initialize the IC for foo in f.
12064 CompileRun("for (var i = 0; i < 4; i++) f();");
12065 // Make sure the value of foo is correct before the deletion.
12066 CHECK_EQ(4, CompileRun("f()")->Int32Value());
12067 // Force the deletion of foo.
12068 CHECK(context->Global()->ForceDelete(v8_str("foo")));
12069 // Make sure the value for foo is read from the prototype, and that
12070 // we don't get in trouble with reading the deleted cell value
12071 // sentinel.
12072 CHECK_EQ(5, CompileRun("f()")->Int32Value());
12073}
12074
12075
ager@chromium.org1bf0cd02009-05-20 11:34:19 +000012076v8::Persistent<Context> calling_context0;
12077v8::Persistent<Context> calling_context1;
12078v8::Persistent<Context> calling_context2;
12079
12080
12081// Check that the call to the callback is initiated in
12082// calling_context2, the directly calling context is calling_context1
12083// and the callback itself is in calling_context0.
12084static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
12085 ApiTestFuzzer::Fuzz();
12086 CHECK(Context::GetCurrent() == calling_context0);
12087 CHECK(Context::GetCalling() == calling_context1);
12088 CHECK(Context::GetEntered() == calling_context2);
12089 return v8::Integer::New(42);
12090}
12091
12092
12093THREADED_TEST(GetCallingContext) {
12094 v8::HandleScope scope;
12095
12096 calling_context0 = Context::New();
12097 calling_context1 = Context::New();
12098 calling_context2 = Context::New();
12099
12100 // Allow cross-domain access.
12101 Local<String> token = v8_str("<security token>");
12102 calling_context0->SetSecurityToken(token);
12103 calling_context1->SetSecurityToken(token);
12104 calling_context2->SetSecurityToken(token);
12105
12106 // Create an object with a C++ callback in context0.
12107 calling_context0->Enter();
12108 Local<v8::FunctionTemplate> callback_templ =
12109 v8::FunctionTemplate::New(GetCallingContextCallback);
12110 calling_context0->Global()->Set(v8_str("callback"),
12111 callback_templ->GetFunction());
12112 calling_context0->Exit();
12113
12114 // Expose context0 in context1 and setup a function that calls the
12115 // callback function.
12116 calling_context1->Enter();
12117 calling_context1->Global()->Set(v8_str("context0"),
12118 calling_context0->Global());
12119 CompileRun("function f() { context0.callback() }");
12120 calling_context1->Exit();
12121
12122 // Expose context1 in context2 and call the callback function in
12123 // context0 indirectly through f in context1.
12124 calling_context2->Enter();
12125 calling_context2->Global()->Set(v8_str("context1"),
12126 calling_context1->Global());
12127 CompileRun("context1.f()");
12128 calling_context2->Exit();
12129
12130 // Dispose the contexts to allow them to be garbage collected.
12131 calling_context0.Dispose();
12132 calling_context1.Dispose();
12133 calling_context2.Dispose();
12134 calling_context0.Clear();
12135 calling_context1.Clear();
12136 calling_context2.Clear();
12137}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012138
12139
12140// Check that a variable declaration with no explicit initialization
12141// value does not shadow an existing property in the prototype chain.
12142//
12143// This is consistent with Firefox and Safari.
12144//
12145// See http://crbug.com/12548.
12146THREADED_TEST(InitGlobalVarInProtoChain) {
12147 v8::HandleScope scope;
12148 LocalContext context;
12149 // Introduce a variable in the prototype chain.
12150 CompileRun("__proto__.x = 42");
12151 v8::Handle<v8::Value> result = CompileRun("var x; x");
12152 CHECK(!result->IsUndefined());
12153 CHECK_EQ(42, result->Int32Value());
12154}
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000012155
12156
12157// Regression test for issue 398.
12158// If a function is added to an object, creating a constant function
12159// field, and the result is cloned, replacing the constant function on the
12160// original should not affect the clone.
12161// See http://code.google.com/p/v8/issues/detail?id=398
12162THREADED_TEST(ReplaceConstantFunction) {
12163 v8::HandleScope scope;
12164 LocalContext context;
12165 v8::Handle<v8::Object> obj = v8::Object::New();
12166 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
12167 v8::Handle<v8::String> foo_string = v8::String::New("foo");
12168 obj->Set(foo_string, func_templ->GetFunction());
12169 v8::Handle<v8::Object> obj_clone = obj->Clone();
12170 obj_clone->Set(foo_string, v8::String::New("Hello"));
12171 CHECK(!obj->Get(foo_string)->IsUndefined());
12172}
kasperl@chromium.orge959c182009-07-27 08:59:04 +000012173
12174
12175// Regression test for http://crbug.com/16276.
12176THREADED_TEST(Regress16276) {
12177 v8::HandleScope scope;
12178 LocalContext context;
12179 // Force the IC in f to be a dictionary load IC.
12180 CompileRun("function f(obj) { return obj.x; }\n"
12181 "var obj = { x: { foo: 42 }, y: 87 };\n"
12182 "var x = obj.x;\n"
12183 "delete obj.y;\n"
12184 "for (var i = 0; i < 5; i++) f(obj);");
12185 // Detach the global object to make 'this' refer directly to the
12186 // global object (not the proxy), and make sure that the dictionary
12187 // load IC doesn't mess up loading directly from the global object.
12188 context->DetachGlobal();
12189 CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
12190}
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012191
12192
12193THREADED_TEST(PixelArray) {
12194 v8::HandleScope scope;
12195 LocalContext context;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000012196 const int kElementCount = 260;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012197 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012198 i::Handle<i::ExternalPixelArray> pixels =
12199 i::Handle<i::ExternalPixelArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012200 FACTORY->NewExternalArray(kElementCount,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012201 v8::kExternalPixelArray,
12202 pixel_data));
12203 // Force GC to trigger verification.
12204 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012205 for (int i = 0; i < kElementCount; i++) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000012206 pixels->set(i, i % 256);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012207 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012208 // Force GC to trigger verification.
12209 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012210 for (int i = 0; i < kElementCount; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012211 CHECK_EQ(i % 256, pixels->get_scalar(i));
ager@chromium.orgc4c92722009-11-18 14:12:51 +000012212 CHECK_EQ(i % 256, pixel_data[i]);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012213 }
12214
12215 v8::Handle<v8::Object> obj = v8::Object::New();
12216 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
12217 // Set the elements to be the pixels.
12218 // jsobj->set_elements(*pixels);
12219 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012220 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012221 obj->Set(v8_str("field"), v8::Int32::New(1503));
12222 context->Global()->Set(v8_str("pixels"), obj);
12223 v8::Handle<v8::Value> result = CompileRun("pixels.field");
12224 CHECK_EQ(1503, result->Int32Value());
12225 result = CompileRun("pixels[1]");
12226 CHECK_EQ(1, result->Int32Value());
sgjesse@chromium.org9eceac12009-09-30 07:18:41 +000012227
12228 result = CompileRun("var sum = 0;"
12229 "for (var i = 0; i < 8; i++) {"
12230 " sum += pixels[i] = pixels[i] = -i;"
12231 "}"
12232 "sum;");
12233 CHECK_EQ(-28, result->Int32Value());
12234
12235 result = CompileRun("var sum = 0;"
12236 "for (var i = 0; i < 8; i++) {"
12237 " sum += pixels[i] = pixels[i] = 0;"
12238 "}"
12239 "sum;");
12240 CHECK_EQ(0, result->Int32Value());
12241
12242 result = CompileRun("var sum = 0;"
12243 "for (var i = 0; i < 8; i++) {"
12244 " sum += pixels[i] = pixels[i] = 255;"
12245 "}"
12246 "sum;");
12247 CHECK_EQ(8 * 255, result->Int32Value());
12248
12249 result = CompileRun("var sum = 0;"
12250 "for (var i = 0; i < 8; i++) {"
12251 " sum += pixels[i] = pixels[i] = 256 + i;"
12252 "}"
12253 "sum;");
12254 CHECK_EQ(2076, result->Int32Value());
12255
12256 result = CompileRun("var sum = 0;"
12257 "for (var i = 0; i < 8; i++) {"
12258 " sum += pixels[i] = pixels[i] = i;"
12259 "}"
12260 "sum;");
12261 CHECK_EQ(28, result->Int32Value());
12262
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012263 result = CompileRun("var sum = 0;"
12264 "for (var i = 0; i < 8; i++) {"
12265 " sum += pixels[i];"
12266 "}"
12267 "sum;");
12268 CHECK_EQ(28, result->Int32Value());
12269
12270 i::Handle<i::Smi> value(i::Smi::FromInt(2));
jkummerow@chromium.org486075a2011-09-07 12:44:28 +000012271 i::Handle<i::Object> no_failure;
12272 no_failure = i::SetElement(jsobj, 1, value, i::kNonStrictMode);
12273 ASSERT(!no_failure.is_null());
12274 i::USE(no_failure);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012275 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012276 *value.location() = i::Smi::FromInt(256);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +000012277 no_failure = i::SetElement(jsobj, 1, value, i::kNonStrictMode);
12278 ASSERT(!no_failure.is_null());
12279 i::USE(no_failure);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012280 CHECK_EQ(255,
12281 i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012282 *value.location() = i::Smi::FromInt(-1);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +000012283 no_failure = i::SetElement(jsobj, 1, value, i::kNonStrictMode);
12284 ASSERT(!no_failure.is_null());
12285 i::USE(no_failure);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012286 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012287
12288 result = CompileRun("for (var i = 0; i < 8; i++) {"
12289 " pixels[i] = (i * 65) - 109;"
12290 "}"
12291 "pixels[1] + pixels[6];");
12292 CHECK_EQ(255, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012293 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
12294 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
12295 CHECK_EQ(21,
12296 i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
12297 CHECK_EQ(86,
12298 i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
12299 CHECK_EQ(151,
12300 i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
12301 CHECK_EQ(216,
12302 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
12303 CHECK_EQ(255,
12304 i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
12305 CHECK_EQ(255,
12306 i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012307 result = CompileRun("var sum = 0;"
12308 "for (var i = 0; i < 8; i++) {"
12309 " sum += pixels[i];"
12310 "}"
12311 "sum;");
12312 CHECK_EQ(984, result->Int32Value());
12313
12314 result = CompileRun("for (var i = 0; i < 8; i++) {"
12315 " pixels[i] = (i * 1.1);"
12316 "}"
12317 "pixels[1] + pixels[6];");
12318 CHECK_EQ(8, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012319 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
12320 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
12321 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
12322 CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
12323 CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
12324 CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
12325 CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
12326 CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012327
12328 result = CompileRun("for (var i = 0; i < 8; i++) {"
12329 " pixels[7] = undefined;"
12330 "}"
12331 "pixels[7];");
12332 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012333 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012334
12335 result = CompileRun("for (var i = 0; i < 8; i++) {"
12336 " pixels[6] = '2.3';"
12337 "}"
12338 "pixels[6];");
12339 CHECK_EQ(2, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012340 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012341
12342 result = CompileRun("for (var i = 0; i < 8; i++) {"
12343 " pixels[5] = NaN;"
12344 "}"
12345 "pixels[5];");
12346 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012347 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012348
12349 result = CompileRun("for (var i = 0; i < 8; i++) {"
12350 " pixels[8] = Infinity;"
12351 "}"
12352 "pixels[8];");
12353 CHECK_EQ(255, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012354 CHECK_EQ(255,
12355 i::Smi::cast(jsobj->GetElement(8)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012356
12357 result = CompileRun("for (var i = 0; i < 8; i++) {"
12358 " pixels[9] = -Infinity;"
12359 "}"
12360 "pixels[9];");
12361 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012362 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012363
12364 result = CompileRun("pixels[3] = 33;"
12365 "delete pixels[3];"
12366 "pixels[3];");
12367 CHECK_EQ(33, result->Int32Value());
12368
12369 result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
12370 "pixels[2] = 12; pixels[3] = 13;"
12371 "pixels.__defineGetter__('2',"
12372 "function() { return 120; });"
12373 "pixels[2];");
12374 CHECK_EQ(12, result->Int32Value());
12375
12376 result = CompileRun("var js_array = new Array(40);"
12377 "js_array[0] = 77;"
12378 "js_array;");
12379 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
12380
12381 result = CompileRun("pixels[1] = 23;"
12382 "pixels.__proto__ = [];"
12383 "js_array.__proto__ = pixels;"
12384 "js_array.concat(pixels);");
12385 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
12386 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
12387
sgjesse@chromium.org9eceac12009-09-30 07:18:41 +000012388 result = CompileRun("pixels[1] = 23;");
12389 CHECK_EQ(23, result->Int32Value());
12390
ager@chromium.orgc4c92722009-11-18 14:12:51 +000012391 // Test for index greater than 255. Regression test for:
12392 // http://code.google.com/p/chromium/issues/detail?id=26337.
12393 result = CompileRun("pixels[256] = 255;");
12394 CHECK_EQ(255, result->Int32Value());
12395 result = CompileRun("var i = 0;"
12396 "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
12397 "i");
12398 CHECK_EQ(255, result->Int32Value());
12399
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012400 // Make sure that pixel array ICs recognize when a non-pixel array
12401 // is passed to it.
12402 result = CompileRun("function pa_load(p) {"
12403 " var sum = 0;"
12404 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
12405 " return sum;"
12406 "}"
12407 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12408 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
12409 "just_ints = new Object();"
12410 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12411 "for (var i = 0; i < 10; ++i) {"
12412 " result = pa_load(just_ints);"
12413 "}"
12414 "result");
12415 CHECK_EQ(32640, result->Int32Value());
12416
12417 // Make sure that pixel array ICs recognize out-of-bound accesses.
12418 result = CompileRun("function pa_load(p, start) {"
12419 " var sum = 0;"
12420 " for (var j = start; j < 256; j++) { sum += p[j]; }"
12421 " return sum;"
12422 "}"
12423 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12424 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
12425 "for (var i = 0; i < 10; ++i) {"
12426 " result = pa_load(pixels,-10);"
12427 "}"
12428 "result");
12429 CHECK_EQ(0, result->Int32Value());
12430
12431 // Make sure that generic ICs properly handles a pixel array.
12432 result = CompileRun("function pa_load(p) {"
12433 " var sum = 0;"
12434 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
12435 " return sum;"
12436 "}"
12437 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12438 "just_ints = new Object();"
12439 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12440 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
12441 "for (var i = 0; i < 10; ++i) {"
12442 " result = pa_load(pixels);"
12443 "}"
12444 "result");
12445 CHECK_EQ(32640, result->Int32Value());
12446
12447 // Make sure that generic load ICs recognize out-of-bound accesses in
12448 // pixel arrays.
12449 result = CompileRun("function pa_load(p, start) {"
12450 " var sum = 0;"
12451 " for (var j = start; j < 256; j++) { sum += p[j]; }"
12452 " return sum;"
12453 "}"
12454 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12455 "just_ints = new Object();"
12456 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12457 "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
12458 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
12459 "for (var i = 0; i < 10; ++i) {"
12460 " result = pa_load(pixels,-10);"
12461 "}"
12462 "result");
12463 CHECK_EQ(0, result->Int32Value());
12464
12465 // Make sure that generic ICs properly handles other types than pixel
12466 // arrays (that the inlined fast pixel array test leaves the right information
12467 // in the right registers).
12468 result = CompileRun("function pa_load(p) {"
12469 " var sum = 0;"
12470 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
12471 " return sum;"
12472 "}"
12473 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12474 "just_ints = new Object();"
12475 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12476 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
12477 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
12478 "sparse_array = new Object();"
12479 "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
12480 "sparse_array[1000000] = 3;"
12481 "for (var i = 0; i < 10; ++i) {"
12482 " result = pa_load(sparse_array);"
12483 "}"
12484 "result");
12485 CHECK_EQ(32640, result->Int32Value());
12486
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +000012487 // Make sure that pixel array store ICs clamp values correctly.
12488 result = CompileRun("function pa_store(p) {"
12489 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
12490 "}"
12491 "pa_store(pixels);"
12492 "var sum = 0;"
12493 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
12494 "sum");
12495 CHECK_EQ(48896, result->Int32Value());
12496
12497 // Make sure that pixel array stores correctly handle accesses outside
12498 // of the pixel array..
12499 result = CompileRun("function pa_store(p,start) {"
12500 " for (var j = 0; j < 256; j++) {"
12501 " p[j+start] = j * 2;"
12502 " }"
12503 "}"
12504 "pa_store(pixels,0);"
12505 "pa_store(pixels,-128);"
12506 "var sum = 0;"
12507 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
12508 "sum");
12509 CHECK_EQ(65280, result->Int32Value());
12510
12511 // Make sure that the generic store stub correctly handle accesses outside
12512 // of the pixel array..
12513 result = CompileRun("function pa_store(p,start) {"
12514 " for (var j = 0; j < 256; j++) {"
12515 " p[j+start] = j * 2;"
12516 " }"
12517 "}"
12518 "pa_store(pixels,0);"
12519 "just_ints = new Object();"
12520 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12521 "pa_store(just_ints, 0);"
12522 "pa_store(pixels,-128);"
12523 "var sum = 0;"
12524 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
12525 "sum");
12526 CHECK_EQ(65280, result->Int32Value());
12527
12528 // Make sure that the generic keyed store stub clamps pixel array values
12529 // correctly.
12530 result = CompileRun("function pa_store(p) {"
12531 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
12532 "}"
12533 "pa_store(pixels);"
12534 "just_ints = new Object();"
12535 "pa_store(just_ints);"
12536 "pa_store(pixels);"
12537 "var sum = 0;"
12538 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
12539 "sum");
12540 CHECK_EQ(48896, result->Int32Value());
12541
12542 // Make sure that pixel array loads are optimized by crankshaft.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000012543 result = CompileRun("function pa_load(p) {"
12544 " var sum = 0;"
12545 " for (var i=0; i<256; ++i) {"
12546 " sum += p[i];"
12547 " }"
12548 " return sum; "
12549 "}"
12550 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012551 "for (var i = 0; i < 5000; ++i) {"
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000012552 " result = pa_load(pixels);"
12553 "}"
12554 "result");
12555 CHECK_EQ(32640, result->Int32Value());
12556
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000012557 // Make sure that pixel array stores are optimized by crankshaft.
12558 result = CompileRun("function pa_init(p) {"
12559 "for (var i = 0; i < 256; ++i) { p[i] = i; }"
12560 "}"
12561 "function pa_load(p) {"
12562 " var sum = 0;"
12563 " for (var i=0; i<256; ++i) {"
12564 " sum += p[i];"
12565 " }"
12566 " return sum; "
12567 "}"
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012568 "for (var i = 0; i < 5000; ++i) {"
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000012569 " pa_init(pixels);"
12570 "}"
12571 "result = pa_load(pixels);"
12572 "result");
12573 CHECK_EQ(32640, result->Int32Value());
12574
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012575 free(pixel_data);
12576}
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000012577
ager@chromium.org96c75b52009-08-26 09:13:16 +000012578
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000012579THREADED_TEST(PixelArrayInfo) {
12580 v8::HandleScope scope;
12581 LocalContext context;
12582 for (int size = 0; size < 100; size += 10) {
12583 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
12584 v8::Handle<v8::Object> obj = v8::Object::New();
12585 obj->SetIndexedPropertiesToPixelData(pixel_data, size);
12586 CHECK(obj->HasIndexedPropertiesInPixelData());
12587 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
12588 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
12589 free(pixel_data);
12590 }
12591}
12592
12593
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000012594static v8::Handle<Value> NotHandledIndexedPropertyGetter(
12595 uint32_t index,
12596 const AccessorInfo& info) {
12597 ApiTestFuzzer::Fuzz();
12598 return v8::Handle<Value>();
12599}
12600
12601
12602static v8::Handle<Value> NotHandledIndexedPropertySetter(
12603 uint32_t index,
12604 Local<Value> value,
12605 const AccessorInfo& info) {
12606 ApiTestFuzzer::Fuzz();
12607 return v8::Handle<Value>();
12608}
12609
12610
12611THREADED_TEST(PixelArrayWithInterceptor) {
12612 v8::HandleScope scope;
12613 LocalContext context;
12614 const int kElementCount = 260;
12615 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012616 i::Handle<i::ExternalPixelArray> pixels =
12617 i::Handle<i::ExternalPixelArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012618 FACTORY->NewExternalArray(kElementCount,
12619 v8::kExternalPixelArray,
12620 pixel_data));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000012621 for (int i = 0; i < kElementCount; i++) {
12622 pixels->set(i, i % 256);
12623 }
12624 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12625 templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
12626 NotHandledIndexedPropertySetter);
12627 v8::Handle<v8::Object> obj = templ->NewInstance();
12628 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
12629 context->Global()->Set(v8_str("pixels"), obj);
12630 v8::Handle<v8::Value> result = CompileRun("pixels[1]");
12631 CHECK_EQ(1, result->Int32Value());
12632 result = CompileRun("var sum = 0;"
12633 "for (var i = 0; i < 8; i++) {"
12634 " sum += pixels[i] = pixels[i] = -i;"
12635 "}"
12636 "sum;");
12637 CHECK_EQ(-28, result->Int32Value());
12638 result = CompileRun("pixels.hasOwnProperty('1')");
12639 CHECK(result->BooleanValue());
12640 free(pixel_data);
12641}
12642
12643
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000012644static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
12645 switch (array_type) {
12646 case v8::kExternalByteArray:
12647 case v8::kExternalUnsignedByteArray:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012648 case v8::kExternalPixelArray:
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000012649 return 1;
12650 break;
12651 case v8::kExternalShortArray:
12652 case v8::kExternalUnsignedShortArray:
12653 return 2;
12654 break;
12655 case v8::kExternalIntArray:
12656 case v8::kExternalUnsignedIntArray:
12657 case v8::kExternalFloatArray:
12658 return 4;
12659 break;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000012660 case v8::kExternalDoubleArray:
12661 return 8;
12662 break;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000012663 default:
12664 UNREACHABLE();
12665 return -1;
12666 }
12667 UNREACHABLE();
12668 return -1;
12669}
12670
12671
ager@chromium.org3811b432009-10-28 14:53:37 +000012672template <class ExternalArrayClass, class ElementType>
12673static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
12674 int64_t low,
12675 int64_t high) {
12676 v8::HandleScope scope;
12677 LocalContext context;
12678 const int kElementCount = 40;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000012679 int element_size = ExternalArrayElementSize(array_type);
ager@chromium.org3811b432009-10-28 14:53:37 +000012680 ElementType* array_data =
12681 static_cast<ElementType*>(malloc(kElementCount * element_size));
12682 i::Handle<ExternalArrayClass> array =
12683 i::Handle<ExternalArrayClass>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012684 FACTORY->NewExternalArray(kElementCount, array_type, array_data));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012685 // Force GC to trigger verification.
12686 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3811b432009-10-28 14:53:37 +000012687 for (int i = 0; i < kElementCount; i++) {
12688 array->set(i, static_cast<ElementType>(i));
12689 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012690 // Force GC to trigger verification.
12691 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3811b432009-10-28 14:53:37 +000012692 for (int i = 0; i < kElementCount; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012693 CHECK_EQ(static_cast<int64_t>(i),
12694 static_cast<int64_t>(array->get_scalar(i)));
ager@chromium.org3811b432009-10-28 14:53:37 +000012695 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
12696 }
12697
12698 v8::Handle<v8::Object> obj = v8::Object::New();
12699 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
12700 // Set the elements to be the external array.
12701 obj->SetIndexedPropertiesToExternalArrayData(array_data,
12702 array_type,
12703 kElementCount);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012704 CHECK_EQ(
12705 1, static_cast<int>(jsobj->GetElement(1)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000012706 obj->Set(v8_str("field"), v8::Int32::New(1503));
12707 context->Global()->Set(v8_str("ext_array"), obj);
12708 v8::Handle<v8::Value> result = CompileRun("ext_array.field");
12709 CHECK_EQ(1503, result->Int32Value());
12710 result = CompileRun("ext_array[1]");
12711 CHECK_EQ(1, result->Int32Value());
12712
12713 // Check pass through of assigned smis
12714 result = CompileRun("var sum = 0;"
12715 "for (var i = 0; i < 8; i++) {"
12716 " sum += ext_array[i] = ext_array[i] = -i;"
12717 "}"
12718 "sum;");
12719 CHECK_EQ(-28, result->Int32Value());
12720
12721 // Check assigned smis
12722 result = CompileRun("for (var i = 0; i < 8; i++) {"
12723 " ext_array[i] = i;"
12724 "}"
12725 "var sum = 0;"
12726 "for (var i = 0; i < 8; i++) {"
12727 " sum += ext_array[i];"
12728 "}"
12729 "sum;");
12730 CHECK_EQ(28, result->Int32Value());
12731
12732 // Check assigned smis in reverse order
12733 result = CompileRun("for (var i = 8; --i >= 0; ) {"
12734 " ext_array[i] = i;"
12735 "}"
12736 "var sum = 0;"
12737 "for (var i = 0; i < 8; i++) {"
12738 " sum += ext_array[i];"
12739 "}"
12740 "sum;");
12741 CHECK_EQ(28, result->Int32Value());
12742
12743 // Check pass through of assigned HeapNumbers
12744 result = CompileRun("var sum = 0;"
12745 "for (var i = 0; i < 16; i+=2) {"
12746 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
12747 "}"
12748 "sum;");
12749 CHECK_EQ(-28, result->Int32Value());
12750
12751 // Check assigned HeapNumbers
12752 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
12753 " ext_array[i] = (i * 0.5);"
12754 "}"
12755 "var sum = 0;"
12756 "for (var i = 0; i < 16; i+=2) {"
12757 " sum += ext_array[i];"
12758 "}"
12759 "sum;");
12760 CHECK_EQ(28, result->Int32Value());
12761
12762 // Check assigned HeapNumbers in reverse order
12763 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
12764 " ext_array[i] = (i * 0.5);"
12765 "}"
12766 "var sum = 0;"
12767 "for (var i = 0; i < 16; i+=2) {"
12768 " sum += ext_array[i];"
12769 "}"
12770 "sum;");
12771 CHECK_EQ(28, result->Int32Value());
12772
12773 i::ScopedVector<char> test_buf(1024);
12774
12775 // Check legal boundary conditions.
12776 // The repeated loads and stores ensure the ICs are exercised.
12777 const char* boundary_program =
12778 "var res = 0;"
12779 "for (var i = 0; i < 16; i++) {"
12780 " ext_array[i] = %lld;"
12781 " if (i > 8) {"
12782 " res = ext_array[i];"
12783 " }"
12784 "}"
12785 "res;";
12786 i::OS::SNPrintF(test_buf,
12787 boundary_program,
12788 low);
12789 result = CompileRun(test_buf.start());
12790 CHECK_EQ(low, result->IntegerValue());
12791
12792 i::OS::SNPrintF(test_buf,
12793 boundary_program,
12794 high);
12795 result = CompileRun(test_buf.start());
12796 CHECK_EQ(high, result->IntegerValue());
12797
12798 // Check misprediction of type in IC.
12799 result = CompileRun("var tmp_array = ext_array;"
12800 "var sum = 0;"
12801 "for (var i = 0; i < 8; i++) {"
12802 " tmp_array[i] = i;"
12803 " sum += tmp_array[i];"
12804 " if (i == 4) {"
12805 " tmp_array = {};"
12806 " }"
12807 "}"
12808 "sum;");
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012809 // Force GC to trigger verification.
12810 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3811b432009-10-28 14:53:37 +000012811 CHECK_EQ(28, result->Int32Value());
12812
12813 // Make sure out-of-range loads do not throw.
12814 i::OS::SNPrintF(test_buf,
12815 "var caught_exception = false;"
12816 "try {"
12817 " ext_array[%d];"
12818 "} catch (e) {"
12819 " caught_exception = true;"
12820 "}"
12821 "caught_exception;",
12822 kElementCount);
12823 result = CompileRun(test_buf.start());
12824 CHECK_EQ(false, result->BooleanValue());
12825
12826 // Make sure out-of-range stores do not throw.
12827 i::OS::SNPrintF(test_buf,
12828 "var caught_exception = false;"
12829 "try {"
12830 " ext_array[%d] = 1;"
12831 "} catch (e) {"
12832 " caught_exception = true;"
12833 "}"
12834 "caught_exception;",
12835 kElementCount);
12836 result = CompileRun(test_buf.start());
12837 CHECK_EQ(false, result->BooleanValue());
12838
12839 // Check other boundary conditions, values and operations.
12840 result = CompileRun("for (var i = 0; i < 8; i++) {"
12841 " ext_array[7] = undefined;"
12842 "}"
12843 "ext_array[7];");
12844 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012845 CHECK_EQ(
12846 0, static_cast<int>(jsobj->GetElement(7)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000012847
12848 result = CompileRun("for (var i = 0; i < 8; i++) {"
12849 " ext_array[6] = '2.3';"
12850 "}"
12851 "ext_array[6];");
12852 CHECK_EQ(2, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012853 CHECK_EQ(
12854 2, static_cast<int>(jsobj->GetElement(6)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000012855
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000012856 if (array_type != v8::kExternalFloatArray &&
12857 array_type != v8::kExternalDoubleArray) {
ager@chromium.org3811b432009-10-28 14:53:37 +000012858 // Though the specification doesn't state it, be explicit about
12859 // converting NaNs and +/-Infinity to zero.
12860 result = CompileRun("for (var i = 0; i < 8; i++) {"
12861 " ext_array[i] = 5;"
12862 "}"
12863 "for (var i = 0; i < 8; i++) {"
12864 " ext_array[i] = NaN;"
12865 "}"
12866 "ext_array[5];");
12867 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012868 CHECK_EQ(0,
12869 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
ager@chromium.org3811b432009-10-28 14:53:37 +000012870
12871 result = CompileRun("for (var i = 0; i < 8; i++) {"
12872 " ext_array[i] = 5;"
12873 "}"
12874 "for (var i = 0; i < 8; i++) {"
12875 " ext_array[i] = Infinity;"
12876 "}"
12877 "ext_array[5];");
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012878 int expected_value =
12879 (array_type == v8::kExternalPixelArray) ? 255 : 0;
12880 CHECK_EQ(expected_value, result->Int32Value());
12881 CHECK_EQ(expected_value,
lrn@chromium.org303ada72010-10-27 09:33:13 +000012882 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
ager@chromium.org3811b432009-10-28 14:53:37 +000012883
12884 result = CompileRun("for (var i = 0; i < 8; i++) {"
12885 " ext_array[i] = 5;"
12886 "}"
12887 "for (var i = 0; i < 8; i++) {"
12888 " ext_array[i] = -Infinity;"
12889 "}"
12890 "ext_array[5];");
12891 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012892 CHECK_EQ(0,
12893 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000012894
12895 // Check truncation behavior of integral arrays.
12896 const char* unsigned_data =
12897 "var source_data = [0.6, 10.6];"
12898 "var expected_results = [0, 10];";
12899 const char* signed_data =
12900 "var source_data = [0.6, 10.6, -0.6, -10.6];"
12901 "var expected_results = [0, 10, 0, -10];";
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012902 const char* pixel_data =
12903 "var source_data = [0.6, 10.6];"
12904 "var expected_results = [1, 11];";
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000012905 bool is_unsigned =
12906 (array_type == v8::kExternalUnsignedByteArray ||
12907 array_type == v8::kExternalUnsignedShortArray ||
12908 array_type == v8::kExternalUnsignedIntArray);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012909 bool is_pixel_data = array_type == v8::kExternalPixelArray;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000012910
12911 i::OS::SNPrintF(test_buf,
12912 "%s"
12913 "var all_passed = true;"
12914 "for (var i = 0; i < source_data.length; i++) {"
12915 " for (var j = 0; j < 8; j++) {"
12916 " ext_array[j] = source_data[i];"
12917 " }"
12918 " all_passed = all_passed &&"
12919 " (ext_array[5] == expected_results[i]);"
12920 "}"
12921 "all_passed;",
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012922 (is_unsigned ?
12923 unsigned_data :
12924 (is_pixel_data ? pixel_data : signed_data)));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000012925 result = CompileRun(test_buf.start());
12926 CHECK_EQ(true, result->BooleanValue());
ager@chromium.org3811b432009-10-28 14:53:37 +000012927 }
12928
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000012929 for (int i = 0; i < kElementCount; i++) {
12930 array->set(i, static_cast<ElementType>(i));
12931 }
12932 // Test complex assignments
12933 result = CompileRun("function ee_op_test_complex_func(sum) {"
12934 " for (var i = 0; i < 40; ++i) {"
12935 " sum += (ext_array[i] += 1);"
12936 " sum += (ext_array[i] -= 1);"
12937 " } "
12938 " return sum;"
12939 "}"
12940 "sum=0;"
12941 "for (var i=0;i<10000;++i) {"
12942 " sum=ee_op_test_complex_func(sum);"
12943 "}"
12944 "sum;");
12945 CHECK_EQ(16000000, result->Int32Value());
12946
12947 // Test count operations
12948 result = CompileRun("function ee_op_test_count_func(sum) {"
12949 " for (var i = 0; i < 40; ++i) {"
12950 " sum += (++ext_array[i]);"
12951 " sum += (--ext_array[i]);"
12952 " } "
12953 " return sum;"
12954 "}"
12955 "sum=0;"
12956 "for (var i=0;i<10000;++i) {"
12957 " sum=ee_op_test_count_func(sum);"
12958 "}"
12959 "sum;");
12960 CHECK_EQ(16000000, result->Int32Value());
12961
ager@chromium.org3811b432009-10-28 14:53:37 +000012962 result = CompileRun("ext_array[3] = 33;"
12963 "delete ext_array[3];"
12964 "ext_array[3];");
12965 CHECK_EQ(33, result->Int32Value());
12966
12967 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
12968 "ext_array[2] = 12; ext_array[3] = 13;"
12969 "ext_array.__defineGetter__('2',"
12970 "function() { return 120; });"
12971 "ext_array[2];");
12972 CHECK_EQ(12, result->Int32Value());
12973
12974 result = CompileRun("var js_array = new Array(40);"
12975 "js_array[0] = 77;"
12976 "js_array;");
12977 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
12978
12979 result = CompileRun("ext_array[1] = 23;"
12980 "ext_array.__proto__ = [];"
12981 "js_array.__proto__ = ext_array;"
12982 "js_array.concat(ext_array);");
12983 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
12984 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
12985
12986 result = CompileRun("ext_array[1] = 23;");
12987 CHECK_EQ(23, result->Int32Value());
12988
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012989 // Test more complex manipulations which cause eax to contain values
12990 // that won't be completely overwritten by loads from the arrays.
12991 // This catches bugs in the instructions used for the KeyedLoadIC
12992 // for byte and word types.
12993 {
12994 const int kXSize = 300;
12995 const int kYSize = 300;
12996 const int kLargeElementCount = kXSize * kYSize * 4;
12997 ElementType* large_array_data =
12998 static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012999 i::Handle<ExternalArrayClass> large_array(
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013000 i::Handle<ExternalArrayClass>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013001 FACTORY->NewExternalArray(kLargeElementCount,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000013002 array_type,
13003 array_data)));
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013004 v8::Handle<v8::Object> large_obj = v8::Object::New();
13005 // Set the elements to be the external array.
13006 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
13007 array_type,
13008 kLargeElementCount);
13009 context->Global()->Set(v8_str("large_array"), large_obj);
13010 // Initialize contents of a few rows.
13011 for (int x = 0; x < 300; x++) {
13012 int row = 0;
13013 int offset = row * 300 * 4;
13014 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
13015 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
13016 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
13017 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
13018 row = 150;
13019 offset = row * 300 * 4;
13020 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
13021 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
13022 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
13023 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
13024 row = 298;
13025 offset = row * 300 * 4;
13026 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
13027 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
13028 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
13029 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
13030 }
13031 // The goal of the code below is to make "offset" large enough
13032 // that the computation of the index (which goes into eax) has
13033 // high bits set which will not be overwritten by a byte or short
13034 // load.
13035 result = CompileRun("var failed = false;"
13036 "var offset = 0;"
13037 "for (var i = 0; i < 300; i++) {"
13038 " if (large_array[4 * i] != 127 ||"
13039 " large_array[4 * i + 1] != 0 ||"
13040 " large_array[4 * i + 2] != 0 ||"
13041 " large_array[4 * i + 3] != 127) {"
13042 " failed = true;"
13043 " }"
13044 "}"
13045 "offset = 150 * 300 * 4;"
13046 "for (var i = 0; i < 300; i++) {"
13047 " if (large_array[offset + 4 * i] != 127 ||"
13048 " large_array[offset + 4 * i + 1] != 0 ||"
13049 " large_array[offset + 4 * i + 2] != 0 ||"
13050 " large_array[offset + 4 * i + 3] != 127) {"
13051 " failed = true;"
13052 " }"
13053 "}"
13054 "offset = 298 * 300 * 4;"
13055 "for (var i = 0; i < 300; i++) {"
13056 " if (large_array[offset + 4 * i] != 127 ||"
13057 " large_array[offset + 4 * i + 1] != 0 ||"
13058 " large_array[offset + 4 * i + 2] != 0 ||"
13059 " large_array[offset + 4 * i + 3] != 127) {"
13060 " failed = true;"
13061 " }"
13062 "}"
13063 "!failed;");
13064 CHECK_EQ(true, result->BooleanValue());
13065 free(large_array_data);
13066 }
13067
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013068 // The "" property descriptor is overloaded to store information about
13069 // the external array. Ensure that setting and accessing the "" property
13070 // works (it should overwrite the information cached about the external
13071 // array in the DescriptorArray) in various situations.
13072 result = CompileRun("ext_array[''] = 23; ext_array['']");
13073 CHECK_EQ(23, result->Int32Value());
13074
13075 // Property "" set after the external array is associated with the object.
13076 {
13077 v8::Handle<v8::Object> obj2 = v8::Object::New();
13078 obj2->Set(v8_str("ee_test_field"), v8::Int32::New(256));
13079 obj2->Set(v8_str(""), v8::Int32::New(1503));
13080 // Set the elements to be the external array.
13081 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
13082 array_type,
13083 kElementCount);
13084 context->Global()->Set(v8_str("ext_array"), obj2);
13085 result = CompileRun("ext_array['']");
13086 CHECK_EQ(1503, result->Int32Value());
13087 }
13088
13089 // Property "" set after the external array is associated with the object.
13090 {
13091 v8::Handle<v8::Object> obj2 = v8::Object::New();
13092 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
13093 // Set the elements to be the external array.
13094 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
13095 array_type,
13096 kElementCount);
13097 obj2->Set(v8_str(""), v8::Int32::New(1503));
13098 context->Global()->Set(v8_str("ext_array"), obj2);
13099 result = CompileRun("ext_array['']");
13100 CHECK_EQ(1503, result->Int32Value());
13101 }
13102
13103 // Should reuse the map from previous test.
13104 {
13105 v8::Handle<v8::Object> obj2 = v8::Object::New();
13106 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
13107 // Set the elements to be the external array. Should re-use the map
13108 // from previous test.
13109 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
13110 array_type,
13111 kElementCount);
13112 context->Global()->Set(v8_str("ext_array"), obj2);
13113 result = CompileRun("ext_array['']");
13114 }
13115
13116 // Property "" is a constant function that shouldn't not be interfered with
13117 // when an external array is set.
13118 {
13119 v8::Handle<v8::Object> obj2 = v8::Object::New();
13120 // Start
13121 obj2->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
13122
13123 // Add a constant function to an object.
13124 context->Global()->Set(v8_str("ext_array"), obj2);
13125 result = CompileRun("ext_array[''] = function() {return 1503;};"
13126 "ext_array['']();");
13127
13128 // Add an external array transition to the same map that
13129 // has the constant transition.
13130 v8::Handle<v8::Object> obj3 = v8::Object::New();
13131 obj3->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
13132 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
13133 array_type,
13134 kElementCount);
13135 context->Global()->Set(v8_str("ext_array"), obj3);
13136 }
13137
13138 // If a external array transition is in the map, it should get clobbered
13139 // by a constant function.
13140 {
13141 // Add an external array transition.
13142 v8::Handle<v8::Object> obj3 = v8::Object::New();
13143 obj3->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
13144 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
13145 array_type,
13146 kElementCount);
13147
13148 // Add a constant function to the same map that just got an external array
13149 // transition.
13150 v8::Handle<v8::Object> obj2 = v8::Object::New();
13151 obj2->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
13152 context->Global()->Set(v8_str("ext_array"), obj2);
13153 result = CompileRun("ext_array[''] = function() {return 1503;};"
13154 "ext_array['']();");
13155 }
13156
ager@chromium.org3811b432009-10-28 14:53:37 +000013157 free(array_data);
13158}
13159
13160
13161THREADED_TEST(ExternalByteArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000013162 ExternalArrayTestHelper<i::ExternalByteArray, int8_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000013163 v8::kExternalByteArray,
13164 -128,
13165 127);
13166}
13167
13168
13169THREADED_TEST(ExternalUnsignedByteArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000013170 ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000013171 v8::kExternalUnsignedByteArray,
13172 0,
13173 255);
13174}
13175
13176
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000013177THREADED_TEST(ExternalPixelArray) {
13178 ExternalArrayTestHelper<i::ExternalPixelArray, uint8_t>(
13179 v8::kExternalPixelArray,
13180 0,
13181 255);
13182}
13183
13184
ager@chromium.org3811b432009-10-28 14:53:37 +000013185THREADED_TEST(ExternalShortArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000013186 ExternalArrayTestHelper<i::ExternalShortArray, int16_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000013187 v8::kExternalShortArray,
13188 -32768,
13189 32767);
13190}
13191
13192
13193THREADED_TEST(ExternalUnsignedShortArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000013194 ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000013195 v8::kExternalUnsignedShortArray,
13196 0,
13197 65535);
13198}
13199
13200
13201THREADED_TEST(ExternalIntArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000013202 ExternalArrayTestHelper<i::ExternalIntArray, int32_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000013203 v8::kExternalIntArray,
13204 INT_MIN, // -2147483648
13205 INT_MAX); // 2147483647
13206}
13207
13208
13209THREADED_TEST(ExternalUnsignedIntArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000013210 ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000013211 v8::kExternalUnsignedIntArray,
13212 0,
13213 UINT_MAX); // 4294967295
13214}
13215
13216
13217THREADED_TEST(ExternalFloatArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000013218 ExternalArrayTestHelper<i::ExternalFloatArray, float>(
ager@chromium.org3811b432009-10-28 14:53:37 +000013219 v8::kExternalFloatArray,
13220 -500,
13221 500);
13222}
13223
13224
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000013225THREADED_TEST(ExternalDoubleArray) {
13226 ExternalArrayTestHelper<i::ExternalDoubleArray, double>(
13227 v8::kExternalDoubleArray,
13228 -500,
13229 500);
13230}
13231
13232
ager@chromium.org3811b432009-10-28 14:53:37 +000013233THREADED_TEST(ExternalArrays) {
13234 TestExternalByteArray();
13235 TestExternalUnsignedByteArray();
13236 TestExternalShortArray();
13237 TestExternalUnsignedShortArray();
13238 TestExternalIntArray();
13239 TestExternalUnsignedIntArray();
13240 TestExternalFloatArray();
13241}
13242
13243
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000013244void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
13245 v8::HandleScope scope;
13246 LocalContext context;
13247 for (int size = 0; size < 100; size += 10) {
13248 int element_size = ExternalArrayElementSize(array_type);
13249 void* external_data = malloc(size * element_size);
13250 v8::Handle<v8::Object> obj = v8::Object::New();
13251 obj->SetIndexedPropertiesToExternalArrayData(
13252 external_data, array_type, size);
13253 CHECK(obj->HasIndexedPropertiesInExternalArrayData());
13254 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
13255 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
13256 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
13257 free(external_data);
13258 }
13259}
13260
13261
13262THREADED_TEST(ExternalArrayInfo) {
13263 ExternalArrayInfoTestHelper(v8::kExternalByteArray);
13264 ExternalArrayInfoTestHelper(v8::kExternalUnsignedByteArray);
13265 ExternalArrayInfoTestHelper(v8::kExternalShortArray);
13266 ExternalArrayInfoTestHelper(v8::kExternalUnsignedShortArray);
13267 ExternalArrayInfoTestHelper(v8::kExternalIntArray);
13268 ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray);
13269 ExternalArrayInfoTestHelper(v8::kExternalFloatArray);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000013270 ExternalArrayInfoTestHelper(v8::kExternalDoubleArray);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000013271 ExternalArrayInfoTestHelper(v8::kExternalPixelArray);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000013272}
13273
13274
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000013275THREADED_TEST(ScriptContextDependence) {
13276 v8::HandleScope scope;
13277 LocalContext c1;
13278 const char *source = "foo";
13279 v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
13280 v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
13281 c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
13282 CHECK_EQ(dep->Run()->Int32Value(), 100);
13283 CHECK_EQ(indep->Run()->Int32Value(), 100);
13284 LocalContext c2;
13285 c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
13286 CHECK_EQ(dep->Run()->Int32Value(), 100);
13287 CHECK_EQ(indep->Run()->Int32Value(), 101);
13288}
13289
ager@chromium.org96c75b52009-08-26 09:13:16 +000013290
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000013291THREADED_TEST(StackTrace) {
13292 v8::HandleScope scope;
13293 LocalContext context;
13294 v8::TryCatch try_catch;
13295 const char *source = "function foo() { FAIL.FAIL; }; foo();";
13296 v8::Handle<v8::String> src = v8::String::New(source);
13297 v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
13298 v8::Script::New(src, origin)->Run();
13299 CHECK(try_catch.HasCaught());
13300 v8::String::Utf8Value stack(try_catch.StackTrace());
13301 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
13302}
ager@chromium.org96c75b52009-08-26 09:13:16 +000013303
13304
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013305// Checks that a StackFrame has certain expected values.
13306void checkStackFrame(const char* expected_script_name,
13307 const char* expected_func_name, int expected_line_number,
13308 int expected_column, bool is_eval, bool is_constructor,
13309 v8::Handle<v8::StackFrame> frame) {
13310 v8::HandleScope scope;
13311 v8::String::Utf8Value func_name(frame->GetFunctionName());
13312 v8::String::Utf8Value script_name(frame->GetScriptName());
13313 if (*script_name == NULL) {
13314 // The situation where there is no associated script, like for evals.
13315 CHECK(expected_script_name == NULL);
13316 } else {
13317 CHECK(strstr(*script_name, expected_script_name) != NULL);
13318 }
13319 CHECK(strstr(*func_name, expected_func_name) != NULL);
13320 CHECK_EQ(expected_line_number, frame->GetLineNumber());
13321 CHECK_EQ(expected_column, frame->GetColumn());
13322 CHECK_EQ(is_eval, frame->IsEval());
13323 CHECK_EQ(is_constructor, frame->IsConstructor());
13324}
13325
13326
13327v8::Handle<Value> AnalyzeStackInNativeCode(const v8::Arguments& args) {
13328 v8::HandleScope scope;
13329 const char* origin = "capture-stack-trace-test";
13330 const int kOverviewTest = 1;
13331 const int kDetailedTest = 2;
13332
13333 ASSERT(args.Length() == 1);
13334
13335 int testGroup = args[0]->Int32Value();
13336 if (testGroup == kOverviewTest) {
13337 v8::Handle<v8::StackTrace> stackTrace =
13338 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
13339 CHECK_EQ(4, stackTrace->GetFrameCount());
13340 checkStackFrame(origin, "bar", 2, 10, false, false,
13341 stackTrace->GetFrame(0));
13342 checkStackFrame(origin, "foo", 6, 3, false, false,
13343 stackTrace->GetFrame(1));
whesse@chromium.org030d38e2011-07-13 13:23:34 +000013344 // This is the source string inside the eval which has the call to foo.
13345 checkStackFrame(NULL, "", 1, 5, false, false,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013346 stackTrace->GetFrame(2));
whesse@chromium.org030d38e2011-07-13 13:23:34 +000013347 // The last frame is an anonymous function which has the initial eval call.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013348 checkStackFrame(origin, "", 8, 7, false, false,
13349 stackTrace->GetFrame(3));
13350
13351 CHECK(stackTrace->AsArray()->IsArray());
13352 } else if (testGroup == kDetailedTest) {
13353 v8::Handle<v8::StackTrace> stackTrace =
13354 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
13355 CHECK_EQ(4, stackTrace->GetFrameCount());
13356 checkStackFrame(origin, "bat", 4, 22, false, false,
13357 stackTrace->GetFrame(0));
13358 checkStackFrame(origin, "baz", 8, 3, false, true,
13359 stackTrace->GetFrame(1));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000013360#ifdef ENABLE_DEBUGGER_SUPPORT
13361 bool is_eval = true;
13362#else // ENABLE_DEBUGGER_SUPPORT
13363 bool is_eval = false;
13364#endif // ENABLE_DEBUGGER_SUPPORT
13365
whesse@chromium.org030d38e2011-07-13 13:23:34 +000013366 // This is the source string inside the eval which has the call to baz.
13367 checkStackFrame(NULL, "", 1, 5, is_eval, false,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013368 stackTrace->GetFrame(2));
whesse@chromium.org030d38e2011-07-13 13:23:34 +000013369 // The last frame is an anonymous function which has the initial eval call.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013370 checkStackFrame(origin, "", 10, 1, false, false,
13371 stackTrace->GetFrame(3));
13372
13373 CHECK(stackTrace->AsArray()->IsArray());
13374 }
13375 return v8::Undefined();
13376}
13377
13378
13379// Tests the C++ StackTrace API.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013380// TODO(3074796): Reenable this as a THREADED_TEST once it passes.
13381// THREADED_TEST(CaptureStackTrace) {
13382TEST(CaptureStackTrace) {
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013383 v8::HandleScope scope;
13384 v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
13385 Local<ObjectTemplate> templ = ObjectTemplate::New();
13386 templ->Set(v8_str("AnalyzeStackInNativeCode"),
13387 v8::FunctionTemplate::New(AnalyzeStackInNativeCode));
13388 LocalContext context(0, templ);
13389
13390 // Test getting OVERVIEW information. Should ignore information that is not
13391 // script name, function name, line number, and column offset.
13392 const char *overview_source =
13393 "function bar() {\n"
13394 " var y; AnalyzeStackInNativeCode(1);\n"
13395 "}\n"
13396 "function foo() {\n"
13397 "\n"
13398 " bar();\n"
13399 "}\n"
13400 "var x;eval('new foo();');";
13401 v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000013402 v8::Handle<Value> overview_result(
13403 v8::Script::New(overview_src, origin)->Run());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013404 ASSERT(!overview_result.IsEmpty());
13405 ASSERT(overview_result->IsObject());
13406
13407 // Test getting DETAILED information.
13408 const char *detailed_source =
13409 "function bat() {AnalyzeStackInNativeCode(2);\n"
13410 "}\n"
13411 "\n"
13412 "function baz() {\n"
13413 " bat();\n"
13414 "}\n"
13415 "eval('new baz();');";
13416 v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
13417 // Make the script using a non-zero line and column offset.
13418 v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
13419 v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
13420 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
13421 v8::Handle<v8::Script> detailed_script(
13422 v8::Script::New(detailed_src, &detailed_origin));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000013423 v8::Handle<Value> detailed_result(detailed_script->Run());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013424 ASSERT(!detailed_result.IsEmpty());
13425 ASSERT(detailed_result->IsObject());
13426}
13427
13428
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000013429static void StackTraceForUncaughtExceptionListener(
13430 v8::Handle<v8::Message> message,
13431 v8::Handle<Value>) {
13432 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
13433 CHECK_EQ(2, stack_trace->GetFrameCount());
13434 checkStackFrame("origin", "foo", 2, 3, false, false,
13435 stack_trace->GetFrame(0));
13436 checkStackFrame("origin", "bar", 5, 3, false, false,
13437 stack_trace->GetFrame(1));
13438}
13439
13440TEST(CaptureStackTraceForUncaughtException) {
13441 report_count = 0;
13442 v8::HandleScope scope;
13443 LocalContext env;
13444 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
13445 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
13446
13447 Script::Compile(v8_str("function foo() {\n"
13448 " throw 1;\n"
13449 "};\n"
13450 "function bar() {\n"
13451 " foo();\n"
13452 "};"),
13453 v8_str("origin"))->Run();
13454 v8::Local<v8::Object> global = env->Global();
13455 Local<Value> trouble = global->Get(v8_str("bar"));
13456 CHECK(trouble->IsFunction());
13457 Function::Cast(*trouble)->Call(global, 0, NULL);
13458 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
13459 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
13460}
13461
13462
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000013463TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
13464 v8::HandleScope scope;
13465 LocalContext env;
13466 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
13467 1024,
13468 v8::StackTrace::kDetailed);
13469
13470 CompileRun(
13471 "var setters = ['column', 'lineNumber', 'scriptName',\n"
13472 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
13473 " 'isConstructor'];\n"
13474 "for (var i = 0; i < setters.length; i++) {\n"
13475 " var prop = setters[i];\n"
13476 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
13477 "}\n");
13478 CompileRun("throw 'exception';");
13479 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
13480}
13481
13482
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000013483v8::Handle<Value> AnalyzeStackOfEvalWithSourceURL(const v8::Arguments& args) {
13484 v8::HandleScope scope;
13485 v8::Handle<v8::StackTrace> stackTrace =
13486 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
13487 CHECK_EQ(5, stackTrace->GetFrameCount());
13488 v8::Handle<v8::String> url = v8_str("eval_url");
13489 for (int i = 0; i < 3; i++) {
13490 v8::Handle<v8::String> name =
13491 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
13492 CHECK(!name.IsEmpty());
13493 CHECK_EQ(url, name);
13494 }
13495 return v8::Undefined();
13496}
13497
13498
13499TEST(SourceURLInStackTrace) {
13500 v8::HandleScope scope;
13501 Local<ObjectTemplate> templ = ObjectTemplate::New();
13502 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
13503 v8::FunctionTemplate::New(AnalyzeStackOfEvalWithSourceURL));
13504 LocalContext context(0, templ);
13505
13506 const char *source =
13507 "function outer() {\n"
13508 "function bar() {\n"
13509 " AnalyzeStackOfEvalWithSourceURL();\n"
13510 "}\n"
13511 "function foo() {\n"
13512 "\n"
13513 " bar();\n"
13514 "}\n"
13515 "foo();\n"
13516 "}\n"
13517 "eval('(' + outer +')()//@ sourceURL=eval_url');";
13518 CHECK(CompileRun(source)->IsUndefined());
13519}
13520
13521
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000013522// Test that idle notification can be handled and eventually returns true.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000013523// This just checks the contract of the IdleNotification() function,
13524// and does not verify that it does reasonable work.
ager@chromium.org96c75b52009-08-26 09:13:16 +000013525THREADED_TEST(IdleNotification) {
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +000013526 v8::HandleScope scope;
13527 LocalContext env;
13528 CompileRun("function binom(n, m) {"
13529 " var C = [[1]];"
13530 " for (var i = 1; i <= n; ++i) {"
13531 " C[i] = [1];"
13532 " for (var j = 1; j < i; ++j) {"
13533 " C[i][j] = C[i-1][j-1] + C[i-1][j];"
13534 " }"
13535 " C[i][i] = 1;"
13536 " }"
13537 " return C[n][m];"
13538 "};"
13539 "binom(1000, 500)");
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000013540 bool rv = false;
13541 for (int i = 0; i < 100; i++) {
13542 rv = v8::V8::IdleNotification();
13543 if (rv)
13544 break;
13545 }
13546 CHECK(rv == true);
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +000013547}
13548
13549// Test that idle notification can be handled and eventually returns true.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000013550// This just checks the contract of the IdleNotification() function,
13551// and does not verify that it does reasonable work.
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +000013552THREADED_TEST(IdleNotificationWithHint) {
13553 v8::HandleScope scope;
13554 LocalContext env;
13555 CompileRun("function binom(n, m) {"
13556 " var C = [[1]];"
13557 " for (var i = 1; i <= n; ++i) {"
13558 " C[i] = [1];"
13559 " for (var j = 1; j < i; ++j) {"
13560 " C[i][j] = C[i-1][j-1] + C[i-1][j];"
13561 " }"
13562 " C[i][i] = 1;"
13563 " }"
13564 " return C[n][m];"
13565 "};"
13566 "binom(1000, 500)");
13567 bool rv = false;
13568 intptr_t old_size = HEAP->SizeOfObjects();
13569 bool no_idle_work = v8::V8::IdleNotification(10);
13570 for (int i = 0; i < 200; i++) {
13571 rv = v8::V8::IdleNotification(10);
13572 if (rv)
13573 break;
13574 }
13575 CHECK(rv == true);
13576 intptr_t new_size = HEAP->SizeOfObjects();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000013577 CHECK(no_idle_work || new_size < old_size);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000013578}
13579
13580
13581static uint32_t* stack_limit;
13582
13583static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013584 stack_limit = reinterpret_cast<uint32_t*>(
13585 i::Isolate::Current()->stack_guard()->real_climit());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000013586 return v8::Undefined();
13587}
13588
13589
13590// Uses the address of a local variable to determine the stack top now.
13591// Given a size, returns an address that is that far from the current
13592// top of stack.
13593static uint32_t* ComputeStackLimit(uint32_t size) {
13594 uint32_t* answer = &size - (size / sizeof(size));
13595 // If the size is very large and the stack is very near the bottom of
13596 // memory then the calculation above may wrap around and give an address
13597 // that is above the (downwards-growing) stack. In that case we return
13598 // a very low address.
13599 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
13600 return answer;
13601}
13602
13603
13604TEST(SetResourceConstraints) {
13605 static const int K = 1024;
13606 uint32_t* set_limit = ComputeStackLimit(128 * K);
13607
13608 // Set stack limit.
13609 v8::ResourceConstraints constraints;
13610 constraints.set_stack_limit(set_limit);
13611 CHECK(v8::SetResourceConstraints(&constraints));
13612
13613 // Execute a script.
13614 v8::HandleScope scope;
13615 LocalContext env;
13616 Local<v8::FunctionTemplate> fun_templ =
13617 v8::FunctionTemplate::New(GetStackLimitCallback);
13618 Local<Function> fun = fun_templ->GetFunction();
13619 env->Global()->Set(v8_str("get_stack_limit"), fun);
13620 CompileRun("get_stack_limit();");
13621
13622 CHECK(stack_limit == set_limit);
13623}
13624
13625
13626TEST(SetResourceConstraintsInThread) {
13627 uint32_t* set_limit;
13628 {
13629 v8::Locker locker;
13630 static const int K = 1024;
13631 set_limit = ComputeStackLimit(128 * K);
13632
13633 // Set stack limit.
13634 v8::ResourceConstraints constraints;
13635 constraints.set_stack_limit(set_limit);
13636 CHECK(v8::SetResourceConstraints(&constraints));
13637
13638 // Execute a script.
13639 v8::HandleScope scope;
13640 LocalContext env;
13641 Local<v8::FunctionTemplate> fun_templ =
13642 v8::FunctionTemplate::New(GetStackLimitCallback);
13643 Local<Function> fun = fun_templ->GetFunction();
13644 env->Global()->Set(v8_str("get_stack_limit"), fun);
13645 CompileRun("get_stack_limit();");
13646
13647 CHECK(stack_limit == set_limit);
13648 }
13649 {
13650 v8::Locker locker;
13651 CHECK(stack_limit == set_limit);
13652 }
ager@chromium.org96c75b52009-08-26 09:13:16 +000013653}
ager@chromium.org3811b432009-10-28 14:53:37 +000013654
13655
13656THREADED_TEST(GetHeapStatistics) {
13657 v8::HandleScope scope;
13658 LocalContext c1;
13659 v8::HeapStatistics heap_statistics;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000013660 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
13661 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
ager@chromium.org3811b432009-10-28 14:53:37 +000013662 v8::V8::GetHeapStatistics(&heap_statistics);
ager@chromium.orgc4c92722009-11-18 14:12:51 +000013663 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
13664 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
ager@chromium.org3811b432009-10-28 14:53:37 +000013665}
13666
13667
13668static double DoubleFromBits(uint64_t value) {
13669 double target;
ager@chromium.org3811b432009-10-28 14:53:37 +000013670 memcpy(&target, &value, sizeof(target));
ager@chromium.org3811b432009-10-28 14:53:37 +000013671 return target;
13672}
13673
13674
13675static uint64_t DoubleToBits(double value) {
13676 uint64_t target;
ager@chromium.org3811b432009-10-28 14:53:37 +000013677 memcpy(&target, &value, sizeof(target));
ager@chromium.org3811b432009-10-28 14:53:37 +000013678 return target;
13679}
13680
13681
13682static double DoubleToDateTime(double input) {
13683 double date_limit = 864e13;
13684 if (IsNaN(input) || input < -date_limit || input > date_limit) {
13685 return i::OS::nan_value();
13686 }
13687 return (input < 0) ? -(floor(-input)) : floor(input);
13688}
13689
13690// We don't have a consistent way to write 64-bit constants syntactically, so we
13691// split them into two 32-bit constants and combine them programmatically.
13692static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
13693 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
13694}
13695
13696
13697THREADED_TEST(QuietSignalingNaNs) {
13698 v8::HandleScope scope;
13699 LocalContext context;
13700 v8::TryCatch try_catch;
13701
13702 // Special double values.
13703 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
13704 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
13705 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
13706 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
13707 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
13708 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
13709 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
13710
13711 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
13712 // on either side of the epoch.
13713 double date_limit = 864e13;
13714
13715 double test_values[] = {
13716 snan,
13717 qnan,
13718 infinity,
13719 max_normal,
13720 date_limit + 1,
13721 date_limit,
13722 min_normal,
13723 max_denormal,
13724 min_denormal,
13725 0,
13726 -0,
13727 -min_denormal,
13728 -max_denormal,
13729 -min_normal,
13730 -date_limit,
13731 -date_limit - 1,
13732 -max_normal,
13733 -infinity,
13734 -qnan,
13735 -snan
13736 };
13737 int num_test_values = 20;
13738
13739 for (int i = 0; i < num_test_values; i++) {
13740 double test_value = test_values[i];
13741
13742 // Check that Number::New preserves non-NaNs and quiets SNaNs.
13743 v8::Handle<v8::Value> number = v8::Number::New(test_value);
13744 double stored_number = number->NumberValue();
13745 if (!IsNaN(test_value)) {
13746 CHECK_EQ(test_value, stored_number);
13747 } else {
13748 uint64_t stored_bits = DoubleToBits(stored_number);
13749 // Check if quiet nan (bits 51..62 all set).
danno@chromium.orgc612e022011-11-10 11:38:15 +000013750#if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
13751 // Most significant fraction bit for quiet nan is set to 0
13752 // on MIPS architecture. Allowed by IEEE-754.
13753 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
13754#else
ager@chromium.org3811b432009-10-28 14:53:37 +000013755 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
danno@chromium.orgc612e022011-11-10 11:38:15 +000013756#endif
ager@chromium.org3811b432009-10-28 14:53:37 +000013757 }
13758
13759 // Check that Date::New preserves non-NaNs in the date range and
13760 // quiets SNaNs.
13761 v8::Handle<v8::Value> date = v8::Date::New(test_value);
13762 double expected_stored_date = DoubleToDateTime(test_value);
13763 double stored_date = date->NumberValue();
13764 if (!IsNaN(expected_stored_date)) {
13765 CHECK_EQ(expected_stored_date, stored_date);
13766 } else {
13767 uint64_t stored_bits = DoubleToBits(stored_date);
13768 // Check if quiet nan (bits 51..62 all set).
danno@chromium.orgc612e022011-11-10 11:38:15 +000013769#if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
13770 // Most significant fraction bit for quiet nan is set to 0
13771 // on MIPS architecture. Allowed by IEEE-754.
13772 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
13773#else
ager@chromium.org3811b432009-10-28 14:53:37 +000013774 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
danno@chromium.orgc612e022011-11-10 11:38:15 +000013775#endif
ager@chromium.org3811b432009-10-28 14:53:37 +000013776 }
13777 }
13778}
christian.plesner.hansen@gmail.comb9ce6372009-11-03 11:38:18 +000013779
13780
13781static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
13782 v8::HandleScope scope;
13783 v8::TryCatch tc;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000013784 v8::Handle<v8::String> str(args[0]->ToString());
christian.plesner.hansen@gmail.comb9ce6372009-11-03 11:38:18 +000013785 if (tc.HasCaught())
13786 return tc.ReThrow();
13787 return v8::Undefined();
13788}
13789
13790
13791// Test that an exception can be propagated down through a spaghetti
13792// stack using ReThrow.
13793THREADED_TEST(SpaghettiStackReThrow) {
13794 v8::HandleScope scope;
13795 LocalContext context;
13796 context->Global()->Set(
13797 v8::String::New("s"),
13798 v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
13799 v8::TryCatch try_catch;
13800 CompileRun(
13801 "var i = 0;"
13802 "var o = {"
13803 " toString: function () {"
13804 " if (i == 10) {"
13805 " throw 'Hey!';"
13806 " } else {"
13807 " i++;"
13808 " return s(o);"
13809 " }"
13810 " }"
13811 "};"
13812 "s(o);");
13813 CHECK(try_catch.HasCaught());
13814 v8::String::Utf8Value value(try_catch.Exception());
13815 CHECK_EQ(0, strcmp(*value, "Hey!"));
13816}
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013817
13818
sgjesse@chromium.org98180592009-12-02 08:17:28 +000013819TEST(Regress528) {
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013820 v8::V8::Initialize();
13821
13822 v8::HandleScope scope;
13823 v8::Persistent<Context> context;
ager@chromium.org60121232009-12-03 11:25:37 +000013824 v8::Persistent<Context> other_context;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013825 int gc_count;
13826
ager@chromium.org60121232009-12-03 11:25:37 +000013827 // Create a context used to keep the code from aging in the compilation
13828 // cache.
13829 other_context = Context::New();
13830
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013831 // Context-dependent context data creates reference from the compilation
13832 // cache to the global object.
ager@chromium.org60121232009-12-03 11:25:37 +000013833 const char* source_simple = "1";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013834 context = Context::New();
13835 {
13836 v8::HandleScope scope;
13837
13838 context->Enter();
13839 Local<v8::String> obj = v8::String::New("");
13840 context->SetData(obj);
ager@chromium.org60121232009-12-03 11:25:37 +000013841 CompileRun(source_simple);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013842 context->Exit();
13843 }
13844 context.Dispose();
13845 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000013846 other_context->Enter();
13847 CompileRun(source_simple);
13848 other_context->Exit();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013849 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org60121232009-12-03 11:25:37 +000013850 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013851 }
ager@chromium.org60121232009-12-03 11:25:37 +000013852 CHECK_GE(2, gc_count);
13853 CHECK_EQ(1, GetGlobalObjectsCount());
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013854
13855 // Eval in a function creates reference from the compilation cache to the
13856 // global object.
ager@chromium.org60121232009-12-03 11:25:37 +000013857 const char* source_eval = "function f(){eval('1')}; f()";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013858 context = Context::New();
13859 {
13860 v8::HandleScope scope;
13861
13862 context->Enter();
ager@chromium.org60121232009-12-03 11:25:37 +000013863 CompileRun(source_eval);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013864 context->Exit();
13865 }
13866 context.Dispose();
13867 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000013868 other_context->Enter();
13869 CompileRun(source_eval);
13870 other_context->Exit();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013871 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org60121232009-12-03 11:25:37 +000013872 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013873 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013874 CHECK_GE(2, gc_count);
sgjesse@chromium.org98180592009-12-02 08:17:28 +000013875 CHECK_EQ(1, GetGlobalObjectsCount());
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013876
13877 // Looking up the line number for an exception creates reference from the
13878 // compilation cache to the global object.
ager@chromium.org60121232009-12-03 11:25:37 +000013879 const char* source_exception = "function f(){throw 1;} f()";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013880 context = Context::New();
13881 {
13882 v8::HandleScope scope;
13883
13884 context->Enter();
13885 v8::TryCatch try_catch;
ager@chromium.org60121232009-12-03 11:25:37 +000013886 CompileRun(source_exception);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013887 CHECK(try_catch.HasCaught());
13888 v8::Handle<v8::Message> message = try_catch.Message();
13889 CHECK(!message.IsEmpty());
13890 CHECK_EQ(1, message->GetLineNumber());
13891 context->Exit();
13892 }
13893 context.Dispose();
13894 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000013895 other_context->Enter();
13896 CompileRun(source_exception);
13897 other_context->Exit();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013898 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org60121232009-12-03 11:25:37 +000013899 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013900 }
ager@chromium.org60121232009-12-03 11:25:37 +000013901 CHECK_GE(2, gc_count);
13902 CHECK_EQ(1, GetGlobalObjectsCount());
13903
13904 other_context.Dispose();
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013905}
ager@chromium.org5c838252010-02-19 08:53:10 +000013906
13907
13908THREADED_TEST(ScriptOrigin) {
13909 v8::HandleScope scope;
13910 LocalContext env;
13911 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
13912 v8::Handle<v8::String> script = v8::String::New(
13913 "function f() {}\n\nfunction g() {}");
13914 v8::Script::Compile(script, &origin)->Run();
13915 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
13916 env->Global()->Get(v8::String::New("f")));
13917 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
13918 env->Global()->Get(v8::String::New("g")));
13919
13920 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
13921 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
13922 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
13923
13924 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
13925 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
13926 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
13927}
13928
13929
13930THREADED_TEST(ScriptLineNumber) {
13931 v8::HandleScope scope;
13932 LocalContext env;
13933 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
13934 v8::Handle<v8::String> script = v8::String::New(
13935 "function f() {}\n\nfunction g() {}");
13936 v8::Script::Compile(script, &origin)->Run();
13937 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
13938 env->Global()->Get(v8::String::New("f")));
13939 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
13940 env->Global()->Get(v8::String::New("g")));
13941 CHECK_EQ(0, f->GetScriptLineNumber());
13942 CHECK_EQ(2, g->GetScriptLineNumber());
13943}
13944
13945
danno@chromium.orgc612e022011-11-10 11:38:15 +000013946THREADED_TEST(ScriptColumnNumber) {
13947 v8::HandleScope scope;
13948 LocalContext env;
13949 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"),
13950 v8::Integer::New(3), v8::Integer::New(2));
13951 v8::Handle<v8::String> script = v8::String::New(
13952 "function foo() {}\n\n function bar() {}");
13953 v8::Script::Compile(script, &origin)->Run();
13954 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
13955 env->Global()->Get(v8::String::New("foo")));
13956 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
13957 env->Global()->Get(v8::String::New("bar")));
13958 CHECK_EQ(14, foo->GetScriptColumnNumber());
13959 CHECK_EQ(17, bar->GetScriptColumnNumber());
13960}
13961
13962
13963THREADED_TEST(FunctionGetScriptId) {
13964 v8::HandleScope scope;
13965 LocalContext env;
13966 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"),
13967 v8::Integer::New(3), v8::Integer::New(2));
13968 v8::Handle<v8::String> scriptSource = v8::String::New(
13969 "function foo() {}\n\n function bar() {}");
13970 v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
13971 script->Run();
13972 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
13973 env->Global()->Get(v8::String::New("foo")));
13974 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
13975 env->Global()->Get(v8::String::New("bar")));
13976 CHECK_EQ(script->Id(), foo->GetScriptId());
13977 CHECK_EQ(script->Id(), bar->GetScriptId());
13978}
13979
13980
ager@chromium.org5c838252010-02-19 08:53:10 +000013981static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
13982 const AccessorInfo& info) {
13983 return v8_num(42);
13984}
13985
13986
13987static void SetterWhichSetsYOnThisTo23(Local<String> name,
13988 Local<Value> value,
13989 const AccessorInfo& info) {
13990 info.This()->Set(v8_str("y"), v8_num(23));
13991}
13992
13993
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013994TEST(SetterOnConstructorPrototype) {
ager@chromium.org5c838252010-02-19 08:53:10 +000013995 v8::HandleScope scope;
13996 Local<ObjectTemplate> templ = ObjectTemplate::New();
13997 templ->SetAccessor(v8_str("x"),
13998 GetterWhichReturns42,
13999 SetterWhichSetsYOnThisTo23);
14000 LocalContext context;
14001 context->Global()->Set(v8_str("P"), templ->NewInstance());
14002 CompileRun("function C1() {"
14003 " this.x = 23;"
14004 "};"
14005 "C1.prototype = P;"
14006 "function C2() {"
14007 " this.x = 23"
14008 "};"
14009 "C2.prototype = { };"
14010 "C2.prototype.__proto__ = P;");
14011
14012 v8::Local<v8::Script> script;
14013 script = v8::Script::Compile(v8_str("new C1();"));
14014 for (int i = 0; i < 10; i++) {
14015 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
14016 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
14017 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
14018 }
14019
14020 script = v8::Script::Compile(v8_str("new C2();"));
14021 for (int i = 0; i < 10; i++) {
14022 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
14023 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
14024 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
14025 }
14026}
14027
14028
14029static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
14030 Local<String> name, const AccessorInfo& info) {
14031 return v8_num(42);
14032}
14033
14034
14035static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
14036 Local<String> name, Local<Value> value, const AccessorInfo& info) {
14037 if (name->Equals(v8_str("x"))) {
14038 info.This()->Set(v8_str("y"), v8_num(23));
14039 }
14040 return v8::Handle<Value>();
14041}
14042
14043
14044THREADED_TEST(InterceptorOnConstructorPrototype) {
14045 v8::HandleScope scope;
14046 Local<ObjectTemplate> templ = ObjectTemplate::New();
14047 templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
14048 NamedPropertySetterWhichSetsYOnThisTo23);
14049 LocalContext context;
14050 context->Global()->Set(v8_str("P"), templ->NewInstance());
14051 CompileRun("function C1() {"
14052 " this.x = 23;"
14053 "};"
14054 "C1.prototype = P;"
14055 "function C2() {"
14056 " this.x = 23"
14057 "};"
14058 "C2.prototype = { };"
14059 "C2.prototype.__proto__ = P;");
14060
14061 v8::Local<v8::Script> script;
14062 script = v8::Script::Compile(v8_str("new C1();"));
14063 for (int i = 0; i < 10; i++) {
14064 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
14065 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
14066 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
14067 }
14068
14069 script = v8::Script::Compile(v8_str("new C2();"));
14070 for (int i = 0; i < 10; i++) {
14071 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
14072 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
14073 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
14074 }
14075}
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000014076
14077
14078TEST(Bug618) {
14079 const char* source = "function C1() {"
14080 " this.x = 23;"
14081 "};"
14082 "C1.prototype = P;";
14083
14084 v8::HandleScope scope;
14085 LocalContext context;
14086 v8::Local<v8::Script> script;
14087
14088 // Use a simple object as prototype.
14089 v8::Local<v8::Object> prototype = v8::Object::New();
14090 prototype->Set(v8_str("y"), v8_num(42));
14091 context->Global()->Set(v8_str("P"), prototype);
14092
14093 // This compile will add the code to the compilation cache.
14094 CompileRun(source);
14095
14096 script = v8::Script::Compile(v8_str("new C1();"));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000014097 // Allow enough iterations for the inobject slack tracking logic
14098 // to finalize instance size and install the fast construct stub.
14099 for (int i = 0; i < 256; i++) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000014100 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
14101 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
14102 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
14103 }
14104
14105 // Use an API object with accessors as prototype.
14106 Local<ObjectTemplate> templ = ObjectTemplate::New();
14107 templ->SetAccessor(v8_str("x"),
14108 GetterWhichReturns42,
14109 SetterWhichSetsYOnThisTo23);
14110 context->Global()->Set(v8_str("P"), templ->NewInstance());
14111
14112 // This compile will get the code from the compilation cache.
14113 CompileRun(source);
14114
14115 script = v8::Script::Compile(v8_str("new C1();"));
14116 for (int i = 0; i < 10; i++) {
14117 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
14118 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
14119 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
14120 }
14121}
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000014122
14123int prologue_call_count = 0;
14124int epilogue_call_count = 0;
14125int prologue_call_count_second = 0;
14126int epilogue_call_count_second = 0;
14127
14128void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
14129 ++prologue_call_count;
14130}
14131
14132void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
14133 ++epilogue_call_count;
14134}
14135
14136void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
14137 ++prologue_call_count_second;
14138}
14139
14140void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
14141 ++epilogue_call_count_second;
14142}
14143
14144TEST(GCCallbacks) {
14145 LocalContext context;
14146
14147 v8::V8::AddGCPrologueCallback(PrologueCallback);
14148 v8::V8::AddGCEpilogueCallback(EpilogueCallback);
14149 CHECK_EQ(0, prologue_call_count);
14150 CHECK_EQ(0, epilogue_call_count);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000014151 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000014152 CHECK_EQ(1, prologue_call_count);
14153 CHECK_EQ(1, epilogue_call_count);
14154 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
14155 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000014156 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000014157 CHECK_EQ(2, prologue_call_count);
14158 CHECK_EQ(2, epilogue_call_count);
14159 CHECK_EQ(1, prologue_call_count_second);
14160 CHECK_EQ(1, epilogue_call_count_second);
14161 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
14162 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000014163 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000014164 CHECK_EQ(2, prologue_call_count);
14165 CHECK_EQ(2, epilogue_call_count);
14166 CHECK_EQ(2, prologue_call_count_second);
14167 CHECK_EQ(2, epilogue_call_count_second);
14168 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
14169 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000014170 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000014171 CHECK_EQ(2, prologue_call_count);
14172 CHECK_EQ(2, epilogue_call_count);
14173 CHECK_EQ(2, prologue_call_count_second);
14174 CHECK_EQ(2, epilogue_call_count_second);
14175}
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014176
14177
14178THREADED_TEST(AddToJSFunctionResultCache) {
14179 i::FLAG_allow_natives_syntax = true;
14180 v8::HandleScope scope;
14181
14182 LocalContext context;
14183
14184 const char* code =
14185 "(function() {"
14186 " var key0 = 'a';"
14187 " var key1 = 'b';"
14188 " var r0 = %_GetFromCache(0, key0);"
14189 " var r1 = %_GetFromCache(0, key1);"
14190 " var r0_ = %_GetFromCache(0, key0);"
14191 " if (r0 !== r0_)"
14192 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
14193 " var r1_ = %_GetFromCache(0, key1);"
14194 " if (r1 !== r1_)"
14195 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
14196 " return 'PASSED';"
14197 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014198 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014199 ExpectString(code, "PASSED");
14200}
14201
14202
14203static const int k0CacheSize = 16;
14204
14205THREADED_TEST(FillJSFunctionResultCache) {
14206 i::FLAG_allow_natives_syntax = true;
14207 v8::HandleScope scope;
14208
14209 LocalContext context;
14210
14211 const char* code =
14212 "(function() {"
14213 " var k = 'a';"
14214 " var r = %_GetFromCache(0, k);"
14215 " for (var i = 0; i < 16; i++) {"
14216 " %_GetFromCache(0, 'a' + i);"
14217 " };"
14218 " if (r === %_GetFromCache(0, k))"
14219 " return 'FAILED: k0CacheSize is too small';"
14220 " return 'PASSED';"
14221 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014222 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014223 ExpectString(code, "PASSED");
14224}
14225
14226
14227THREADED_TEST(RoundRobinGetFromCache) {
14228 i::FLAG_allow_natives_syntax = true;
14229 v8::HandleScope scope;
14230
14231 LocalContext context;
14232
14233 const char* code =
14234 "(function() {"
14235 " var keys = [];"
14236 " for (var i = 0; i < 16; i++) keys.push(i);"
14237 " var values = [];"
14238 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
14239 " for (var i = 0; i < 16; i++) {"
14240 " var v = %_GetFromCache(0, keys[i]);"
14241 " if (v !== values[i])"
14242 " return 'Wrong value for ' + "
14243 " keys[i] + ': ' + v + ' vs. ' + values[i];"
14244 " };"
14245 " return 'PASSED';"
14246 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014247 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014248 ExpectString(code, "PASSED");
14249}
14250
14251
14252THREADED_TEST(ReverseGetFromCache) {
14253 i::FLAG_allow_natives_syntax = true;
14254 v8::HandleScope scope;
14255
14256 LocalContext context;
14257
14258 const char* code =
14259 "(function() {"
14260 " var keys = [];"
14261 " for (var i = 0; i < 16; i++) keys.push(i);"
14262 " var values = [];"
14263 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
14264 " for (var i = 15; i >= 16; i--) {"
14265 " var v = %_GetFromCache(0, keys[i]);"
14266 " if (v !== values[i])"
14267 " return 'Wrong value for ' + "
14268 " keys[i] + ': ' + v + ' vs. ' + values[i];"
14269 " };"
14270 " return 'PASSED';"
14271 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014272 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014273 ExpectString(code, "PASSED");
14274}
14275
14276
14277THREADED_TEST(TestEviction) {
14278 i::FLAG_allow_natives_syntax = true;
14279 v8::HandleScope scope;
14280
14281 LocalContext context;
14282
14283 const char* code =
14284 "(function() {"
14285 " for (var i = 0; i < 2*16; i++) {"
14286 " %_GetFromCache(0, 'a' + i);"
14287 " };"
14288 " return 'PASSED';"
14289 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014290 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014291 ExpectString(code, "PASSED");
14292}
lrn@chromium.org32d961d2010-06-30 09:09:34 +000014293
14294
14295THREADED_TEST(TwoByteStringInAsciiCons) {
14296 // See Chromium issue 47824.
14297 v8::HandleScope scope;
14298
14299 LocalContext context;
14300 const char* init_code =
14301 "var str1 = 'abelspendabel';"
14302 "var str2 = str1 + str1 + str1;"
14303 "str2;";
14304 Local<Value> result = CompileRun(init_code);
14305
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000014306 Local<Value> indexof = CompileRun("str2.indexOf('els')");
14307 Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
14308
lrn@chromium.org32d961d2010-06-30 09:09:34 +000014309 CHECK(result->IsString());
14310 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
14311 int length = string->length();
14312 CHECK(string->IsAsciiRepresentation());
14313
14314 FlattenString(string);
14315 i::Handle<i::String> flat_string = FlattenGetString(string);
14316
14317 CHECK(string->IsAsciiRepresentation());
14318 CHECK(flat_string->IsAsciiRepresentation());
14319
14320 // Create external resource.
14321 uint16_t* uc16_buffer = new uint16_t[length + 1];
14322
14323 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
14324 uc16_buffer[length] = 0;
14325
14326 TestResource resource(uc16_buffer);
14327
14328 flat_string->MakeExternal(&resource);
14329
14330 CHECK(flat_string->IsTwoByteRepresentation());
14331
14332 // At this point, we should have a Cons string which is flat and ASCII,
14333 // with a first half that is a two-byte string (although it only contains
14334 // ASCII characters). This is a valid sequence of steps, and it can happen
14335 // in real pages.
14336
14337 CHECK(string->IsAsciiRepresentation());
14338 i::ConsString* cons = i::ConsString::cast(*string);
14339 CHECK_EQ(0, cons->second()->length());
14340 CHECK(cons->first()->IsTwoByteRepresentation());
14341
14342 // Check that some string operations work.
14343
14344 // Atom RegExp.
14345 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
14346 CHECK_EQ(6, reresult->Int32Value());
14347
14348 // Nonatom RegExp.
14349 reresult = CompileRun("str2.match(/abe./g).length;");
14350 CHECK_EQ(6, reresult->Int32Value());
14351
14352 reresult = CompileRun("str2.search(/bel/g);");
14353 CHECK_EQ(1, reresult->Int32Value());
14354
14355 reresult = CompileRun("str2.search(/be./g);");
14356 CHECK_EQ(1, reresult->Int32Value());
14357
14358 ExpectTrue("/bel/g.test(str2);");
14359
14360 ExpectTrue("/be./g.test(str2);");
14361
14362 reresult = CompileRun("/bel/g.exec(str2);");
14363 CHECK(!reresult->IsNull());
14364
14365 reresult = CompileRun("/be./g.exec(str2);");
14366 CHECK(!reresult->IsNull());
14367
14368 ExpectString("str2.substring(2, 10);", "elspenda");
14369
14370 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
14371
14372 ExpectString("str2.charAt(2);", "e");
14373
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000014374 ExpectObject("str2.indexOf('els');", indexof);
14375
14376 ExpectObject("str2.lastIndexOf('dab');", lastindexof);
14377
lrn@chromium.org32d961d2010-06-30 09:09:34 +000014378 reresult = CompileRun("str2.charCodeAt(2);");
14379 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
14380}
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000014381
14382
14383// Failed access check callback that performs a GC on each invocation.
14384void FailedAccessCheckCallbackGC(Local<v8::Object> target,
14385 v8::AccessType type,
14386 Local<v8::Value> data) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000014387 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000014388}
14389
14390
14391TEST(GCInFailedAccessCheckCallback) {
14392 // Install a failed access check callback that performs a GC on each
14393 // invocation. Then force the callback to be called from va
14394
14395 v8::V8::Initialize();
14396 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
14397
14398 v8::HandleScope scope;
14399
14400 // Create an ObjectTemplate for global objects and install access
14401 // check callbacks that will block access.
14402 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
14403 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
14404 IndexedGetAccessBlocker,
14405 v8::Handle<v8::Value>(),
14406 false);
14407
14408 // Create a context and set an x property on it's global object.
14409 LocalContext context0(NULL, global_template);
14410 context0->Global()->Set(v8_str("x"), v8_num(42));
14411 v8::Handle<v8::Object> global0 = context0->Global();
14412
14413 // Create a context with a different security token so that the
14414 // failed access check callback will be called on each access.
14415 LocalContext context1(NULL, global_template);
14416 context1->Global()->Set(v8_str("other"), global0);
14417
14418 // Get property with failed access check.
14419 ExpectUndefined("other.x");
14420
14421 // Get element with failed access check.
14422 ExpectUndefined("other[0]");
14423
14424 // Set property with failed access check.
14425 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
14426 CHECK(result->IsObject());
14427
14428 // Set element with failed access check.
14429 result = CompileRun("other[0] = new Object()");
14430 CHECK(result->IsObject());
14431
14432 // Get property attribute with failed access check.
14433 ExpectFalse("\'x\' in other");
14434
14435 // Get property attribute for element with failed access check.
14436 ExpectFalse("0 in other");
14437
14438 // Delete property.
14439 ExpectFalse("delete other.x");
14440
14441 // Delete element.
14442 CHECK_EQ(false, global0->Delete(0));
14443
14444 // DefineAccessor.
14445 CHECK_EQ(false,
14446 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
14447
14448 // Define JavaScript accessor.
14449 ExpectUndefined("Object.prototype.__defineGetter__.call("
14450 " other, \'x\', function() { return 42; })");
14451
14452 // LookupAccessor.
14453 ExpectUndefined("Object.prototype.__lookupGetter__.call("
14454 " other, \'x\')");
14455
14456 // HasLocalElement.
14457 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
14458
14459 CHECK_EQ(false, global0->HasRealIndexedProperty(0));
14460 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
14461 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
14462
14463 // Reset the failed access check callback so it does not influence
14464 // the other tests.
14465 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
14466}
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000014467
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014468TEST(DefaultIsolateGetCurrent) {
14469 CHECK(v8::Isolate::GetCurrent() != NULL);
14470 v8::Isolate* isolate = v8::Isolate::GetCurrent();
14471 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
14472 printf("*** %s\n", "DefaultIsolateGetCurrent success");
14473}
14474
14475TEST(IsolateNewDispose) {
14476 v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
14477 v8::Isolate* isolate = v8::Isolate::New();
14478 CHECK(isolate != NULL);
14479 CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
14480 CHECK(current_isolate != isolate);
14481 CHECK(current_isolate == v8::Isolate::GetCurrent());
14482
14483 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14484 last_location = last_message = NULL;
14485 isolate->Dispose();
14486 CHECK_EQ(last_location, NULL);
14487 CHECK_EQ(last_message, NULL);
14488}
14489
14490TEST(IsolateEnterExitDefault) {
14491 v8::HandleScope scope;
14492 LocalContext context;
14493 v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
14494 CHECK(current_isolate != NULL); // Default isolate.
14495 ExpectString("'hello'", "hello");
14496 current_isolate->Enter();
14497 ExpectString("'still working'", "still working");
14498 current_isolate->Exit();
14499 ExpectString("'still working 2'", "still working 2");
14500 current_isolate->Exit();
14501 // Default isolate is always, well, 'default current'.
14502 CHECK_EQ(v8::Isolate::GetCurrent(), current_isolate);
14503 // Still working since default isolate is auto-entering any thread
14504 // that has no isolate and attempts to execute V8 APIs.
14505 ExpectString("'still working 3'", "still working 3");
14506}
14507
14508TEST(DisposeDefaultIsolate) {
14509 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14510
14511 // Run some V8 code to trigger default isolate to become 'current'.
14512 v8::HandleScope scope;
14513 LocalContext context;
14514 ExpectString("'run some V8'", "run some V8");
14515
14516 v8::Isolate* isolate = v8::Isolate::GetCurrent();
14517 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
14518 last_location = last_message = NULL;
14519 isolate->Dispose();
14520 // It is not possible to dispose default isolate via Isolate API.
14521 CHECK_NE(last_location, NULL);
14522 CHECK_NE(last_message, NULL);
14523}
14524
14525TEST(RunDefaultAndAnotherIsolate) {
14526 v8::HandleScope scope;
14527 LocalContext context;
14528
14529 // Enter new isolate.
14530 v8::Isolate* isolate = v8::Isolate::New();
14531 CHECK(isolate);
14532 isolate->Enter();
14533 { // Need this block because subsequent Exit() will deallocate Heap,
14534 // so we need all scope objects to be deconstructed when it happens.
14535 v8::HandleScope scope_new;
14536 LocalContext context_new;
14537
14538 // Run something in new isolate.
14539 CompileRun("var foo = 153;");
14540 ExpectTrue("function f() { return foo == 153; }; f()");
14541 }
14542 isolate->Exit();
14543
14544 // This runs automatically in default isolate.
14545 // Variables in another isolate should be not available.
14546 ExpectTrue("function f() {"
14547 " try {"
14548 " foo;"
14549 " return false;"
14550 " } catch(e) {"
14551 " return true;"
14552 " }"
14553 "};"
14554 "var bar = 371;"
14555 "f()");
14556
14557 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14558 last_location = last_message = NULL;
14559 isolate->Dispose();
14560 CHECK_EQ(last_location, NULL);
14561 CHECK_EQ(last_message, NULL);
14562
14563 // Check that default isolate still runs.
14564 ExpectTrue("function f() { return bar == 371; }; f()");
14565}
14566
14567TEST(DisposeIsolateWhenInUse) {
14568 v8::Isolate* isolate = v8::Isolate::New();
14569 CHECK(isolate);
14570 isolate->Enter();
14571 v8::HandleScope scope;
14572 LocalContext context;
14573 // Run something in this isolate.
14574 ExpectTrue("true");
14575 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14576 last_location = last_message = NULL;
14577 // Still entered, should fail.
14578 isolate->Dispose();
14579 CHECK_NE(last_location, NULL);
14580 CHECK_NE(last_message, NULL);
14581}
14582
14583TEST(RunTwoIsolatesOnSingleThread) {
14584 // Run isolate 1.
14585 v8::Isolate* isolate1 = v8::Isolate::New();
14586 isolate1->Enter();
14587 v8::Persistent<v8::Context> context1 = v8::Context::New();
14588
14589 {
14590 v8::Context::Scope cscope(context1);
14591 v8::HandleScope scope;
14592 // Run something in new isolate.
14593 CompileRun("var foo = 'isolate 1';");
14594 ExpectString("function f() { return foo; }; f()", "isolate 1");
14595 }
14596
14597 // Run isolate 2.
14598 v8::Isolate* isolate2 = v8::Isolate::New();
14599 v8::Persistent<v8::Context> context2;
14600
14601 {
14602 v8::Isolate::Scope iscope(isolate2);
14603 context2 = v8::Context::New();
14604 v8::Context::Scope cscope(context2);
14605 v8::HandleScope scope;
14606
14607 // Run something in new isolate.
14608 CompileRun("var foo = 'isolate 2';");
14609 ExpectString("function f() { return foo; }; f()", "isolate 2");
14610 }
14611
14612 {
14613 v8::Context::Scope cscope(context1);
14614 v8::HandleScope scope;
14615 // Now again in isolate 1
14616 ExpectString("function f() { return foo; }; f()", "isolate 1");
14617 }
14618
14619 isolate1->Exit();
14620
14621 // Run some stuff in default isolate.
14622 v8::Persistent<v8::Context> context_default = v8::Context::New();
14623
14624 {
14625 v8::Context::Scope cscope(context_default);
14626 v8::HandleScope scope;
14627 // Variables in other isolates should be not available, verify there
14628 // is an exception.
14629 ExpectTrue("function f() {"
14630 " try {"
14631 " foo;"
14632 " return false;"
14633 " } catch(e) {"
14634 " return true;"
14635 " }"
14636 "};"
14637 "var isDefaultIsolate = true;"
14638 "f()");
14639 }
14640
14641 isolate1->Enter();
14642
14643 {
14644 v8::Isolate::Scope iscope(isolate2);
14645 v8::Context::Scope cscope(context2);
14646 v8::HandleScope scope;
14647 ExpectString("function f() { return foo; }; f()", "isolate 2");
14648 }
14649
14650 {
14651 v8::Context::Scope cscope(context1);
14652 v8::HandleScope scope;
14653 ExpectString("function f() { return foo; }; f()", "isolate 1");
14654 }
14655
14656 {
14657 v8::Isolate::Scope iscope(isolate2);
14658 context2.Dispose();
14659 }
14660
14661 context1.Dispose();
14662 isolate1->Exit();
14663
14664 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14665 last_location = last_message = NULL;
14666
14667 isolate1->Dispose();
14668 CHECK_EQ(last_location, NULL);
14669 CHECK_EQ(last_message, NULL);
14670
14671 isolate2->Dispose();
14672 CHECK_EQ(last_location, NULL);
14673 CHECK_EQ(last_message, NULL);
14674
14675 // Check that default isolate still runs.
14676 {
14677 v8::Context::Scope cscope(context_default);
14678 v8::HandleScope scope;
14679 ExpectTrue("function f() { return isDefaultIsolate; }; f()");
14680 }
14681}
14682
14683static int CalcFibonacci(v8::Isolate* isolate, int limit) {
14684 v8::Isolate::Scope isolate_scope(isolate);
14685 v8::HandleScope scope;
14686 LocalContext context;
14687 i::ScopedVector<char> code(1024);
14688 i::OS::SNPrintF(code, "function fib(n) {"
14689 " if (n <= 2) return 1;"
14690 " return fib(n-1) + fib(n-2);"
14691 "}"
14692 "fib(%d)", limit);
14693 Local<Value> value = CompileRun(code.start());
14694 CHECK(value->IsNumber());
14695 return static_cast<int>(value->NumberValue());
14696}
14697
14698class IsolateThread : public v8::internal::Thread {
14699 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000014700 IsolateThread(v8::Isolate* isolate, int fib_limit)
14701 : Thread("IsolateThread"),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014702 isolate_(isolate),
14703 fib_limit_(fib_limit),
14704 result_(0) { }
14705
14706 void Run() {
14707 result_ = CalcFibonacci(isolate_, fib_limit_);
14708 }
14709
14710 int result() { return result_; }
14711
14712 private:
14713 v8::Isolate* isolate_;
14714 int fib_limit_;
14715 int result_;
14716};
14717
14718TEST(MultipleIsolatesOnIndividualThreads) {
14719 v8::Isolate* isolate1 = v8::Isolate::New();
14720 v8::Isolate* isolate2 = v8::Isolate::New();
14721
14722 IsolateThread thread1(isolate1, 21);
14723 IsolateThread thread2(isolate2, 12);
14724
14725 // Compute some fibonacci numbers on 3 threads in 3 isolates.
14726 thread1.Start();
14727 thread2.Start();
14728
14729 int result1 = CalcFibonacci(v8::Isolate::GetCurrent(), 21);
14730 int result2 = CalcFibonacci(v8::Isolate::GetCurrent(), 12);
14731
14732 thread1.Join();
14733 thread2.Join();
14734
14735 // Compare results. The actual fibonacci numbers for 12 and 21 are taken
14736 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
14737 CHECK_EQ(result1, 10946);
14738 CHECK_EQ(result2, 144);
14739 CHECK_EQ(result1, thread1.result());
14740 CHECK_EQ(result2, thread2.result());
14741
14742 isolate1->Dispose();
14743 isolate2->Dispose();
14744}
14745
lrn@chromium.org1c092762011-05-09 09:42:16 +000014746TEST(IsolateDifferentContexts) {
14747 v8::Isolate* isolate = v8::Isolate::New();
14748 Persistent<v8::Context> context;
14749 {
14750 v8::Isolate::Scope isolate_scope(isolate);
14751 v8::HandleScope handle_scope;
14752 context = v8::Context::New();
14753 v8::Context::Scope context_scope(context);
14754 Local<Value> v = CompileRun("2");
14755 CHECK(v->IsNumber());
14756 CHECK_EQ(2, static_cast<int>(v->NumberValue()));
14757 }
14758 {
14759 v8::Isolate::Scope isolate_scope(isolate);
14760 v8::HandleScope handle_scope;
14761 context = v8::Context::New();
14762 v8::Context::Scope context_scope(context);
14763 Local<Value> v = CompileRun("22");
14764 CHECK(v->IsNumber());
14765 CHECK_EQ(22, static_cast<int>(v->NumberValue()));
14766 }
14767}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014768
14769class InitDefaultIsolateThread : public v8::internal::Thread {
14770 public:
sgjesse@chromium.orge0599052011-03-25 07:34:35 +000014771 enum TestCase {
14772 IgnoreOOM,
14773 SetResourceConstraints,
14774 SetFatalHandler,
14775 SetCounterFunction,
14776 SetCreateHistogramFunction,
14777 SetAddHistogramSampleFunction
14778 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014779
14780 explicit InitDefaultIsolateThread(TestCase testCase)
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000014781 : Thread("InitDefaultIsolateThread"),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014782 testCase_(testCase),
14783 result_(false) { }
14784
14785 void Run() {
14786 switch (testCase_) {
14787 case IgnoreOOM:
14788 v8::V8::IgnoreOutOfMemoryException();
14789 break;
14790
14791 case SetResourceConstraints: {
14792 static const int K = 1024;
14793 v8::ResourceConstraints constraints;
14794 constraints.set_max_young_space_size(256 * K);
14795 constraints.set_max_old_space_size(4 * K * K);
14796 v8::SetResourceConstraints(&constraints);
14797 break;
14798 }
14799
14800 case SetFatalHandler:
14801 v8::V8::SetFatalErrorHandler(NULL);
14802 break;
sgjesse@chromium.orge0599052011-03-25 07:34:35 +000014803
14804 case SetCounterFunction:
14805 v8::V8::SetCounterFunction(NULL);
14806 break;
14807
14808 case SetCreateHistogramFunction:
14809 v8::V8::SetCreateHistogramFunction(NULL);
14810 break;
14811
14812 case SetAddHistogramSampleFunction:
14813 v8::V8::SetAddHistogramSampleFunction(NULL);
14814 break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014815 }
14816 result_ = true;
14817 }
14818
14819 bool result() { return result_; }
14820
14821 private:
14822 TestCase testCase_;
14823 bool result_;
14824};
14825
14826
14827static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
14828 InitDefaultIsolateThread thread(testCase);
14829 thread.Start();
14830 thread.Join();
14831 CHECK_EQ(thread.result(), true);
14832}
14833
14834TEST(InitializeDefaultIsolateOnSecondaryThread1) {
14835 InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM);
14836}
14837
14838TEST(InitializeDefaultIsolateOnSecondaryThread2) {
14839 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
14840}
14841
14842TEST(InitializeDefaultIsolateOnSecondaryThread3) {
14843 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
14844}
14845
sgjesse@chromium.orge0599052011-03-25 07:34:35 +000014846TEST(InitializeDefaultIsolateOnSecondaryThread4) {
14847 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
14848}
14849
14850TEST(InitializeDefaultIsolateOnSecondaryThread5) {
14851 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
14852}
14853
14854TEST(InitializeDefaultIsolateOnSecondaryThread6) {
14855 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
14856}
14857
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000014858
14859TEST(StringCheckMultipleContexts) {
14860 const char* code =
14861 "(function() { return \"a\".charAt(0); })()";
14862
14863 {
14864 // Run the code twice in the first context to initialize the call IC.
14865 v8::HandleScope scope;
14866 LocalContext context1;
14867 ExpectString(code, "a");
14868 ExpectString(code, "a");
14869 }
14870
14871 {
14872 // Change the String.prototype in the second context and check
14873 // that the right function gets called.
14874 v8::HandleScope scope;
14875 LocalContext context2;
14876 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
14877 ExpectString(code, "not a");
14878 }
14879}
14880
14881
14882TEST(NumberCheckMultipleContexts) {
14883 const char* code =
14884 "(function() { return (42).toString(); })()";
14885
14886 {
14887 // Run the code twice in the first context to initialize the call IC.
14888 v8::HandleScope scope;
14889 LocalContext context1;
14890 ExpectString(code, "42");
14891 ExpectString(code, "42");
14892 }
14893
14894 {
14895 // Change the Number.prototype in the second context and check
14896 // that the right function gets called.
14897 v8::HandleScope scope;
14898 LocalContext context2;
14899 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
14900 ExpectString(code, "not 42");
14901 }
14902}
14903
14904
14905TEST(BooleanCheckMultipleContexts) {
14906 const char* code =
14907 "(function() { return true.toString(); })()";
14908
14909 {
14910 // Run the code twice in the first context to initialize the call IC.
14911 v8::HandleScope scope;
14912 LocalContext context1;
14913 ExpectString(code, "true");
14914 ExpectString(code, "true");
14915 }
14916
14917 {
14918 // Change the Boolean.prototype in the second context and check
14919 // that the right function gets called.
14920 v8::HandleScope scope;
14921 LocalContext context2;
14922 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
14923 ExpectString(code, "");
14924 }
14925}
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000014926
14927
14928TEST(DontDeleteCellLoadIC) {
14929 const char* function_code =
14930 "function readCell() { while (true) { return cell; } }";
14931
14932 {
14933 // Run the code twice in the first context to initialize the load
14934 // IC for a don't delete cell.
14935 v8::HandleScope scope;
14936 LocalContext context1;
14937 CompileRun("var cell = \"first\";");
14938 ExpectBoolean("delete cell", false);
14939 CompileRun(function_code);
14940 ExpectString("readCell()", "first");
14941 ExpectString("readCell()", "first");
14942 }
14943
14944 {
14945 // Use a deletable cell in the second context.
14946 v8::HandleScope scope;
14947 LocalContext context2;
14948 CompileRun("cell = \"second\";");
14949 CompileRun(function_code);
14950 ExpectString("readCell()", "second");
14951 ExpectBoolean("delete cell", true);
14952 ExpectString("(function() {"
14953 " try {"
14954 " return readCell();"
14955 " } catch(e) {"
14956 " return e.toString();"
14957 " }"
14958 "})()",
14959 "ReferenceError: cell is not defined");
14960 CompileRun("cell = \"new_second\";");
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000014961 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000014962 ExpectString("readCell()", "new_second");
14963 ExpectString("readCell()", "new_second");
14964 }
14965}
14966
14967
14968TEST(DontDeleteCellLoadICForceDelete) {
14969 const char* function_code =
14970 "function readCell() { while (true) { return cell; } }";
14971
14972 // Run the code twice to initialize the load IC for a don't delete
14973 // cell.
14974 v8::HandleScope scope;
14975 LocalContext context;
14976 CompileRun("var cell = \"value\";");
14977 ExpectBoolean("delete cell", false);
14978 CompileRun(function_code);
14979 ExpectString("readCell()", "value");
14980 ExpectString("readCell()", "value");
14981
14982 // Delete the cell using the API and check the inlined code works
14983 // correctly.
14984 CHECK(context->Global()->ForceDelete(v8_str("cell")));
14985 ExpectString("(function() {"
14986 " try {"
14987 " return readCell();"
14988 " } catch(e) {"
14989 " return e.toString();"
14990 " }"
14991 "})()",
14992 "ReferenceError: cell is not defined");
14993}
14994
14995
14996TEST(DontDeleteCellLoadICAPI) {
14997 const char* function_code =
14998 "function readCell() { while (true) { return cell; } }";
14999
15000 // Run the code twice to initialize the load IC for a don't delete
15001 // cell created using the API.
15002 v8::HandleScope scope;
15003 LocalContext context;
15004 context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
15005 ExpectBoolean("delete cell", false);
15006 CompileRun(function_code);
15007 ExpectString("readCell()", "value");
15008 ExpectString("readCell()", "value");
15009
15010 // Delete the cell using the API and check the inlined code works
15011 // correctly.
15012 CHECK(context->Global()->ForceDelete(v8_str("cell")));
15013 ExpectString("(function() {"
15014 " try {"
15015 " return readCell();"
15016 " } catch(e) {"
15017 " return e.toString();"
15018 " }"
15019 "})()",
15020 "ReferenceError: cell is not defined");
15021}
15022
15023
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000015024TEST(RegExp) {
15025 v8::HandleScope scope;
15026 LocalContext context;
15027
15028 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
15029 CHECK(re->IsRegExp());
15030 CHECK(re->GetSource()->Equals(v8_str("foo")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000015031 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000015032
15033 re = v8::RegExp::New(v8_str("bar"),
15034 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
15035 v8::RegExp::kGlobal));
15036 CHECK(re->IsRegExp());
15037 CHECK(re->GetSource()->Equals(v8_str("bar")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000015038 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
15039 static_cast<int>(re->GetFlags()));
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000015040
15041 re = v8::RegExp::New(v8_str("baz"),
15042 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
15043 v8::RegExp::kMultiline));
15044 CHECK(re->IsRegExp());
15045 CHECK(re->GetSource()->Equals(v8_str("baz")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000015046 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
15047 static_cast<int>(re->GetFlags()));
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000015048
15049 re = CompileRun("/quux/").As<v8::RegExp>();
15050 CHECK(re->IsRegExp());
15051 CHECK(re->GetSource()->Equals(v8_str("quux")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000015052 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000015053
15054 re = CompileRun("/quux/gm").As<v8::RegExp>();
15055 CHECK(re->IsRegExp());
15056 CHECK(re->GetSource()->Equals(v8_str("quux")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000015057 CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
15058 static_cast<int>(re->GetFlags()));
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000015059
15060 // Override the RegExp constructor and check the API constructor
15061 // still works.
15062 CompileRun("RegExp = function() {}");
15063
15064 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
15065 CHECK(re->IsRegExp());
15066 CHECK(re->GetSource()->Equals(v8_str("foobar")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000015067 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000015068
15069 re = v8::RegExp::New(v8_str("foobarbaz"),
15070 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
15071 v8::RegExp::kMultiline));
15072 CHECK(re->IsRegExp());
15073 CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000015074 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
15075 static_cast<int>(re->GetFlags()));
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000015076
15077 context->Global()->Set(v8_str("re"), re);
15078 ExpectTrue("re.test('FoobarbaZ')");
15079
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000015080 // RegExps are objects on which you can set properties.
15081 re->Set(v8_str("property"), v8::Integer::New(32));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000015082 v8::Handle<v8::Value> value(CompileRun("re.property"));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000015083 ASSERT_EQ(32, value->Int32Value());
15084
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000015085 v8::TryCatch try_catch;
15086 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
15087 CHECK(re.IsEmpty());
15088 CHECK(try_catch.HasCaught());
15089 context->Global()->Set(v8_str("ex"), try_catch.Exception());
15090 ExpectTrue("ex instanceof SyntaxError");
15091}
15092
15093
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000015094THREADED_TEST(Equals) {
15095 v8::HandleScope handleScope;
15096 LocalContext localContext;
15097
15098 v8::Handle<v8::Object> globalProxy = localContext->Global();
15099 v8::Handle<Value> global = globalProxy->GetPrototype();
15100
15101 CHECK(global->StrictEquals(global));
15102 CHECK(!global->StrictEquals(globalProxy));
15103 CHECK(!globalProxy->StrictEquals(global));
15104 CHECK(globalProxy->StrictEquals(globalProxy));
15105
15106 CHECK(global->Equals(global));
15107 CHECK(!global->Equals(globalProxy));
15108 CHECK(!globalProxy->Equals(global));
15109 CHECK(globalProxy->Equals(globalProxy));
15110}
15111
15112
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000015113static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
15114 const v8::AccessorInfo& info ) {
15115 return v8_str("42!");
15116}
15117
15118
15119static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo& info) {
15120 v8::Handle<v8::Array> result = v8::Array::New();
15121 result->Set(0, v8_str("universalAnswer"));
15122 return result;
15123}
15124
15125
15126TEST(NamedEnumeratorAndForIn) {
15127 v8::HandleScope handle_scope;
15128 LocalContext context;
15129 v8::Context::Scope context_scope(context.local());
15130
15131 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New();
15132 tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
15133 context->Global()->Set(v8_str("o"), tmpl->NewInstance());
15134 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
15135 "var result = []; for (var k in o) result.push(k); result"));
15136 CHECK_EQ(1, result->Length());
15137 CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
15138}
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000015139
15140
15141TEST(DefinePropertyPostDetach) {
15142 v8::HandleScope scope;
15143 LocalContext context;
15144 v8::Handle<v8::Object> proxy = context->Global();
15145 v8::Handle<v8::Function> define_property =
15146 CompileRun("(function() {"
15147 " Object.defineProperty("
15148 " this,"
15149 " 1,"
15150 " { configurable: true, enumerable: true, value: 3 });"
15151 "})").As<Function>();
15152 context->DetachGlobal();
15153 define_property->Call(proxy, 0, NULL);
15154}
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000015155
15156
15157static void InstallContextId(v8::Handle<Context> context, int id) {
15158 Context::Scope scope(context);
15159 CompileRun("Object.prototype").As<Object>()->
15160 Set(v8_str("context_id"), v8::Integer::New(id));
15161}
15162
15163
15164static void CheckContextId(v8::Handle<Object> object, int expected) {
15165 CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
15166}
15167
15168
15169THREADED_TEST(CreationContext) {
15170 HandleScope handle_scope;
15171 Persistent<Context> context1 = Context::New();
15172 InstallContextId(context1, 1);
15173 Persistent<Context> context2 = Context::New();
15174 InstallContextId(context2, 2);
15175 Persistent<Context> context3 = Context::New();
15176 InstallContextId(context3, 3);
15177
15178 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New();
15179
15180 Local<Object> object1;
15181 Local<Function> func1;
15182 {
15183 Context::Scope scope(context1);
15184 object1 = Object::New();
15185 func1 = tmpl->GetFunction();
15186 }
15187
15188 Local<Object> object2;
15189 Local<Function> func2;
15190 {
15191 Context::Scope scope(context2);
15192 object2 = Object::New();
15193 func2 = tmpl->GetFunction();
15194 }
15195
15196 Local<Object> instance1;
15197 Local<Object> instance2;
15198
15199 {
15200 Context::Scope scope(context3);
15201 instance1 = func1->NewInstance();
15202 instance2 = func2->NewInstance();
15203 }
15204
15205 CHECK(object1->CreationContext() == context1);
15206 CheckContextId(object1, 1);
15207 CHECK(func1->CreationContext() == context1);
15208 CheckContextId(func1, 1);
15209 CHECK(instance1->CreationContext() == context1);
15210 CheckContextId(instance1, 1);
15211 CHECK(object2->CreationContext() == context2);
15212 CheckContextId(object2, 2);
15213 CHECK(func2->CreationContext() == context2);
15214 CheckContextId(func2, 2);
15215 CHECK(instance2->CreationContext() == context2);
15216 CheckContextId(instance2, 2);
15217
15218 {
15219 Context::Scope scope(context1);
15220 CHECK(object1->CreationContext() == context1);
15221 CheckContextId(object1, 1);
15222 CHECK(func1->CreationContext() == context1);
15223 CheckContextId(func1, 1);
15224 CHECK(instance1->CreationContext() == context1);
15225 CheckContextId(instance1, 1);
15226 CHECK(object2->CreationContext() == context2);
15227 CheckContextId(object2, 2);
15228 CHECK(func2->CreationContext() == context2);
15229 CheckContextId(func2, 2);
15230 CHECK(instance2->CreationContext() == context2);
15231 CheckContextId(instance2, 2);
15232 }
15233
15234 {
15235 Context::Scope scope(context2);
15236 CHECK(object1->CreationContext() == context1);
15237 CheckContextId(object1, 1);
15238 CHECK(func1->CreationContext() == context1);
15239 CheckContextId(func1, 1);
15240 CHECK(instance1->CreationContext() == context1);
15241 CheckContextId(instance1, 1);
15242 CHECK(object2->CreationContext() == context2);
15243 CheckContextId(object2, 2);
15244 CHECK(func2->CreationContext() == context2);
15245 CheckContextId(func2, 2);
15246 CHECK(instance2->CreationContext() == context2);
15247 CheckContextId(instance2, 2);
15248 }
15249
15250 context1.Dispose();
15251 context2.Dispose();
15252 context3.Dispose();
15253}
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +000015254
15255
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000015256THREADED_TEST(CreationContextOfJsFunction) {
15257 HandleScope handle_scope;
15258 Persistent<Context> context = Context::New();
15259 InstallContextId(context, 1);
15260
15261 Local<Object> function;
15262 {
15263 Context::Scope scope(context);
15264 function = CompileRun("function foo() {}; foo").As<Object>();
15265 }
15266
15267 CHECK(function->CreationContext() == context);
15268 CheckContextId(function, 1);
15269
15270 context.Dispose();
15271}
15272
15273
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +000015274Handle<Value> HasOwnPropertyIndexedPropertyGetter(uint32_t index,
15275 const AccessorInfo& info) {
15276 if (index == 42) return v8_str("yes");
15277 return Handle<v8::Integer>();
15278}
15279
15280
15281Handle<Value> HasOwnPropertyNamedPropertyGetter(Local<String> property,
15282 const AccessorInfo& info) {
15283 if (property->Equals(v8_str("foo"))) return v8_str("yes");
15284 return Handle<Value>();
15285}
15286
15287
15288Handle<v8::Integer> HasOwnPropertyIndexedPropertyQuery(
15289 uint32_t index, const AccessorInfo& info) {
15290 if (index == 42) return v8_num(1).As<v8::Integer>();
15291 return Handle<v8::Integer>();
15292}
15293
15294
15295Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery(
15296 Local<String> property, const AccessorInfo& info) {
15297 if (property->Equals(v8_str("foo"))) return v8_num(1).As<v8::Integer>();
15298 return Handle<v8::Integer>();
15299}
15300
15301
15302Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery2(
15303 Local<String> property, const AccessorInfo& info) {
15304 if (property->Equals(v8_str("bar"))) return v8_num(1).As<v8::Integer>();
15305 return Handle<v8::Integer>();
15306}
15307
15308
15309Handle<Value> HasOwnPropertyAccessorGetter(Local<String> property,
15310 const AccessorInfo& info) {
15311 return v8_str("yes");
15312}
15313
15314
15315TEST(HasOwnProperty) {
15316 v8::HandleScope scope;
15317 LocalContext env;
15318 { // Check normal properties and defined getters.
15319 Handle<Value> value = CompileRun(
15320 "function Foo() {"
15321 " this.foo = 11;"
15322 " this.__defineGetter__('baz', function() { return 1; });"
15323 "};"
15324 "function Bar() { "
15325 " this.bar = 13;"
15326 " this.__defineGetter__('bla', function() { return 2; });"
15327 "};"
15328 "Bar.prototype = new Foo();"
15329 "new Bar();");
15330 CHECK(value->IsObject());
15331 Handle<Object> object = value->ToObject();
15332 CHECK(object->Has(v8_str("foo")));
15333 CHECK(!object->HasOwnProperty(v8_str("foo")));
15334 CHECK(object->HasOwnProperty(v8_str("bar")));
15335 CHECK(object->Has(v8_str("baz")));
15336 CHECK(!object->HasOwnProperty(v8_str("baz")));
15337 CHECK(object->HasOwnProperty(v8_str("bla")));
15338 }
15339 { // Check named getter interceptors.
15340 Handle<ObjectTemplate> templ = ObjectTemplate::New();
15341 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
15342 Handle<Object> instance = templ->NewInstance();
15343 CHECK(!instance->HasOwnProperty(v8_str("42")));
15344 CHECK(instance->HasOwnProperty(v8_str("foo")));
15345 CHECK(!instance->HasOwnProperty(v8_str("bar")));
15346 }
15347 { // Check indexed getter interceptors.
15348 Handle<ObjectTemplate> templ = ObjectTemplate::New();
15349 templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
15350 Handle<Object> instance = templ->NewInstance();
15351 CHECK(instance->HasOwnProperty(v8_str("42")));
15352 CHECK(!instance->HasOwnProperty(v8_str("43")));
15353 CHECK(!instance->HasOwnProperty(v8_str("foo")));
15354 }
15355 { // Check named query interceptors.
15356 Handle<ObjectTemplate> templ = ObjectTemplate::New();
15357 templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
15358 Handle<Object> instance = templ->NewInstance();
15359 CHECK(instance->HasOwnProperty(v8_str("foo")));
15360 CHECK(!instance->HasOwnProperty(v8_str("bar")));
15361 }
15362 { // Check indexed query interceptors.
15363 Handle<ObjectTemplate> templ = ObjectTemplate::New();
15364 templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
15365 Handle<Object> instance = templ->NewInstance();
15366 CHECK(instance->HasOwnProperty(v8_str("42")));
15367 CHECK(!instance->HasOwnProperty(v8_str("41")));
15368 }
15369 { // Check callbacks.
15370 Handle<ObjectTemplate> templ = ObjectTemplate::New();
15371 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
15372 Handle<Object> instance = templ->NewInstance();
15373 CHECK(instance->HasOwnProperty(v8_str("foo")));
15374 CHECK(!instance->HasOwnProperty(v8_str("bar")));
15375 }
15376 { // Check that query wins on disagreement.
15377 Handle<ObjectTemplate> templ = ObjectTemplate::New();
15378 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
15379 0,
15380 HasOwnPropertyNamedPropertyQuery2);
15381 Handle<Object> instance = templ->NewInstance();
15382 CHECK(!instance->HasOwnProperty(v8_str("foo")));
15383 CHECK(instance->HasOwnProperty(v8_str("bar")));
15384 }
15385}
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000015386
15387
15388void CheckCodeGenerationAllowed() {
15389 Handle<Value> result = CompileRun("eval('42')");
15390 CHECK_EQ(42, result->Int32Value());
15391 result = CompileRun("(function(e) { return e('42'); })(eval)");
15392 CHECK_EQ(42, result->Int32Value());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000015393 result = CompileRun("var f = new Function('return 42'); f()");
15394 CHECK_EQ(42, result->Int32Value());
15395}
15396
15397
15398void CheckCodeGenerationDisallowed() {
15399 TryCatch try_catch;
15400
15401 Handle<Value> result = CompileRun("eval('42')");
15402 CHECK(result.IsEmpty());
15403 CHECK(try_catch.HasCaught());
15404 try_catch.Reset();
15405
15406 result = CompileRun("(function(e) { return e('42'); })(eval)");
15407 CHECK(result.IsEmpty());
15408 CHECK(try_catch.HasCaught());
15409 try_catch.Reset();
15410
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000015411 result = CompileRun("var f = new Function('return 42'); f()");
15412 CHECK(result.IsEmpty());
15413 CHECK(try_catch.HasCaught());
15414}
15415
15416
15417bool CodeGenerationAllowed(Local<Context> context) {
15418 ApiTestFuzzer::Fuzz();
15419 return true;
15420}
15421
15422
15423bool CodeGenerationDisallowed(Local<Context> context) {
15424 ApiTestFuzzer::Fuzz();
15425 return false;
15426}
15427
15428
15429THREADED_TEST(AllowCodeGenFromStrings) {
15430 v8::HandleScope scope;
15431 LocalContext context;
15432
ager@chromium.orgea91cc52011-05-23 06:06:11 +000015433 // eval and the Function constructor allowed by default.
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000015434 CheckCodeGenerationAllowed();
15435
ager@chromium.orgea91cc52011-05-23 06:06:11 +000015436 // Disallow eval and the Function constructor.
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000015437 context->AllowCodeGenerationFromStrings(false);
15438 CheckCodeGenerationDisallowed();
15439
15440 // Allow again.
15441 context->AllowCodeGenerationFromStrings(true);
15442 CheckCodeGenerationAllowed();
15443
15444 // Disallow but setting a global callback that will allow the calls.
15445 context->AllowCodeGenerationFromStrings(false);
15446 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
15447 CheckCodeGenerationAllowed();
15448
15449 // Set a callback that disallows the code generation.
15450 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
15451 CheckCodeGenerationDisallowed();
15452}
lrn@chromium.org1c092762011-05-09 09:42:16 +000015453
15454
15455static v8::Handle<Value> NonObjectThis(const v8::Arguments& args) {
15456 return v8::Undefined();
15457}
15458
15459
15460THREADED_TEST(CallAPIFunctionOnNonObject) {
15461 v8::HandleScope scope;
15462 LocalContext context;
15463 Handle<FunctionTemplate> templ = v8::FunctionTemplate::New(NonObjectThis);
15464 Handle<Function> function = templ->GetFunction();
15465 context->Global()->Set(v8_str("f"), function);
15466 TryCatch try_catch;
15467 CompileRun("f.call(2)");
lrn@chromium.org1c092762011-05-09 09:42:16 +000015468}
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000015469
15470
15471// Regression test for issue 1470.
15472THREADED_TEST(ReadOnlyIndexedProperties) {
15473 v8::HandleScope scope;
15474 Local<ObjectTemplate> templ = ObjectTemplate::New();
15475
15476 LocalContext context;
15477 Local<v8::Object> obj = templ->NewInstance();
15478 context->Global()->Set(v8_str("obj"), obj);
15479 obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
15480 obj->Set(v8_str("1"), v8_str("foobar"));
15481 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
15482 obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
15483 obj->Set(v8_num(2), v8_str("foobar"));
15484 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
15485
15486 // Test non-smi case.
15487 obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
15488 obj->Set(v8_str("2000000000"), v8_str("foobar"));
15489 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
15490}
ricow@chromium.org4f693d62011-07-04 14:01:31 +000015491
15492
15493THREADED_TEST(Regress1516) {
15494 v8::HandleScope scope;
15495
15496 LocalContext context;
15497 { v8::HandleScope temp_scope;
15498 CompileRun("({'a': 0})");
15499 }
15500
15501 int elements;
15502 { i::MapCache* map_cache =
15503 i::MapCache::cast(i::Isolate::Current()->context()->map_cache());
15504 elements = map_cache->NumberOfElements();
15505 CHECK_LE(1, elements);
15506 }
15507
15508 i::Isolate::Current()->heap()->CollectAllGarbage(true);
15509 { i::Object* raw_map_cache = i::Isolate::Current()->context()->map_cache();
15510 if (raw_map_cache != i::Isolate::Current()->heap()->undefined_value()) {
15511 i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
15512 CHECK_GT(elements, map_cache->NumberOfElements());
15513 }
15514 }
15515}
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000015516
15517
15518static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
15519 Local<Value> name,
15520 v8::AccessType type,
15521 Local<Value> data) {
15522 // Only block read access to __proto__.
15523 if (type == v8::ACCESS_GET &&
15524 name->IsString() &&
15525 name->ToString()->Length() == 9 &&
15526 name->ToString()->Utf8Length() == 9) {
15527 char buffer[10];
15528 CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
15529 return strncmp(buffer, "__proto__", 9) != 0;
15530 }
15531
15532 return true;
15533}
15534
15535
15536THREADED_TEST(Regress93759) {
15537 HandleScope scope;
15538
15539 // Template for object with security check.
15540 Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New();
15541 // We don't do indexing, so any callback can be used for that.
15542 no_proto_template->SetAccessCheckCallbacks(
15543 BlockProtoNamedSecurityTestCallback,
15544 IndexedSecurityTestCallback);
15545
15546 // Templates for objects with hidden prototypes and possibly security check.
15547 Local<FunctionTemplate> hidden_proto_template = v8::FunctionTemplate::New();
15548 hidden_proto_template->SetHiddenPrototype(true);
15549
15550 Local<FunctionTemplate> protected_hidden_proto_template =
15551 v8::FunctionTemplate::New();
15552 protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
15553 BlockProtoNamedSecurityTestCallback,
15554 IndexedSecurityTestCallback);
15555 protected_hidden_proto_template->SetHiddenPrototype(true);
15556
15557 // Context for "foreign" objects used in test.
15558 Persistent<Context> context = v8::Context::New();
15559 context->Enter();
15560
15561 // Plain object, no security check.
15562 Local<Object> simple_object = Object::New();
15563
15564 // Object with explicit security check.
15565 Local<Object> protected_object =
15566 no_proto_template->NewInstance();
15567
15568 // JSGlobalProxy object, always have security check.
15569 Local<Object> proxy_object =
15570 context->Global();
15571
15572 // Global object, the prototype of proxy_object. No security checks.
15573 Local<Object> global_object =
15574 proxy_object->GetPrototype()->ToObject();
15575
15576 // Hidden prototype without security check.
15577 Local<Object> hidden_prototype =
15578 hidden_proto_template->GetFunction()->NewInstance();
15579 Local<Object> object_with_hidden =
15580 Object::New();
15581 object_with_hidden->SetPrototype(hidden_prototype);
15582
15583 // Hidden prototype with security check on the hidden prototype.
15584 Local<Object> protected_hidden_prototype =
15585 protected_hidden_proto_template->GetFunction()->NewInstance();
15586 Local<Object> object_with_protected_hidden =
15587 Object::New();
15588 object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
15589
15590 context->Exit();
15591
15592 // Template for object for second context. Values to test are put on it as
15593 // properties.
15594 Local<ObjectTemplate> global_template = ObjectTemplate::New();
15595 global_template->Set(v8_str("simple"), simple_object);
15596 global_template->Set(v8_str("protected"), protected_object);
15597 global_template->Set(v8_str("global"), global_object);
15598 global_template->Set(v8_str("proxy"), proxy_object);
15599 global_template->Set(v8_str("hidden"), object_with_hidden);
15600 global_template->Set(v8_str("phidden"), object_with_protected_hidden);
15601
15602 LocalContext context2(NULL, global_template);
15603
15604 Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
15605 CHECK(result1->Equals(simple_object->GetPrototype()));
15606
15607 Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
15608 CHECK(result2->Equals(Undefined()));
15609
15610 Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
15611 CHECK(result3->Equals(global_object->GetPrototype()));
15612
15613 Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
15614 CHECK(result4->Equals(Undefined()));
15615
15616 Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
15617 CHECK(result5->Equals(
15618 object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
15619
15620 Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
15621 CHECK(result6->Equals(Undefined()));
15622
15623 context.Dispose();
15624}
15625
15626
15627static void TestReceiver(Local<Value> expected_result,
15628 Local<Value> expected_receiver,
15629 const char* code) {
15630 Local<Value> result = CompileRun(code);
15631 CHECK(result->IsObject());
15632 CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
15633 CHECK(expected_result->Equals(result->ToObject()->Get(0)));
15634}
15635
15636
15637THREADED_TEST(ForeignFunctionReceiver) {
15638 HandleScope scope;
15639
15640 // Create two contexts with different "id" properties ('i' and 'o').
15641 // Call a function both from its own context and from a the foreign
15642 // context, and see what "this" is bound to (returning both "this"
15643 // and "this.id" for comparison).
15644
15645 Persistent<Context> foreign_context = v8::Context::New();
15646 foreign_context->Enter();
15647 Local<Value> foreign_function =
15648 CompileRun("function func() { return { 0: this.id, "
15649 " 1: this, "
15650 " toString: function() { "
15651 " return this[0];"
15652 " }"
15653 " };"
15654 "}"
15655 "var id = 'i';"
15656 "func;");
15657 CHECK(foreign_function->IsFunction());
15658 foreign_context->Exit();
15659
15660 LocalContext context;
15661
15662 Local<String> password = v8_str("Password");
15663 // Don't get hit by security checks when accessing foreign_context's
15664 // global receiver (aka. global proxy).
15665 context->SetSecurityToken(password);
15666 foreign_context->SetSecurityToken(password);
15667
15668 Local<String> i = v8_str("i");
15669 Local<String> o = v8_str("o");
15670 Local<String> id = v8_str("id");
15671
15672 CompileRun("function ownfunc() { return { 0: this.id, "
15673 " 1: this, "
15674 " toString: function() { "
15675 " return this[0];"
15676 " }"
15677 " };"
15678 "}"
15679 "var id = 'o';"
15680 "ownfunc");
15681 context->Global()->Set(v8_str("func"), foreign_function);
15682
15683 // Sanity check the contexts.
15684 CHECK(i->Equals(foreign_context->Global()->Get(id)));
15685 CHECK(o->Equals(context->Global()->Get(id)));
15686
15687 // Checking local function's receiver.
15688 // Calling function using its call/apply methods.
15689 TestReceiver(o, context->Global(), "ownfunc.call()");
15690 TestReceiver(o, context->Global(), "ownfunc.apply()");
15691 // Making calls through built-in functions.
15692 TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
15693 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
15694 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
15695 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
15696 // Calling with environment record as base.
15697 TestReceiver(o, context->Global(), "ownfunc()");
15698 // Calling with no base.
15699 TestReceiver(o, context->Global(), "(1,ownfunc)()");
15700
15701 // Checking foreign function return value.
15702 // Calling function using its call/apply methods.
15703 TestReceiver(i, foreign_context->Global(), "func.call()");
15704 TestReceiver(i, foreign_context->Global(), "func.apply()");
15705 // Calling function using another context's call/apply methods.
15706 TestReceiver(i, foreign_context->Global(),
15707 "Function.prototype.call.call(func)");
15708 TestReceiver(i, foreign_context->Global(),
15709 "Function.prototype.call.apply(func)");
15710 TestReceiver(i, foreign_context->Global(),
15711 "Function.prototype.apply.call(func)");
15712 TestReceiver(i, foreign_context->Global(),
15713 "Function.prototype.apply.apply(func)");
15714 // Making calls through built-in functions.
15715 TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
15716 // ToString(func()) is func()[0], i.e., the returned this.id.
15717 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
15718 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
15719 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
15720
15721 // TODO(1547): Make the following also return "i".
15722 // Calling with environment record as base.
15723 TestReceiver(o, context->Global(), "func()");
15724 // Calling with no base.
15725 TestReceiver(o, context->Global(), "(1,func)()");
15726
15727 foreign_context.Dispose();
15728}