blob: 8b618d4906125d77c88361235bedac41405f0226 [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;
1426 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1427 Handle<FunctionTemplate> child = FunctionTemplate::New();
1428 child->Inherit(parent);
1429 AddAccessor(parent, v8_str("age"),
1430 SimpleAccessorGetter, SimpleAccessorSetter);
1431 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1432 LocalContext env;
1433 env->Global()->Set(v8_str("Child"), child->GetFunction());
1434 CompileRun("var child = new Child;"
1435 "function setAge(i){ child.age = i; };"
1436 "for(var i = 0; i <= 10000; i++) setAge(i);");
1437 // All i < 10000 go to the interceptor.
1438 ExpectInt32("child.interceptor_age", 9999);
1439 // The last i goes to the accessor.
1440 ExpectInt32("child.accessor_age", 10000);
1441}
1442
1443THREADED_TEST(SwitchFromAccessorToInterceptor) {
1444 v8::HandleScope scope;
1445 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1446 Handle<FunctionTemplate> child = FunctionTemplate::New();
1447 child->Inherit(parent);
1448 AddAccessor(parent, v8_str("age"),
1449 SimpleAccessorGetter, SimpleAccessorSetter);
1450 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1451 LocalContext env;
1452 env->Global()->Set(v8_str("Child"), child->GetFunction());
1453 CompileRun("var child = new Child;"
1454 "function setAge(i){ child.age = i; };"
1455 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1456 // All i >= 10000 go to the accessor.
1457 ExpectInt32("child.accessor_age", 10000);
1458 // The last i goes to the interceptor.
1459 ExpectInt32("child.interceptor_age", 9999);
1460}
1461
1462THREADED_TEST(SwitchFromInterceptorToProperty) {
1463 v8::HandleScope scope;
1464 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1465 Handle<FunctionTemplate> child = FunctionTemplate::New();
1466 child->Inherit(parent);
1467 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1468 LocalContext env;
1469 env->Global()->Set(v8_str("Child"), child->GetFunction());
1470 CompileRun("var child = new Child;"
1471 "function setAge(i){ child.age = i; };"
1472 "for(var i = 0; i <= 10000; i++) setAge(i);");
1473 // All i < 10000 go to the interceptor.
1474 ExpectInt32("child.interceptor_age", 9999);
1475 // The last i goes to child's own property.
1476 ExpectInt32("child.age", 10000);
1477}
1478
1479THREADED_TEST(SwitchFromPropertyToInterceptor) {
1480 v8::HandleScope scope;
1481 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1482 Handle<FunctionTemplate> child = FunctionTemplate::New();
1483 child->Inherit(parent);
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 child's own property.
1491 ExpectInt32("child.age", 10000);
1492 // The last i goes to the interceptor.
1493 ExpectInt32("child.interceptor_age", 9999);
1494}
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001495
1496THREADED_TEST(NamedPropertyHandlerGetter) {
1497 echo_named_call_count = 0;
1498 v8::HandleScope scope;
1499 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1500 templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
1501 0, 0, 0, 0,
1502 v8_str("data"));
1503 LocalContext env;
1504 env->Global()->Set(v8_str("obj"),
1505 templ->GetFunction()->NewInstance());
1506 CHECK_EQ(echo_named_call_count, 0);
1507 v8_compile("obj.x")->Run();
1508 CHECK_EQ(echo_named_call_count, 1);
1509 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
1510 v8::Handle<Value> str = CompileRun(code);
1511 String::AsciiValue value(str);
1512 CHECK_EQ(*value, "oddlepoddle");
1513 // Check default behavior
1514 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
1515 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
1516 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
1517}
1518
1519
1520int echo_indexed_call_count = 0;
1521
1522
1523static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
1524 const AccessorInfo& info) {
1525 ApiTestFuzzer::Fuzz();
1526 CHECK_EQ(v8_num(637), info.Data());
1527 echo_indexed_call_count++;
1528 return v8_num(index);
1529}
1530
1531
1532THREADED_TEST(IndexedPropertyHandlerGetter) {
1533 v8::HandleScope scope;
1534 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1535 templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
1536 0, 0, 0, 0,
1537 v8_num(637));
1538 LocalContext env;
1539 env->Global()->Set(v8_str("obj"),
1540 templ->GetFunction()->NewInstance());
1541 Local<Script> script = v8_compile("obj[900]");
1542 CHECK_EQ(script->Run()->Int32Value(), 900);
1543}
1544
1545
1546v8::Handle<v8::Object> bottom;
1547
1548static v8::Handle<Value> CheckThisIndexedPropertyHandler(
1549 uint32_t index,
1550 const AccessorInfo& info) {
1551 ApiTestFuzzer::Fuzz();
1552 CHECK(info.This()->Equals(bottom));
1553 return v8::Handle<Value>();
1554}
1555
1556static v8::Handle<Value> CheckThisNamedPropertyHandler(
1557 Local<String> name,
1558 const AccessorInfo& info) {
1559 ApiTestFuzzer::Fuzz();
1560 CHECK(info.This()->Equals(bottom));
1561 return v8::Handle<Value>();
1562}
1563
1564
1565v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
1566 Local<Value> value,
1567 const AccessorInfo& info) {
1568 ApiTestFuzzer::Fuzz();
1569 CHECK(info.This()->Equals(bottom));
1570 return v8::Handle<Value>();
1571}
1572
1573
1574v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
1575 Local<Value> value,
1576 const AccessorInfo& info) {
1577 ApiTestFuzzer::Fuzz();
1578 CHECK(info.This()->Equals(bottom));
1579 return v8::Handle<Value>();
1580}
1581
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001582v8::Handle<v8::Integer> CheckThisIndexedPropertyQuery(
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001583 uint32_t index,
1584 const AccessorInfo& info) {
1585 ApiTestFuzzer::Fuzz();
1586 CHECK(info.This()->Equals(bottom));
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001587 return v8::Handle<v8::Integer>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001588}
1589
1590
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001591v8::Handle<v8::Integer> CheckThisNamedPropertyQuery(Local<String> property,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001592 const AccessorInfo& info) {
1593 ApiTestFuzzer::Fuzz();
1594 CHECK(info.This()->Equals(bottom));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001595 return v8::Handle<v8::Integer>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001596}
1597
1598
1599v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
1600 uint32_t index,
1601 const AccessorInfo& info) {
1602 ApiTestFuzzer::Fuzz();
1603 CHECK(info.This()->Equals(bottom));
1604 return v8::Handle<v8::Boolean>();
1605}
1606
1607
1608v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
1609 Local<String> property,
1610 const AccessorInfo& info) {
1611 ApiTestFuzzer::Fuzz();
1612 CHECK(info.This()->Equals(bottom));
1613 return v8::Handle<v8::Boolean>();
1614}
1615
1616
1617v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
1618 const AccessorInfo& info) {
1619 ApiTestFuzzer::Fuzz();
1620 CHECK(info.This()->Equals(bottom));
1621 return v8::Handle<v8::Array>();
1622}
1623
1624
1625v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
1626 const AccessorInfo& info) {
1627 ApiTestFuzzer::Fuzz();
1628 CHECK(info.This()->Equals(bottom));
1629 return v8::Handle<v8::Array>();
1630}
1631
1632
1633THREADED_TEST(PropertyHandlerInPrototype) {
1634 v8::HandleScope scope;
1635 LocalContext env;
1636
1637 // Set up a prototype chain with three interceptors.
1638 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1639 templ->InstanceTemplate()->SetIndexedPropertyHandler(
1640 CheckThisIndexedPropertyHandler,
1641 CheckThisIndexedPropertySetter,
1642 CheckThisIndexedPropertyQuery,
1643 CheckThisIndexedPropertyDeleter,
1644 CheckThisIndexedPropertyEnumerator);
1645
1646 templ->InstanceTemplate()->SetNamedPropertyHandler(
1647 CheckThisNamedPropertyHandler,
1648 CheckThisNamedPropertySetter,
1649 CheckThisNamedPropertyQuery,
1650 CheckThisNamedPropertyDeleter,
1651 CheckThisNamedPropertyEnumerator);
1652
1653 bottom = templ->GetFunction()->NewInstance();
1654 Local<v8::Object> top = templ->GetFunction()->NewInstance();
1655 Local<v8::Object> middle = templ->GetFunction()->NewInstance();
1656
1657 bottom->Set(v8_str("__proto__"), middle);
1658 middle->Set(v8_str("__proto__"), top);
1659 env->Global()->Set(v8_str("obj"), bottom);
1660
1661 // Indexed and named get.
1662 Script::Compile(v8_str("obj[0]"))->Run();
1663 Script::Compile(v8_str("obj.x"))->Run();
1664
1665 // Indexed and named set.
1666 Script::Compile(v8_str("obj[1] = 42"))->Run();
1667 Script::Compile(v8_str("obj.y = 42"))->Run();
1668
1669 // Indexed and named query.
1670 Script::Compile(v8_str("0 in obj"))->Run();
1671 Script::Compile(v8_str("'x' in obj"))->Run();
1672
1673 // Indexed and named deleter.
1674 Script::Compile(v8_str("delete obj[0]"))->Run();
1675 Script::Compile(v8_str("delete obj.x"))->Run();
1676
1677 // Enumerators.
1678 Script::Compile(v8_str("for (var p in obj) ;"))->Run();
1679}
1680
1681
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001682static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
1683 const AccessorInfo& info) {
1684 ApiTestFuzzer::Fuzz();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001685 if (v8_str("pre")->Equals(key)) {
1686 return v8_str("PrePropertyHandler: pre");
1687 }
1688 return v8::Handle<String>();
1689}
1690
1691
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001692static v8::Handle<v8::Integer> PrePropertyHandlerQuery(Local<String> key,
1693 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001694 if (v8_str("pre")->Equals(key)) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001695 return v8::Integer::New(v8::None);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001696 }
1697
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001698 return v8::Handle<v8::Integer>(); // do not intercept the call
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001699}
1700
1701
1702THREADED_TEST(PrePropertyHandler) {
1703 v8::HandleScope scope;
1704 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
1705 desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
1706 0,
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001707 PrePropertyHandlerQuery);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001708 LocalContext env(NULL, desc->InstanceTemplate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001709 Script::Compile(v8_str(
1710 "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
1711 v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
1712 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
1713 v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
1714 CHECK_EQ(v8_str("Object: on"), result_on);
1715 v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
1716 CHECK(result_post.IsEmpty());
1717}
1718
1719
ager@chromium.org870a0b62008-11-04 11:43:05 +00001720THREADED_TEST(UndefinedIsNotEnumerable) {
1721 v8::HandleScope scope;
1722 LocalContext env;
1723 v8::Handle<Value> result = Script::Compile(v8_str(
1724 "this.propertyIsEnumerable(undefined)"))->Run();
1725 CHECK(result->IsFalse());
1726}
1727
1728
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001729v8::Handle<Script> call_recursively_script;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001730static const int kTargetRecursionDepth = 200; // near maximum
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001731
1732
1733static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
1734 ApiTestFuzzer::Fuzz();
1735 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1736 if (depth == kTargetRecursionDepth) return v8::Undefined();
1737 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1738 return call_recursively_script->Run();
1739}
1740
1741
1742static v8::Handle<Value> CallFunctionRecursivelyCall(
1743 const v8::Arguments& args) {
1744 ApiTestFuzzer::Fuzz();
1745 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1746 if (depth == kTargetRecursionDepth) {
1747 printf("[depth = %d]\n", depth);
1748 return v8::Undefined();
1749 }
1750 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1751 v8::Handle<Value> function =
1752 args.This()->Get(v8_str("callFunctionRecursively"));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001753 return function.As<Function>()->Call(args.This(), 0, NULL);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001754}
1755
1756
1757THREADED_TEST(DeepCrossLanguageRecursion) {
1758 v8::HandleScope scope;
1759 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
1760 global->Set(v8_str("callScriptRecursively"),
1761 v8::FunctionTemplate::New(CallScriptRecursivelyCall));
1762 global->Set(v8_str("callFunctionRecursively"),
1763 v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
1764 LocalContext env(NULL, global);
1765
1766 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1767 call_recursively_script = v8_compile("callScriptRecursively()");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001768 v8::Handle<Value> result(call_recursively_script->Run());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001769 call_recursively_script = v8::Handle<Script>();
1770
1771 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1772 Script::Compile(v8_str("callFunctionRecursively()"))->Run();
1773}
1774
1775
1776static v8::Handle<Value>
1777 ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1778 ApiTestFuzzer::Fuzz();
1779 return v8::ThrowException(key);
1780}
1781
1782
1783static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
1784 Local<Value>,
1785 const AccessorInfo&) {
1786 v8::ThrowException(key);
1787 return v8::Undefined(); // not the same as v8::Handle<v8::Value>()
1788}
1789
1790
1791THREADED_TEST(CallbackExceptionRegression) {
1792 v8::HandleScope scope;
1793 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1794 obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
1795 ThrowingPropertyHandlerSet);
1796 LocalContext env;
1797 env->Global()->Set(v8_str("obj"), obj->NewInstance());
1798 v8::Handle<Value> otto = Script::Compile(v8_str(
1799 "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
1800 CHECK_EQ(v8_str("otto"), otto);
1801 v8::Handle<Value> netto = Script::Compile(v8_str(
1802 "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
1803 CHECK_EQ(v8_str("netto"), netto);
1804}
1805
1806
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001807THREADED_TEST(FunctionPrototype) {
1808 v8::HandleScope scope;
1809 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
1810 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
1811 LocalContext env;
1812 env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
1813 Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
1814 CHECK_EQ(script->Run()->Int32Value(), 321);
1815}
1816
1817
1818THREADED_TEST(InternalFields) {
1819 v8::HandleScope scope;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001820 LocalContext env;
1821
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001822 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1823 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1824 instance_templ->SetInternalFieldCount(1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001825 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1826 CHECK_EQ(1, obj->InternalFieldCount());
1827 CHECK(obj->GetInternalField(0)->IsUndefined());
1828 obj->SetInternalField(0, v8_num(17));
1829 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
1830}
1831
1832
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001833THREADED_TEST(GlobalObjectInternalFields) {
1834 v8::HandleScope scope;
1835 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
1836 global_template->SetInternalFieldCount(1);
1837 LocalContext env(NULL, global_template);
1838 v8::Handle<v8::Object> global_proxy = env->Global();
1839 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
1840 CHECK_EQ(1, global->InternalFieldCount());
1841 CHECK(global->GetInternalField(0)->IsUndefined());
1842 global->SetInternalField(0, v8_num(17));
1843 CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
1844}
1845
1846
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001847THREADED_TEST(InternalFieldsNativePointers) {
1848 v8::HandleScope scope;
1849 LocalContext env;
1850
1851 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1852 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1853 instance_templ->SetInternalFieldCount(1);
1854 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1855 CHECK_EQ(1, obj->InternalFieldCount());
1856 CHECK(obj->GetPointerFromInternalField(0) == NULL);
1857
1858 char* data = new char[100];
1859
1860 void* aligned = data;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001861 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001862 void* unaligned = data + 1;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001863 CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001864
1865 // Check reading and writing aligned pointers.
1866 obj->SetPointerInInternalField(0, aligned);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001867 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001868 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1869
1870 // Check reading and writing unaligned pointers.
1871 obj->SetPointerInInternalField(0, unaligned);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001872 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001873 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1874
1875 delete[] data;
1876}
1877
1878
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001879THREADED_TEST(InternalFieldsNativePointersAndExternal) {
1880 v8::HandleScope scope;
1881 LocalContext env;
1882
1883 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1884 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1885 instance_templ->SetInternalFieldCount(1);
1886 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1887 CHECK_EQ(1, obj->InternalFieldCount());
1888 CHECK(obj->GetPointerFromInternalField(0) == NULL);
1889
1890 char* data = new char[100];
1891
1892 void* aligned = data;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001893 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001894 void* unaligned = data + 1;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001895 CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001896
1897 obj->SetPointerInInternalField(0, aligned);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001898 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001899 CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0)));
1900
1901 obj->SetPointerInInternalField(0, unaligned);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001902 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001903 CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0)));
1904
1905 obj->SetInternalField(0, v8::External::Wrap(aligned));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001906 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001907 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1908
1909 obj->SetInternalField(0, v8::External::Wrap(unaligned));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001910 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001911 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1912
1913 delete[] data;
1914}
1915
1916
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001917THREADED_TEST(IdentityHash) {
1918 v8::HandleScope scope;
1919 LocalContext env;
1920
1921 // Ensure that the test starts with an fresh heap to test whether the hash
1922 // code is based on the address.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001923 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001924 Local<v8::Object> obj = v8::Object::New();
1925 int hash = obj->GetIdentityHash();
1926 int hash1 = obj->GetIdentityHash();
1927 CHECK_EQ(hash, hash1);
1928 int hash2 = v8::Object::New()->GetIdentityHash();
1929 // Since the identity hash is essentially a random number two consecutive
1930 // objects should not be assigned the same hash code. If the test below fails
1931 // the random number generator should be evaluated.
1932 CHECK_NE(hash, hash2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001933 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001934 int hash3 = v8::Object::New()->GetIdentityHash();
1935 // Make sure that the identity hash is not based on the initial address of
1936 // the object alone. If the test below fails the random number generator
1937 // should be evaluated.
1938 CHECK_NE(hash, hash3);
1939 int hash4 = obj->GetIdentityHash();
1940 CHECK_EQ(hash, hash4);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001941
1942 // Check identity hashes behaviour in the presence of JS accessors.
1943 // Put a getter for 'v8::IdentityHash' on the Object's prototype:
1944 {
1945 CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
1946 Local<v8::Object> o1 = v8::Object::New();
1947 Local<v8::Object> o2 = v8::Object::New();
1948 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
1949 }
1950 {
1951 CompileRun(
1952 "function cnst() { return 42; };\n"
1953 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
1954 Local<v8::Object> o1 = v8::Object::New();
1955 Local<v8::Object> o2 = v8::Object::New();
1956 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
1957 }
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001958}
1959
1960
1961THREADED_TEST(HiddenProperties) {
1962 v8::HandleScope scope;
1963 LocalContext env;
1964
1965 v8::Local<v8::Object> obj = v8::Object::New();
1966 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1967 v8::Local<v8::String> empty = v8_str("");
1968 v8::Local<v8::String> prop_name = v8_str("prop_name");
1969
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001970 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001971
kasperl@chromium.orgacae3782009-04-11 09:17:08 +00001972 // Make sure delete of a non-existent hidden value works
1973 CHECK(obj->DeleteHiddenValue(key));
1974
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001975 CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
1976 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
1977 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
1978 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1979
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001980 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001981
1982 // Make sure we do not find the hidden property.
1983 CHECK(!obj->Has(empty));
1984 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1985 CHECK(obj->Get(empty)->IsUndefined());
1986 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1987 CHECK(obj->Set(empty, v8::Integer::New(2003)));
1988 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1989 CHECK_EQ(2003, obj->Get(empty)->Int32Value());
1990
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001991 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001992
1993 // Add another property and delete it afterwards to force the object in
1994 // slow case.
1995 CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
1996 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1997 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
1998 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1999 CHECK(obj->Delete(prop_name));
2000 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2001
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002002 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002003
2004 CHECK(obj->DeleteHiddenValue(key));
2005 CHECK(obj->GetHiddenValue(key).IsEmpty());
2006}
2007
2008
ricow@chromium.org9fe9cdf2011-09-27 08:04:16 +00002009THREADED_TEST(Regress97784) {
2010 // Regression test for crbug.com/97784
2011 // Messing with the Object.prototype should not have effect on
2012 // hidden properties.
2013 v8::HandleScope scope;
2014 LocalContext env;
2015
2016 v8::Local<v8::Object> obj = v8::Object::New();
2017 v8::Local<v8::String> key = v8_str("hidden");
2018
2019 CompileRun(
2020 "set_called = false;"
2021 "Object.defineProperty("
2022 " Object.prototype,"
2023 " 'hidden',"
2024 " {get: function() { return 45; },"
2025 " set: function() { set_called = true; }})");
2026
2027 CHECK(obj->GetHiddenValue(key).IsEmpty());
2028 // Make sure that the getter and setter from Object.prototype is not invoked.
2029 // If it did we would have full access to the hidden properties in
2030 // the accessor.
2031 CHECK(obj->SetHiddenValue(key, v8::Integer::New(42)));
2032 ExpectFalse("set_called");
2033 CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
2034}
2035
2036
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002037static bool interceptor_for_hidden_properties_called;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002038static v8::Handle<Value> InterceptorForHiddenProperties(
2039 Local<String> name, const AccessorInfo& info) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002040 interceptor_for_hidden_properties_called = true;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002041 return v8::Handle<Value>();
2042}
2043
2044
2045THREADED_TEST(HiddenPropertiesWithInterceptors) {
2046 v8::HandleScope scope;
2047 LocalContext context;
2048
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002049 interceptor_for_hidden_properties_called = false;
2050
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002051 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
2052
2053 // Associate an interceptor with an object and start setting hidden values.
2054 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
2055 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
2056 instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
2057 Local<v8::Function> function = fun_templ->GetFunction();
2058 Local<v8::Object> obj = function->NewInstance();
2059 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
2060 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002061 CHECK(!interceptor_for_hidden_properties_called);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002062}
2063
2064
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002065THREADED_TEST(External) {
2066 v8::HandleScope scope;
2067 int x = 3;
2068 Local<v8::External> ext = v8::External::New(&x);
2069 LocalContext env;
2070 env->Global()->Set(v8_str("ext"), ext);
2071 Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002072 v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002073 int* ptr = static_cast<int*>(reext->Value());
2074 CHECK_EQ(x, 3);
2075 *ptr = 10;
2076 CHECK_EQ(x, 10);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002077
2078 // Make sure unaligned pointers are wrapped properly.
2079 char* data = i::StrDup("0123456789");
2080 Local<v8::Value> zero = v8::External::Wrap(&data[0]);
2081 Local<v8::Value> one = v8::External::Wrap(&data[1]);
2082 Local<v8::Value> two = v8::External::Wrap(&data[2]);
2083 Local<v8::Value> three = v8::External::Wrap(&data[3]);
2084
2085 char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero));
2086 CHECK_EQ('0', *char_ptr);
2087 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one));
2088 CHECK_EQ('1', *char_ptr);
2089 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two));
2090 CHECK_EQ('2', *char_ptr);
2091 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three));
2092 CHECK_EQ('3', *char_ptr);
2093 i::DeleteArray(data);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002094}
2095
2096
2097THREADED_TEST(GlobalHandle) {
2098 v8::Persistent<String> global;
2099 {
2100 v8::HandleScope scope;
2101 Local<String> str = v8_str("str");
2102 global = v8::Persistent<String>::New(str);
2103 }
2104 CHECK_EQ(global->Length(), 3);
2105 global.Dispose();
2106}
2107
2108
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002109class WeakCallCounter {
2110 public:
2111 explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
2112 int id() { return id_; }
2113 void increment() { number_of_weak_calls_++; }
2114 int NumberOfWeakCalls() { return number_of_weak_calls_; }
2115 private:
2116 int id_;
2117 int number_of_weak_calls_;
2118};
2119
2120
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002121static void WeakPointerCallback(Persistent<Value> handle, void* id) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002122 WeakCallCounter* counter = reinterpret_cast<WeakCallCounter*>(id);
2123 CHECK_EQ(1234, counter->id());
2124 counter->increment();
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002125 handle.Dispose();
2126}
2127
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002128
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002129THREADED_TEST(ApiObjectGroups) {
2130 HandleScope scope;
2131 LocalContext env;
2132
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002133 Persistent<Object> g1s1;
2134 Persistent<Object> g1s2;
2135 Persistent<Object> g1c1;
2136 Persistent<Object> g2s1;
2137 Persistent<Object> g2s2;
2138 Persistent<Object> g2c1;
2139
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002140 WeakCallCounter counter(1234);
2141
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002142 {
2143 HandleScope scope;
2144 g1s1 = Persistent<Object>::New(Object::New());
2145 g1s2 = Persistent<Object>::New(Object::New());
2146 g1c1 = Persistent<Object>::New(Object::New());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002147 g1s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2148 g1s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2149 g1c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002150
2151 g2s1 = Persistent<Object>::New(Object::New());
2152 g2s2 = Persistent<Object>::New(Object::New());
2153 g2c1 = Persistent<Object>::New(Object::New());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002154 g2s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2155 g2s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2156 g2c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002157 }
2158
2159 Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
2160
2161 // Connect group 1 and 2, make a cycle.
2162 CHECK(g1s2->Set(0, g2s2));
2163 CHECK(g2s1->Set(0, g1s1));
2164
2165 {
2166 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2167 Persistent<Value> g1_children[] = { g1c1 };
2168 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2169 Persistent<Value> g2_children[] = { g2c1 };
2170 V8::AddObjectGroup(g1_objects, 2);
2171 V8::AddImplicitReferences(g1s1, g1_children, 1);
2172 V8::AddObjectGroup(g2_objects, 2);
2173 V8::AddImplicitReferences(g2s2, g2_children, 1);
2174 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002175 // Do a single full GC. Use kMakeHeapIterableMask to ensure that
2176 // incremental garbage collection is stopped.
2177 HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002178
2179 // All object should be alive.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002180 CHECK_EQ(0, counter.NumberOfWeakCalls());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002181
2182 // Weaken the root.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002183 root.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002184 // But make children strong roots---all the objects (except for children)
2185 // should be collectable now.
2186 g1c1.ClearWeak();
2187 g2c1.ClearWeak();
2188
2189 // Groups are deleted, rebuild groups.
2190 {
2191 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2192 Persistent<Value> g1_children[] = { g1c1 };
2193 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2194 Persistent<Value> g2_children[] = { g2c1 };
2195 V8::AddObjectGroup(g1_objects, 2);
2196 V8::AddImplicitReferences(g1s1, g1_children, 1);
2197 V8::AddObjectGroup(g2_objects, 2);
2198 V8::AddImplicitReferences(g2s2, g2_children, 1);
2199 }
2200
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002201 HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002202
2203 // All objects should be gone. 5 global handles in total.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002204 CHECK_EQ(5, counter.NumberOfWeakCalls());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002205
2206 // And now make children weak again and collect them.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002207 g1c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2208 g2c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002209
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002210 HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
2211 CHECK_EQ(7, counter.NumberOfWeakCalls());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002212}
2213
2214
2215THREADED_TEST(ApiObjectGroupsCycle) {
2216 HandleScope scope;
2217 LocalContext env;
2218
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002219 WeakCallCounter counter(1234);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002220
2221 Persistent<Object> g1s1;
2222 Persistent<Object> g1s2;
2223 Persistent<Object> g2s1;
2224 Persistent<Object> g2s2;
2225 Persistent<Object> g3s1;
2226 Persistent<Object> g3s2;
2227
2228 {
2229 HandleScope scope;
2230 g1s1 = Persistent<Object>::New(Object::New());
2231 g1s2 = Persistent<Object>::New(Object::New());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002232 g1s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2233 g1s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002234
2235 g2s1 = Persistent<Object>::New(Object::New());
2236 g2s2 = Persistent<Object>::New(Object::New());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002237 g2s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2238 g2s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002239
2240 g3s1 = Persistent<Object>::New(Object::New());
2241 g3s2 = Persistent<Object>::New(Object::New());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002242 g3s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2243 g3s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002244 }
2245
2246 Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
2247
2248 // Connect groups. We're building the following cycle:
2249 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
2250 // groups.
2251 {
2252 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2253 Persistent<Value> g1_children[] = { g2s1 };
2254 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2255 Persistent<Value> g2_children[] = { g3s1 };
2256 Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2257 Persistent<Value> g3_children[] = { g1s1 };
2258 V8::AddObjectGroup(g1_objects, 2);
2259 V8::AddImplicitReferences(g1s1, g1_children, 1);
2260 V8::AddObjectGroup(g2_objects, 2);
2261 V8::AddImplicitReferences(g2s1, g2_children, 1);
2262 V8::AddObjectGroup(g3_objects, 2);
2263 V8::AddImplicitReferences(g3s1, g3_children, 1);
2264 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002265 // Do a single full GC
2266 HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002267
2268 // All object should be alive.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002269 CHECK_EQ(0, counter.NumberOfWeakCalls());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002270
2271 // Weaken the root.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002272 root.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002273
2274 // Groups are deleted, rebuild groups.
2275 {
2276 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2277 Persistent<Value> g1_children[] = { g2s1 };
2278 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2279 Persistent<Value> g2_children[] = { g3s1 };
2280 Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2281 Persistent<Value> g3_children[] = { g1s1 };
2282 V8::AddObjectGroup(g1_objects, 2);
2283 V8::AddImplicitReferences(g1s1, g1_children, 1);
2284 V8::AddObjectGroup(g2_objects, 2);
2285 V8::AddImplicitReferences(g2s1, g2_children, 1);
2286 V8::AddObjectGroup(g3_objects, 2);
2287 V8::AddImplicitReferences(g3s1, g3_children, 1);
2288 }
2289
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002290 HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002291
2292 // All objects should be gone. 7 global handles in total.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002293 CHECK_EQ(7, counter.NumberOfWeakCalls());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002294}
2295
2296
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002297THREADED_TEST(ScriptException) {
2298 v8::HandleScope scope;
2299 LocalContext env;
2300 Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
2301 v8::TryCatch try_catch;
2302 Local<Value> result = script->Run();
2303 CHECK(result.IsEmpty());
2304 CHECK(try_catch.HasCaught());
2305 String::AsciiValue exception_value(try_catch.Exception());
2306 CHECK_EQ(*exception_value, "panama!");
2307}
2308
2309
2310bool message_received;
2311
2312
2313static void check_message(v8::Handle<v8::Message> message,
2314 v8::Handle<Value> data) {
2315 CHECK_EQ(5.76, data->NumberValue());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002316 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002317 CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002318 message_received = true;
2319}
2320
2321
2322THREADED_TEST(MessageHandlerData) {
2323 message_received = false;
2324 v8::HandleScope scope;
2325 CHECK(!message_received);
2326 v8::V8::AddMessageListener(check_message, v8_num(5.76));
2327 LocalContext context;
2328 v8::ScriptOrigin origin =
2329 v8::ScriptOrigin(v8_str("6.75"));
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002330 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
2331 &origin);
2332 script->SetData(v8_str("7.56"));
2333 script->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002334 CHECK(message_received);
2335 // clear out the message listener
2336 v8::V8::RemoveMessageListeners(check_message);
2337}
2338
2339
2340THREADED_TEST(GetSetProperty) {
2341 v8::HandleScope scope;
2342 LocalContext context;
2343 context->Global()->Set(v8_str("foo"), v8_num(14));
2344 context->Global()->Set(v8_str("12"), v8_num(92));
2345 context->Global()->Set(v8::Integer::New(16), v8_num(32));
2346 context->Global()->Set(v8_num(13), v8_num(56));
2347 Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
2348 CHECK_EQ(14, foo->Int32Value());
2349 Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
2350 CHECK_EQ(92, twelve->Int32Value());
2351 Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
2352 CHECK_EQ(32, sixteen->Int32Value());
2353 Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
2354 CHECK_EQ(56, thirteen->Int32Value());
2355 CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
2356 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
2357 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
2358 CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
2359 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
2360 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
2361 CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
2362 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
2363 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
2364}
2365
2366
2367THREADED_TEST(PropertyAttributes) {
2368 v8::HandleScope scope;
2369 LocalContext context;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002370 // none
2371 Local<String> prop = v8_str("none");
2372 context->Global()->Set(prop, v8_num(7));
2373 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002374 // read-only
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002375 prop = v8_str("read_only");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002376 context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
2377 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002378 CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002379 Script::Compile(v8_str("read_only = 9"))->Run();
2380 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2381 context->Global()->Set(prop, v8_num(10));
2382 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2383 // dont-delete
2384 prop = v8_str("dont_delete");
2385 context->Global()->Set(prop, v8_num(13), v8::DontDelete);
2386 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
2387 Script::Compile(v8_str("delete dont_delete"))->Run();
2388 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002389 CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
2390 // dont-enum
2391 prop = v8_str("dont_enum");
2392 context->Global()->Set(prop, v8_num(28), v8::DontEnum);
2393 CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
2394 // absent
2395 prop = v8_str("absent");
2396 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
2397 Local<Value> fake_prop = v8_num(1);
2398 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
2399 // exception
2400 TryCatch try_catch;
2401 Local<Value> exception =
2402 CompileRun("({ toString: function() { throw 'exception';} })");
2403 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
2404 CHECK(try_catch.HasCaught());
2405 String::AsciiValue exception_value(try_catch.Exception());
2406 CHECK_EQ("exception", *exception_value);
2407 try_catch.Reset();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002408}
2409
2410
2411THREADED_TEST(Array) {
2412 v8::HandleScope scope;
2413 LocalContext context;
2414 Local<v8::Array> array = v8::Array::New();
2415 CHECK_EQ(0, array->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002416 CHECK(array->Get(0)->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002417 CHECK(!array->Has(0));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002418 CHECK(array->Get(100)->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002419 CHECK(!array->Has(100));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002420 array->Set(2, v8_num(7));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002421 CHECK_EQ(3, array->Length());
2422 CHECK(!array->Has(0));
2423 CHECK(!array->Has(1));
2424 CHECK(array->Has(2));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002425 CHECK_EQ(7, array->Get(2)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002426 Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002427 Local<v8::Array> arr = obj.As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002428 CHECK_EQ(3, arr->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002429 CHECK_EQ(1, arr->Get(0)->Int32Value());
2430 CHECK_EQ(2, arr->Get(1)->Int32Value());
2431 CHECK_EQ(3, arr->Get(2)->Int32Value());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002432 array = v8::Array::New(27);
2433 CHECK_EQ(27, array->Length());
2434 array = v8::Array::New(-27);
2435 CHECK_EQ(0, array->Length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002436}
2437
2438
2439v8::Handle<Value> HandleF(const v8::Arguments& args) {
2440 v8::HandleScope scope;
2441 ApiTestFuzzer::Fuzz();
2442 Local<v8::Array> result = v8::Array::New(args.Length());
2443 for (int i = 0; i < args.Length(); i++)
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002444 result->Set(i, args[i]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002445 return scope.Close(result);
2446}
2447
2448
2449THREADED_TEST(Vector) {
2450 v8::HandleScope scope;
2451 Local<ObjectTemplate> global = ObjectTemplate::New();
2452 global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
2453 LocalContext context(0, global);
2454
2455 const char* fun = "f()";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002456 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002457 CHECK_EQ(0, a0->Length());
2458
2459 const char* fun2 = "f(11)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002460 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002461 CHECK_EQ(1, a1->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002462 CHECK_EQ(11, a1->Get(0)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002463
2464 const char* fun3 = "f(12, 13)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002465 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002466 CHECK_EQ(2, a2->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002467 CHECK_EQ(12, a2->Get(0)->Int32Value());
2468 CHECK_EQ(13, a2->Get(1)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002469
2470 const char* fun4 = "f(14, 15, 16)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002471 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002472 CHECK_EQ(3, a3->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002473 CHECK_EQ(14, a3->Get(0)->Int32Value());
2474 CHECK_EQ(15, a3->Get(1)->Int32Value());
2475 CHECK_EQ(16, a3->Get(2)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002476
2477 const char* fun5 = "f(17, 18, 19, 20)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002478 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002479 CHECK_EQ(4, a4->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002480 CHECK_EQ(17, a4->Get(0)->Int32Value());
2481 CHECK_EQ(18, a4->Get(1)->Int32Value());
2482 CHECK_EQ(19, a4->Get(2)->Int32Value());
2483 CHECK_EQ(20, a4->Get(3)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002484}
2485
2486
2487THREADED_TEST(FunctionCall) {
2488 v8::HandleScope scope;
2489 LocalContext context;
2490 CompileRun(
2491 "function Foo() {"
2492 " var result = [];"
2493 " for (var i = 0; i < arguments.length; i++) {"
2494 " result.push(arguments[i]);"
2495 " }"
2496 " return result;"
2497 "}");
2498 Local<Function> Foo =
2499 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2500
2501 v8::Handle<Value>* args0 = NULL;
2502 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
2503 CHECK_EQ(0, a0->Length());
2504
2505 v8::Handle<Value> args1[] = { v8_num(1.1) };
2506 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
2507 CHECK_EQ(1, a1->Length());
2508 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2509
2510 v8::Handle<Value> args2[] = { v8_num(2.2),
2511 v8_num(3.3) };
2512 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
2513 CHECK_EQ(2, a2->Length());
2514 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2515 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2516
2517 v8::Handle<Value> args3[] = { v8_num(4.4),
2518 v8_num(5.5),
2519 v8_num(6.6) };
2520 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
2521 CHECK_EQ(3, a3->Length());
2522 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2523 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2524 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2525
2526 v8::Handle<Value> args4[] = { v8_num(7.7),
2527 v8_num(8.8),
2528 v8_num(9.9),
2529 v8_num(10.11) };
2530 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
2531 CHECK_EQ(4, a4->Length());
2532 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2533 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2534 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2535 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2536}
2537
2538
2539static const char* js_code_causing_out_of_memory =
2540 "var a = new Array(); while(true) a.push(a);";
2541
2542
2543// These tests run for a long time and prevent us from running tests
2544// that come after them so they cannot run in parallel.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002545TEST(OutOfMemory) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002546 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002547 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002548 // Set heap limits.
2549 static const int K = 1024;
2550 v8::ResourceConstraints constraints;
2551 constraints.set_max_young_space_size(256 * K);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002552 constraints.set_max_old_space_size(4 * K * K);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002553 v8::SetResourceConstraints(&constraints);
2554
2555 // Execute a script that causes out of memory.
2556 v8::HandleScope scope;
2557 LocalContext context;
2558 v8::V8::IgnoreOutOfMemoryException();
2559 Local<Script> script =
2560 Script::Compile(String::New(js_code_causing_out_of_memory));
2561 Local<Value> result = script->Run();
2562
2563 // Check for out of memory state.
2564 CHECK(result.IsEmpty());
2565 CHECK(context->HasOutOfMemoryException());
2566}
2567
2568
2569v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
2570 ApiTestFuzzer::Fuzz();
2571
2572 v8::HandleScope scope;
2573 LocalContext context;
2574 Local<Script> script =
2575 Script::Compile(String::New(js_code_causing_out_of_memory));
2576 Local<Value> result = script->Run();
2577
2578 // Check for out of memory state.
2579 CHECK(result.IsEmpty());
2580 CHECK(context->HasOutOfMemoryException());
2581
2582 return result;
2583}
2584
2585
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002586TEST(OutOfMemoryNested) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002587 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002588 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002589 // Set heap limits.
2590 static const int K = 1024;
2591 v8::ResourceConstraints constraints;
2592 constraints.set_max_young_space_size(256 * K);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002593 constraints.set_max_old_space_size(4 * K * K);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002594 v8::SetResourceConstraints(&constraints);
2595
2596 v8::HandleScope scope;
2597 Local<ObjectTemplate> templ = ObjectTemplate::New();
2598 templ->Set(v8_str("ProvokeOutOfMemory"),
2599 v8::FunctionTemplate::New(ProvokeOutOfMemory));
2600 LocalContext context(0, templ);
2601 v8::V8::IgnoreOutOfMemoryException();
2602 Local<Value> result = CompileRun(
2603 "var thrown = false;"
2604 "try {"
2605 " ProvokeOutOfMemory();"
2606 "} catch (e) {"
2607 " thrown = true;"
2608 "}");
2609 // Check for out of memory state.
2610 CHECK(result.IsEmpty());
2611 CHECK(context->HasOutOfMemoryException());
2612}
2613
2614
2615TEST(HugeConsStringOutOfMemory) {
2616 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002617 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002618 // Set heap limits.
2619 static const int K = 1024;
2620 v8::ResourceConstraints constraints;
2621 constraints.set_max_young_space_size(256 * K);
2622 constraints.set_max_old_space_size(2 * K * K);
2623 v8::SetResourceConstraints(&constraints);
2624
2625 // Execute a script that causes out of memory.
2626 v8::V8::IgnoreOutOfMemoryException();
2627
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002628 v8::HandleScope scope;
2629 LocalContext context;
2630
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002631 // Build huge string. This should fail with out of memory exception.
2632 Local<Value> result = CompileRun(
2633 "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002634 "for (var i = 0; i < 22; i++) { str = str + str; }");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002635
2636 // Check for out of memory state.
2637 CHECK(result.IsEmpty());
2638 CHECK(context->HasOutOfMemoryException());
2639}
2640
2641
2642THREADED_TEST(ConstructCall) {
2643 v8::HandleScope scope;
2644 LocalContext context;
2645 CompileRun(
2646 "function Foo() {"
2647 " var result = [];"
2648 " for (var i = 0; i < arguments.length; i++) {"
2649 " result.push(arguments[i]);"
2650 " }"
2651 " return result;"
2652 "}");
2653 Local<Function> Foo =
2654 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2655
2656 v8::Handle<Value>* args0 = NULL;
2657 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
2658 CHECK_EQ(0, a0->Length());
2659
2660 v8::Handle<Value> args1[] = { v8_num(1.1) };
2661 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
2662 CHECK_EQ(1, a1->Length());
2663 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2664
2665 v8::Handle<Value> args2[] = { v8_num(2.2),
2666 v8_num(3.3) };
2667 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
2668 CHECK_EQ(2, a2->Length());
2669 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2670 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2671
2672 v8::Handle<Value> args3[] = { v8_num(4.4),
2673 v8_num(5.5),
2674 v8_num(6.6) };
2675 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
2676 CHECK_EQ(3, a3->Length());
2677 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2678 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2679 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2680
2681 v8::Handle<Value> args4[] = { v8_num(7.7),
2682 v8_num(8.8),
2683 v8_num(9.9),
2684 v8_num(10.11) };
2685 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
2686 CHECK_EQ(4, a4->Length());
2687 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2688 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2689 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2690 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2691}
2692
2693
2694static void CheckUncle(v8::TryCatch* try_catch) {
2695 CHECK(try_catch->HasCaught());
2696 String::AsciiValue str_value(try_catch->Exception());
2697 CHECK_EQ(*str_value, "uncle?");
2698 try_catch->Reset();
2699}
2700
2701
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002702THREADED_TEST(ConversionNumber) {
2703 v8::HandleScope scope;
2704 LocalContext env;
2705 // Very large number.
2706 CompileRun("var obj = Math.pow(2,32) * 1237;");
2707 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2708 CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
2709 CHECK_EQ(0, obj->ToInt32()->Value());
2710 CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned.
2711 // Large number.
2712 CompileRun("var obj = -1234567890123;");
2713 obj = env->Global()->Get(v8_str("obj"));
2714 CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
2715 CHECK_EQ(-1912276171, obj->ToInt32()->Value());
2716 CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT
2717 // Small positive integer.
2718 CompileRun("var obj = 42;");
2719 obj = env->Global()->Get(v8_str("obj"));
2720 CHECK_EQ(42.0, obj->ToNumber()->Value());
2721 CHECK_EQ(42, obj->ToInt32()->Value());
2722 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
2723 // Negative integer.
2724 CompileRun("var obj = -37;");
2725 obj = env->Global()->Get(v8_str("obj"));
2726 CHECK_EQ(-37.0, obj->ToNumber()->Value());
2727 CHECK_EQ(-37, obj->ToInt32()->Value());
2728 CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT
2729 // Positive non-int32 integer.
2730 CompileRun("var obj = 0x81234567;");
2731 obj = env->Global()->Get(v8_str("obj"));
2732 CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
2733 CHECK_EQ(-2128394905, obj->ToInt32()->Value());
2734 CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT
2735 // Fraction.
2736 CompileRun("var obj = 42.3;");
2737 obj = env->Global()->Get(v8_str("obj"));
2738 CHECK_EQ(42.3, obj->ToNumber()->Value());
2739 CHECK_EQ(42, obj->ToInt32()->Value());
2740 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
2741 // Large negative fraction.
2742 CompileRun("var obj = -5726623061.75;");
2743 obj = env->Global()->Get(v8_str("obj"));
2744 CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
2745 CHECK_EQ(-1431655765, obj->ToInt32()->Value());
2746 CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT
2747}
2748
2749
2750THREADED_TEST(isNumberType) {
2751 v8::HandleScope scope;
2752 LocalContext env;
2753 // Very large number.
2754 CompileRun("var obj = Math.pow(2,32) * 1237;");
2755 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2756 CHECK(!obj->IsInt32());
2757 CHECK(!obj->IsUint32());
2758 // Large negative number.
2759 CompileRun("var obj = -1234567890123;");
2760 obj = env->Global()->Get(v8_str("obj"));
2761 CHECK(!obj->IsInt32());
2762 CHECK(!obj->IsUint32());
2763 // Small positive integer.
2764 CompileRun("var obj = 42;");
2765 obj = env->Global()->Get(v8_str("obj"));
2766 CHECK(obj->IsInt32());
2767 CHECK(obj->IsUint32());
2768 // Negative integer.
2769 CompileRun("var obj = -37;");
2770 obj = env->Global()->Get(v8_str("obj"));
2771 CHECK(obj->IsInt32());
2772 CHECK(!obj->IsUint32());
2773 // Positive non-int32 integer.
2774 CompileRun("var obj = 0x81234567;");
2775 obj = env->Global()->Get(v8_str("obj"));
2776 CHECK(!obj->IsInt32());
2777 CHECK(obj->IsUint32());
2778 // Fraction.
2779 CompileRun("var obj = 42.3;");
2780 obj = env->Global()->Get(v8_str("obj"));
2781 CHECK(!obj->IsInt32());
2782 CHECK(!obj->IsUint32());
2783 // Large negative fraction.
2784 CompileRun("var obj = -5726623061.75;");
2785 obj = env->Global()->Get(v8_str("obj"));
2786 CHECK(!obj->IsInt32());
2787 CHECK(!obj->IsUint32());
2788}
2789
2790
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002791THREADED_TEST(ConversionException) {
2792 v8::HandleScope scope;
2793 LocalContext env;
2794 CompileRun(
2795 "function TestClass() { };"
2796 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
2797 "var obj = new TestClass();");
2798 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2799
2800 v8::TryCatch try_catch;
2801
2802 Local<Value> to_string_result = obj->ToString();
2803 CHECK(to_string_result.IsEmpty());
2804 CheckUncle(&try_catch);
2805
2806 Local<Value> to_number_result = obj->ToNumber();
2807 CHECK(to_number_result.IsEmpty());
2808 CheckUncle(&try_catch);
2809
2810 Local<Value> to_integer_result = obj->ToInteger();
2811 CHECK(to_integer_result.IsEmpty());
2812 CheckUncle(&try_catch);
2813
2814 Local<Value> to_uint32_result = obj->ToUint32();
2815 CHECK(to_uint32_result.IsEmpty());
2816 CheckUncle(&try_catch);
2817
2818 Local<Value> to_int32_result = obj->ToInt32();
2819 CHECK(to_int32_result.IsEmpty());
2820 CheckUncle(&try_catch);
2821
2822 Local<Value> to_object_result = v8::Undefined()->ToObject();
2823 CHECK(to_object_result.IsEmpty());
2824 CHECK(try_catch.HasCaught());
2825 try_catch.Reset();
2826
2827 int32_t int32_value = obj->Int32Value();
2828 CHECK_EQ(0, int32_value);
2829 CheckUncle(&try_catch);
2830
2831 uint32_t uint32_value = obj->Uint32Value();
2832 CHECK_EQ(0, uint32_value);
2833 CheckUncle(&try_catch);
2834
2835 double number_value = obj->NumberValue();
2836 CHECK_NE(0, IsNaN(number_value));
2837 CheckUncle(&try_catch);
2838
2839 int64_t integer_value = obj->IntegerValue();
2840 CHECK_EQ(0.0, static_cast<double>(integer_value));
2841 CheckUncle(&try_catch);
2842}
2843
2844
2845v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
2846 ApiTestFuzzer::Fuzz();
2847 return v8::ThrowException(v8_str("konto"));
2848}
2849
2850
ager@chromium.org8bb60582008-12-11 12:02:20 +00002851v8::Handle<Value> CCatcher(const v8::Arguments& args) {
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00002852 if (args.Length() < 1) return v8::False();
ager@chromium.org8bb60582008-12-11 12:02:20 +00002853 v8::HandleScope scope;
2854 v8::TryCatch try_catch;
ager@chromium.org71daaf62009-04-01 07:22:49 +00002855 Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
2856 CHECK(!try_catch.HasCaught() || result.IsEmpty());
ager@chromium.org8bb60582008-12-11 12:02:20 +00002857 return v8::Boolean::New(try_catch.HasCaught());
2858}
2859
2860
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002861THREADED_TEST(APICatch) {
2862 v8::HandleScope scope;
2863 Local<ObjectTemplate> templ = ObjectTemplate::New();
2864 templ->Set(v8_str("ThrowFromC"),
2865 v8::FunctionTemplate::New(ThrowFromC));
2866 LocalContext context(0, templ);
2867 CompileRun(
2868 "var thrown = false;"
2869 "try {"
2870 " ThrowFromC();"
2871 "} catch (e) {"
2872 " thrown = true;"
2873 "}");
2874 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
2875 CHECK(thrown->BooleanValue());
2876}
2877
2878
ager@chromium.org8bb60582008-12-11 12:02:20 +00002879THREADED_TEST(APIThrowTryCatch) {
2880 v8::HandleScope scope;
2881 Local<ObjectTemplate> templ = ObjectTemplate::New();
2882 templ->Set(v8_str("ThrowFromC"),
2883 v8::FunctionTemplate::New(ThrowFromC));
2884 LocalContext context(0, templ);
2885 v8::TryCatch try_catch;
2886 CompileRun("ThrowFromC();");
2887 CHECK(try_catch.HasCaught());
2888}
2889
2890
2891// Test that a try-finally block doesn't shadow a try-catch block
2892// when setting up an external handler.
ager@chromium.org71daaf62009-04-01 07:22:49 +00002893//
2894// BUG(271): Some of the exception propagation does not work on the
2895// ARM simulator because the simulator separates the C++ stack and the
2896// JS stack. This test therefore fails on the simulator. The test is
2897// not threaded to allow the threading tests to run on the simulator.
2898TEST(TryCatchInTryFinally) {
ager@chromium.org8bb60582008-12-11 12:02:20 +00002899 v8::HandleScope scope;
2900 Local<ObjectTemplate> templ = ObjectTemplate::New();
2901 templ->Set(v8_str("CCatcher"),
2902 v8::FunctionTemplate::New(CCatcher));
2903 LocalContext context(0, templ);
2904 Local<Value> result = CompileRun("try {"
2905 " try {"
2906 " CCatcher('throw 7;');"
2907 " } finally {"
2908 " }"
2909 "} catch (e) {"
2910 "}");
2911 CHECK(result->IsTrue());
2912}
2913
2914
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002915static void check_reference_error_message(
2916 v8::Handle<v8::Message> message,
2917 v8::Handle<v8::Value> data) {
2918 const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
2919 CHECK(message->Get()->Equals(v8_str(reference_error)));
2920}
2921
2922
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00002923static v8::Handle<Value> Fail(const v8::Arguments& args) {
2924 ApiTestFuzzer::Fuzz();
2925 CHECK(false);
2926 return v8::Undefined();
2927}
2928
2929
2930// Test that overwritten methods are not invoked on uncaught exception
2931// formatting. However, they are invoked when performing normal error
2932// string conversions.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002933TEST(APIThrowMessageOverwrittenToString) {
2934 v8::HandleScope scope;
2935 v8::V8::AddMessageListener(check_reference_error_message);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00002936 Local<ObjectTemplate> templ = ObjectTemplate::New();
2937 templ->Set(v8_str("fail"), v8::FunctionTemplate::New(Fail));
2938 LocalContext context(NULL, templ);
2939 CompileRun("asdf;");
2940 CompileRun("var limit = {};"
2941 "limit.valueOf = fail;"
2942 "Error.stackTraceLimit = limit;");
2943 CompileRun("asdf");
2944 CompileRun("Array.prototype.pop = fail;");
2945 CompileRun("Object.prototype.hasOwnProperty = fail;");
2946 CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
whesse@chromium.org7a392b32011-01-31 11:30:36 +00002947 CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
2948 CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002949 CompileRun("ReferenceError.prototype.toString ="
2950 " function() { return 'Whoops' }");
2951 CompileRun("asdf;");
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002952 CompileRun("ReferenceError.prototype.constructor.name = void 0;");
2953 CompileRun("asdf;");
2954 CompileRun("ReferenceError.prototype.constructor = void 0;");
2955 CompileRun("asdf;");
ager@chromium.org0ee099b2011-01-25 14:06:47 +00002956 CompileRun("ReferenceError.prototype.__proto__ = new Object();");
2957 CompileRun("asdf;");
2958 CompileRun("ReferenceError.prototype = new Object();");
2959 CompileRun("asdf;");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002960 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
2961 CHECK(string->Equals(v8_str("Whoops")));
ager@chromium.org378b34e2011-01-28 08:04:38 +00002962 CompileRun("ReferenceError.prototype.constructor = new Object();"
2963 "ReferenceError.prototype.constructor.name = 1;"
2964 "Number.prototype.toString = function() { return 'Whoops'; };"
2965 "ReferenceError.prototype.toString = Object.prototype.toString;");
2966 CompileRun("asdf;");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002967 v8::V8::RemoveMessageListeners(check_message);
2968}
2969
2970
ager@chromium.org8bb60582008-12-11 12:02:20 +00002971static void receive_message(v8::Handle<v8::Message> message,
2972 v8::Handle<v8::Value> data) {
ager@chromium.org71daaf62009-04-01 07:22:49 +00002973 message->Get();
ager@chromium.org8bb60582008-12-11 12:02:20 +00002974 message_received = true;
2975}
2976
2977
2978TEST(APIThrowMessage) {
2979 message_received = false;
2980 v8::HandleScope scope;
2981 v8::V8::AddMessageListener(receive_message);
2982 Local<ObjectTemplate> templ = ObjectTemplate::New();
2983 templ->Set(v8_str("ThrowFromC"),
2984 v8::FunctionTemplate::New(ThrowFromC));
2985 LocalContext context(0, templ);
2986 CompileRun("ThrowFromC();");
2987 CHECK(message_received);
2988 v8::V8::RemoveMessageListeners(check_message);
2989}
2990
2991
2992TEST(APIThrowMessageAndVerboseTryCatch) {
2993 message_received = false;
2994 v8::HandleScope scope;
2995 v8::V8::AddMessageListener(receive_message);
2996 Local<ObjectTemplate> templ = ObjectTemplate::New();
2997 templ->Set(v8_str("ThrowFromC"),
2998 v8::FunctionTemplate::New(ThrowFromC));
2999 LocalContext context(0, templ);
3000 v8::TryCatch try_catch;
3001 try_catch.SetVerbose(true);
ager@chromium.org71daaf62009-04-01 07:22:49 +00003002 Local<Value> result = CompileRun("ThrowFromC();");
ager@chromium.org8bb60582008-12-11 12:02:20 +00003003 CHECK(try_catch.HasCaught());
ager@chromium.org71daaf62009-04-01 07:22:49 +00003004 CHECK(result.IsEmpty());
ager@chromium.org8bb60582008-12-11 12:02:20 +00003005 CHECK(message_received);
3006 v8::V8::RemoveMessageListeners(check_message);
3007}
3008
3009
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003010TEST(APIStackOverflowAndVerboseTryCatch) {
3011 message_received = false;
3012 v8::HandleScope scope;
3013 v8::V8::AddMessageListener(receive_message);
3014 LocalContext context;
3015 v8::TryCatch try_catch;
3016 try_catch.SetVerbose(true);
3017 Local<Value> result = CompileRun("function foo() { foo(); } foo();");
3018 CHECK(try_catch.HasCaught());
3019 CHECK(result.IsEmpty());
3020 CHECK(message_received);
3021 v8::V8::RemoveMessageListeners(receive_message);
3022}
3023
3024
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003025THREADED_TEST(ExternalScriptException) {
3026 v8::HandleScope scope;
3027 Local<ObjectTemplate> templ = ObjectTemplate::New();
3028 templ->Set(v8_str("ThrowFromC"),
3029 v8::FunctionTemplate::New(ThrowFromC));
3030 LocalContext context(0, templ);
3031
3032 v8::TryCatch try_catch;
3033 Local<Script> script
3034 = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
3035 Local<Value> result = script->Run();
3036 CHECK(result.IsEmpty());
3037 CHECK(try_catch.HasCaught());
3038 String::AsciiValue exception_value(try_catch.Exception());
3039 CHECK_EQ("konto", *exception_value);
3040}
3041
3042
3043
3044v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
3045 ApiTestFuzzer::Fuzz();
3046 CHECK_EQ(4, args.Length());
3047 int count = args[0]->Int32Value();
3048 int cInterval = args[2]->Int32Value();
3049 if (count == 0) {
3050 return v8::ThrowException(v8_str("FromC"));
3051 } else {
3052 Local<v8::Object> global = Context::GetCurrent()->Global();
3053 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
3054 v8::Handle<Value> argv[] = { v8_num(count - 1),
3055 args[1],
3056 args[2],
3057 args[3] };
3058 if (count % cInterval == 0) {
3059 v8::TryCatch try_catch;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003060 Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003061 int expected = args[3]->Int32Value();
3062 if (try_catch.HasCaught()) {
3063 CHECK_EQ(expected, count);
ager@chromium.org71daaf62009-04-01 07:22:49 +00003064 CHECK(result.IsEmpty());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003065 CHECK(!i::Isolate::Current()->has_scheduled_exception());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003066 } else {
3067 CHECK_NE(expected, count);
3068 }
3069 return result;
3070 } else {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003071 return fun.As<Function>()->Call(global, 4, argv);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003072 }
3073 }
3074}
3075
3076
3077v8::Handle<Value> JSCheck(const v8::Arguments& args) {
3078 ApiTestFuzzer::Fuzz();
3079 CHECK_EQ(3, args.Length());
3080 bool equality = args[0]->BooleanValue();
3081 int count = args[1]->Int32Value();
3082 int expected = args[2]->Int32Value();
3083 if (equality) {
3084 CHECK_EQ(count, expected);
3085 } else {
3086 CHECK_NE(count, expected);
3087 }
3088 return v8::Undefined();
3089}
3090
3091
ager@chromium.org8bb60582008-12-11 12:02:20 +00003092THREADED_TEST(EvalInTryFinally) {
3093 v8::HandleScope scope;
3094 LocalContext context;
3095 v8::TryCatch try_catch;
3096 CompileRun("(function() {"
3097 " try {"
3098 " eval('asldkf (*&^&*^');"
3099 " } finally {"
3100 " return;"
3101 " }"
3102 "})()");
3103 CHECK(!try_catch.HasCaught());
3104}
3105
3106
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003107// This test works by making a stack of alternating JavaScript and C
3108// activations. These activations set up exception handlers with regular
3109// intervals, one interval for C activations and another for JavaScript
3110// activations. When enough activations have been created an exception is
3111// thrown and we check that the right activation catches the exception and that
3112// no other activations do. The right activation is always the topmost one with
3113// a handler, regardless of whether it is in JavaScript or C.
3114//
3115// The notation used to describe a test case looks like this:
3116//
3117// *JS[4] *C[3] @JS[2] C[1] JS[0]
3118//
3119// Each entry is an activation, either JS or C. The index is the count at that
3120// level. Stars identify activations with exception handlers, the @ identifies
3121// the exception handler that should catch the exception.
ager@chromium.org71daaf62009-04-01 07:22:49 +00003122//
3123// BUG(271): Some of the exception propagation does not work on the
3124// ARM simulator because the simulator separates the C++ stack and the
3125// JS stack. This test therefore fails on the simulator. The test is
3126// not threaded to allow the threading tests to run on the simulator.
3127TEST(ExceptionOrder) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003128 v8::HandleScope scope;
3129 Local<ObjectTemplate> templ = ObjectTemplate::New();
3130 templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
3131 templ->Set(v8_str("CThrowCountDown"),
3132 v8::FunctionTemplate::New(CThrowCountDown));
3133 LocalContext context(0, templ);
3134 CompileRun(
3135 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
3136 " if (count == 0) throw 'FromJS';"
3137 " if (count % jsInterval == 0) {"
3138 " try {"
3139 " var value = CThrowCountDown(count - 1,"
3140 " jsInterval,"
3141 " cInterval,"
3142 " expected);"
3143 " check(false, count, expected);"
3144 " return value;"
3145 " } catch (e) {"
3146 " check(true, count, expected);"
3147 " }"
3148 " } else {"
3149 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
3150 " }"
3151 "}");
3152 Local<Function> fun =
3153 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
3154
3155 const int argc = 4;
3156 // count jsInterval cInterval expected
3157
3158 // *JS[4] *C[3] @JS[2] C[1] JS[0]
3159 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
3160 fun->Call(fun, argc, a0);
3161
3162 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
3163 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
3164 fun->Call(fun, argc, a1);
3165
3166 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
3167 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
3168 fun->Call(fun, argc, a2);
3169
3170 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
3171 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
3172 fun->Call(fun, argc, a3);
3173
3174 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
3175 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
3176 fun->Call(fun, argc, a4);
3177
3178 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
3179 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
3180 fun->Call(fun, argc, a5);
3181}
3182
3183
3184v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
3185 ApiTestFuzzer::Fuzz();
3186 CHECK_EQ(1, args.Length());
3187 return v8::ThrowException(args[0]);
3188}
3189
3190
3191THREADED_TEST(ThrowValues) {
3192 v8::HandleScope scope;
3193 Local<ObjectTemplate> templ = ObjectTemplate::New();
3194 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
3195 LocalContext context(0, templ);
3196 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
3197 "function Run(obj) {"
3198 " try {"
3199 " Throw(obj);"
3200 " } catch (e) {"
3201 " return e;"
3202 " }"
3203 " return 'no exception';"
3204 "}"
3205 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
3206 CHECK_EQ(5, result->Length());
3207 CHECK(result->Get(v8::Integer::New(0))->IsString());
3208 CHECK(result->Get(v8::Integer::New(1))->IsNumber());
3209 CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
3210 CHECK(result->Get(v8::Integer::New(2))->IsNumber());
3211 CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
3212 CHECK(result->Get(v8::Integer::New(3))->IsNull());
3213 CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
3214}
3215
3216
3217THREADED_TEST(CatchZero) {
3218 v8::HandleScope scope;
3219 LocalContext context;
3220 v8::TryCatch try_catch;
3221 CHECK(!try_catch.HasCaught());
3222 Script::Compile(v8_str("throw 10"))->Run();
3223 CHECK(try_catch.HasCaught());
3224 CHECK_EQ(10, try_catch.Exception()->Int32Value());
3225 try_catch.Reset();
3226 CHECK(!try_catch.HasCaught());
3227 Script::Compile(v8_str("throw 0"))->Run();
3228 CHECK(try_catch.HasCaught());
3229 CHECK_EQ(0, try_catch.Exception()->Int32Value());
3230}
3231
3232
3233THREADED_TEST(CatchExceptionFromWith) {
3234 v8::HandleScope scope;
3235 LocalContext context;
3236 v8::TryCatch try_catch;
3237 CHECK(!try_catch.HasCaught());
3238 Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
3239 CHECK(try_catch.HasCaught());
3240}
3241
3242
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003243THREADED_TEST(TryCatchAndFinallyHidingException) {
3244 v8::HandleScope scope;
3245 LocalContext context;
3246 v8::TryCatch try_catch;
3247 CHECK(!try_catch.HasCaught());
3248 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
3249 CompileRun("f({toString: function() { throw 42; }});");
3250 CHECK(!try_catch.HasCaught());
3251}
3252
3253
3254v8::Handle<v8::Value> WithTryCatch(const v8::Arguments& args) {
3255 v8::TryCatch try_catch;
3256 return v8::Undefined();
3257}
3258
3259
3260THREADED_TEST(TryCatchAndFinally) {
3261 v8::HandleScope scope;
3262 LocalContext context;
3263 context->Global()->Set(
3264 v8_str("native_with_try_catch"),
3265 v8::FunctionTemplate::New(WithTryCatch)->GetFunction());
3266 v8::TryCatch try_catch;
3267 CHECK(!try_catch.HasCaught());
3268 CompileRun(
3269 "try {\n"
3270 " throw new Error('a');\n"
3271 "} finally {\n"
3272 " native_with_try_catch();\n"
3273 "}\n");
3274 CHECK(try_catch.HasCaught());
3275}
3276
3277
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003278THREADED_TEST(Equality) {
3279 v8::HandleScope scope;
3280 LocalContext context;
3281 // Check that equality works at all before relying on CHECK_EQ
3282 CHECK(v8_str("a")->Equals(v8_str("a")));
3283 CHECK(!v8_str("a")->Equals(v8_str("b")));
3284
3285 CHECK_EQ(v8_str("a"), v8_str("a"));
3286 CHECK_NE(v8_str("a"), v8_str("b"));
3287 CHECK_EQ(v8_num(1), v8_num(1));
3288 CHECK_EQ(v8_num(1.00), v8_num(1));
3289 CHECK_NE(v8_num(1), v8_num(2));
3290
3291 // Assume String is not symbol.
3292 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
3293 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
3294 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
3295 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
3296 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
3297 CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
3298 Local<Value> not_a_number = v8_num(i::OS::nan_value());
3299 CHECK(!not_a_number->StrictEquals(not_a_number));
3300 CHECK(v8::False()->StrictEquals(v8::False()));
3301 CHECK(!v8::False()->StrictEquals(v8::Undefined()));
3302
3303 v8::Handle<v8::Object> obj = v8::Object::New();
3304 v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
3305 CHECK(alias->StrictEquals(obj));
3306 alias.Dispose();
3307}
3308
3309
3310THREADED_TEST(MultiRun) {
3311 v8::HandleScope scope;
3312 LocalContext context;
3313 Local<Script> script = Script::Compile(v8_str("x"));
3314 for (int i = 0; i < 10; i++)
3315 script->Run();
3316}
3317
3318
3319static v8::Handle<Value> GetXValue(Local<String> name,
3320 const AccessorInfo& info) {
3321 ApiTestFuzzer::Fuzz();
3322 CHECK_EQ(info.Data(), v8_str("donut"));
3323 CHECK_EQ(name, v8_str("x"));
3324 return name;
3325}
3326
3327
3328THREADED_TEST(SimplePropertyRead) {
3329 v8::HandleScope scope;
3330 Local<ObjectTemplate> templ = ObjectTemplate::New();
3331 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3332 LocalContext context;
3333 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3334 Local<Script> script = Script::Compile(v8_str("obj.x"));
3335 for (int i = 0; i < 10; i++) {
3336 Local<Value> result = script->Run();
3337 CHECK_EQ(result, v8_str("x"));
3338 }
3339}
3340
ager@chromium.org5c838252010-02-19 08:53:10 +00003341THREADED_TEST(DefinePropertyOnAPIAccessor) {
3342 v8::HandleScope scope;
3343 Local<ObjectTemplate> templ = ObjectTemplate::New();
3344 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3345 LocalContext context;
3346 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3347
3348 // Uses getOwnPropertyDescriptor to check the configurable status
3349 Local<Script> script_desc
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003350 = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
ager@chromium.org5c838252010-02-19 08:53:10 +00003351 "obj, 'x');"
3352 "prop.configurable;"));
3353 Local<Value> result = script_desc->Run();
3354 CHECK_EQ(result->BooleanValue(), true);
3355
3356 // Redefine get - but still configurable
3357 Local<Script> script_define
3358 = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
3359 " configurable: true };"
3360 "Object.defineProperty(obj, 'x', desc);"
3361 "obj.x"));
3362 result = script_define->Run();
3363 CHECK_EQ(result, v8_num(42));
3364
3365 // Check that the accessor is still configurable
3366 result = script_desc->Run();
3367 CHECK_EQ(result->BooleanValue(), true);
3368
3369 // Redefine to a non-configurable
3370 script_define
3371 = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
3372 " configurable: false };"
3373 "Object.defineProperty(obj, 'x', desc);"
3374 "obj.x"));
3375 result = script_define->Run();
3376 CHECK_EQ(result, v8_num(43));
3377 result = script_desc->Run();
3378 CHECK_EQ(result->BooleanValue(), false);
3379
3380 // Make sure that it is not possible to redefine again
3381 v8::TryCatch try_catch;
3382 result = script_define->Run();
3383 CHECK(try_catch.HasCaught());
3384 String::AsciiValue exception_value(try_catch.Exception());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003385 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
ager@chromium.org5c838252010-02-19 08:53:10 +00003386}
3387
3388THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
3389 v8::HandleScope scope;
3390 Local<ObjectTemplate> templ = ObjectTemplate::New();
3391 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3392 LocalContext context;
3393 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3394
3395 Local<Script> script_desc = Script::Compile(v8_str("var prop ="
3396 "Object.getOwnPropertyDescriptor( "
3397 "obj, 'x');"
3398 "prop.configurable;"));
3399 Local<Value> result = script_desc->Run();
3400 CHECK_EQ(result->BooleanValue(), true);
3401
3402 Local<Script> script_define =
3403 Script::Compile(v8_str("var desc = {get: function(){return 42; },"
3404 " configurable: true };"
3405 "Object.defineProperty(obj, 'x', desc);"
3406 "obj.x"));
3407 result = script_define->Run();
3408 CHECK_EQ(result, v8_num(42));
3409
3410
3411 result = script_desc->Run();
3412 CHECK_EQ(result->BooleanValue(), true);
3413
3414
3415 script_define =
3416 Script::Compile(v8_str("var desc = {get: function(){return 43; },"
3417 " configurable: false };"
3418 "Object.defineProperty(obj, 'x', desc);"
3419 "obj.x"));
3420 result = script_define->Run();
3421 CHECK_EQ(result, v8_num(43));
3422 result = script_desc->Run();
3423
3424 CHECK_EQ(result->BooleanValue(), false);
3425
3426 v8::TryCatch try_catch;
3427 result = script_define->Run();
3428 CHECK(try_catch.HasCaught());
3429 String::AsciiValue exception_value(try_catch.Exception());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003430 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
ager@chromium.org5c838252010-02-19 08:53:10 +00003431}
3432
3433
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003434static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
3435 char const* name) {
3436 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
3437}
ager@chromium.org5c838252010-02-19 08:53:10 +00003438
3439
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003440THREADED_TEST(DefineAPIAccessorOnObject) {
3441 v8::HandleScope scope;
3442 Local<ObjectTemplate> templ = ObjectTemplate::New();
3443 LocalContext context;
3444
3445 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3446 CompileRun("var obj2 = {};");
3447
3448 CHECK(CompileRun("obj1.x")->IsUndefined());
3449 CHECK(CompileRun("obj2.x")->IsUndefined());
3450
3451 CHECK(GetGlobalProperty(&context, "obj1")->
3452 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3453
3454 ExpectString("obj1.x", "x");
3455 CHECK(CompileRun("obj2.x")->IsUndefined());
3456
3457 CHECK(GetGlobalProperty(&context, "obj2")->
3458 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3459
3460 ExpectString("obj1.x", "x");
3461 ExpectString("obj2.x", "x");
3462
3463 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3464 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3465
3466 CompileRun("Object.defineProperty(obj1, 'x',"
3467 "{ get: function() { return 'y'; }, configurable: true })");
3468
3469 ExpectString("obj1.x", "y");
3470 ExpectString("obj2.x", "x");
3471
3472 CompileRun("Object.defineProperty(obj2, 'x',"
3473 "{ get: function() { return 'y'; }, configurable: true })");
3474
3475 ExpectString("obj1.x", "y");
3476 ExpectString("obj2.x", "y");
3477
3478 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3479 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3480
3481 CHECK(GetGlobalProperty(&context, "obj1")->
3482 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3483 CHECK(GetGlobalProperty(&context, "obj2")->
3484 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3485
3486 ExpectString("obj1.x", "x");
3487 ExpectString("obj2.x", "x");
3488
3489 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3490 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3491
3492 // Define getters/setters, but now make them not configurable.
3493 CompileRun("Object.defineProperty(obj1, 'x',"
3494 "{ get: function() { return 'z'; }, configurable: false })");
3495 CompileRun("Object.defineProperty(obj2, 'x',"
3496 "{ get: function() { return 'z'; }, configurable: false })");
3497
3498 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3499 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3500
3501 ExpectString("obj1.x", "z");
3502 ExpectString("obj2.x", "z");
3503
3504 CHECK(!GetGlobalProperty(&context, "obj1")->
3505 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3506 CHECK(!GetGlobalProperty(&context, "obj2")->
3507 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3508
3509 ExpectString("obj1.x", "z");
3510 ExpectString("obj2.x", "z");
3511}
3512
3513
3514THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
3515 v8::HandleScope scope;
3516 Local<ObjectTemplate> templ = ObjectTemplate::New();
3517 LocalContext context;
3518
3519 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3520 CompileRun("var obj2 = {};");
3521
3522 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3523 v8_str("x"),
3524 GetXValue, NULL,
3525 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3526 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3527 v8_str("x"),
3528 GetXValue, NULL,
3529 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3530
3531 ExpectString("obj1.x", "x");
3532 ExpectString("obj2.x", "x");
3533
3534 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3535 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3536
3537 CHECK(!GetGlobalProperty(&context, "obj1")->
3538 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3539 CHECK(!GetGlobalProperty(&context, "obj2")->
3540 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3541
3542 {
3543 v8::TryCatch try_catch;
3544 CompileRun("Object.defineProperty(obj1, 'x',"
3545 "{get: function() { return 'func'; }})");
3546 CHECK(try_catch.HasCaught());
3547 String::AsciiValue exception_value(try_catch.Exception());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003548 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003549 }
3550 {
3551 v8::TryCatch try_catch;
3552 CompileRun("Object.defineProperty(obj2, 'x',"
3553 "{get: function() { return 'func'; }})");
3554 CHECK(try_catch.HasCaught());
3555 String::AsciiValue exception_value(try_catch.Exception());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003556 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003557 }
3558}
3559
3560
3561static v8::Handle<Value> Get239Value(Local<String> name,
3562 const AccessorInfo& info) {
3563 ApiTestFuzzer::Fuzz();
3564 CHECK_EQ(info.Data(), v8_str("donut"));
3565 CHECK_EQ(name, v8_str("239"));
3566 return name;
3567}
3568
3569
3570THREADED_TEST(ElementAPIAccessor) {
3571 v8::HandleScope scope;
3572 Local<ObjectTemplate> templ = ObjectTemplate::New();
3573 LocalContext context;
3574
3575 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3576 CompileRun("var obj2 = {};");
3577
3578 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3579 v8_str("239"),
3580 Get239Value, NULL,
3581 v8_str("donut")));
3582 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3583 v8_str("239"),
3584 Get239Value, NULL,
3585 v8_str("donut")));
3586
3587 ExpectString("obj1[239]", "239");
3588 ExpectString("obj2[239]", "239");
3589 ExpectString("obj1['239']", "239");
3590 ExpectString("obj2['239']", "239");
3591}
3592
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003593
3594v8::Persistent<Value> xValue;
3595
3596
3597static void SetXValue(Local<String> name,
3598 Local<Value> value,
3599 const AccessorInfo& info) {
3600 CHECK_EQ(value, v8_num(4));
3601 CHECK_EQ(info.Data(), v8_str("donut"));
3602 CHECK_EQ(name, v8_str("x"));
3603 CHECK(xValue.IsEmpty());
3604 xValue = v8::Persistent<Value>::New(value);
3605}
3606
3607
3608THREADED_TEST(SimplePropertyWrite) {
3609 v8::HandleScope scope;
3610 Local<ObjectTemplate> templ = ObjectTemplate::New();
3611 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
3612 LocalContext context;
3613 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3614 Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
3615 for (int i = 0; i < 10; i++) {
3616 CHECK(xValue.IsEmpty());
3617 script->Run();
3618 CHECK_EQ(v8_num(4), xValue);
3619 xValue.Dispose();
3620 xValue = v8::Persistent<Value>();
3621 }
3622}
3623
3624
3625static v8::Handle<Value> XPropertyGetter(Local<String> property,
3626 const AccessorInfo& info) {
3627 ApiTestFuzzer::Fuzz();
3628 CHECK(info.Data()->IsUndefined());
3629 return property;
3630}
3631
3632
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003633THREADED_TEST(NamedInterceptorPropertyRead) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003634 v8::HandleScope scope;
3635 Local<ObjectTemplate> templ = ObjectTemplate::New();
3636 templ->SetNamedPropertyHandler(XPropertyGetter);
3637 LocalContext context;
3638 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3639 Local<Script> script = Script::Compile(v8_str("obj.x"));
3640 for (int i = 0; i < 10; i++) {
3641 Local<Value> result = script->Run();
3642 CHECK_EQ(result, v8_str("x"));
3643 }
3644}
3645
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003646
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00003647THREADED_TEST(NamedInterceptorDictionaryIC) {
3648 v8::HandleScope scope;
3649 Local<ObjectTemplate> templ = ObjectTemplate::New();
3650 templ->SetNamedPropertyHandler(XPropertyGetter);
3651 LocalContext context;
3652 // Create an object with a named interceptor.
3653 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
3654 Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
3655 for (int i = 0; i < 10; i++) {
3656 Local<Value> result = script->Run();
3657 CHECK_EQ(result, v8_str("x"));
3658 }
3659 // Create a slow case object and a function accessing a property in
3660 // that slow case object (with dictionary probing in generated
3661 // code). Then force object with a named interceptor into slow-case,
3662 // pass it to the function, and check that the interceptor is called
3663 // instead of accessing the local property.
3664 Local<Value> result =
3665 CompileRun("function get_x(o) { return o.x; };"
3666 "var obj = { x : 42, y : 0 };"
3667 "delete obj.y;"
3668 "for (var i = 0; i < 10; i++) get_x(obj);"
3669 "interceptor_obj.x = 42;"
3670 "interceptor_obj.y = 10;"
3671 "delete interceptor_obj.y;"
3672 "get_x(interceptor_obj)");
3673 CHECK_EQ(result, v8_str("x"));
3674}
3675
3676
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003677THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
3678 v8::HandleScope scope;
3679
3680 v8::Persistent<Context> context1 = Context::New();
3681
3682 context1->Enter();
3683 Local<ObjectTemplate> templ = ObjectTemplate::New();
3684 templ->SetNamedPropertyHandler(XPropertyGetter);
3685 // Create an object with a named interceptor.
3686 v8::Local<v8::Object> object = templ->NewInstance();
3687 context1->Global()->Set(v8_str("interceptor_obj"), object);
3688
3689 // Force the object into the slow case.
3690 CompileRun("interceptor_obj.y = 0;"
3691 "delete interceptor_obj.y;");
3692 context1->Exit();
3693
3694 {
3695 // Introduce the object into a different context.
3696 // Repeat named loads to exercise ICs.
3697 LocalContext context2;
3698 context2->Global()->Set(v8_str("interceptor_obj"), object);
3699 Local<Value> result =
3700 CompileRun("function get_x(o) { return o.x; }"
3701 "interceptor_obj.x = 42;"
3702 "for (var i=0; i != 10; i++) {"
3703 " get_x(interceptor_obj);"
3704 "}"
3705 "get_x(interceptor_obj)");
3706 // Check that the interceptor was actually invoked.
3707 CHECK_EQ(result, v8_str("x"));
3708 }
3709
3710 // Return to the original context and force some object to the slow case
3711 // to cause the NormalizedMapCache to verify.
3712 context1->Enter();
3713 CompileRun("var obj = { x : 0 }; delete obj.x;");
3714 context1->Exit();
3715
3716 context1.Dispose();
3717}
3718
3719
ager@chromium.org5c838252010-02-19 08:53:10 +00003720static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
3721 const AccessorInfo& info) {
3722 // Set x on the prototype object and do not handle the get request.
3723 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003724 proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
ager@chromium.org5c838252010-02-19 08:53:10 +00003725 return v8::Handle<Value>();
3726}
3727
3728
3729// This is a regression test for http://crbug.com/20104. Map
3730// transitions should not interfere with post interceptor lookup.
3731THREADED_TEST(NamedInterceptorMapTransitionRead) {
3732 v8::HandleScope scope;
3733 Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
3734 Local<v8::ObjectTemplate> instance_template
3735 = function_template->InstanceTemplate();
3736 instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
3737 LocalContext context;
3738 context->Global()->Set(v8_str("F"), function_template->GetFunction());
3739 // Create an instance of F and introduce a map transition for x.
3740 CompileRun("var o = new F(); o.x = 23;");
3741 // Create an instance of F and invoke the getter. The result should be 23.
3742 Local<Value> result = CompileRun("o = new F(); o.x");
3743 CHECK_EQ(result->Int32Value(), 23);
3744}
3745
3746
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003747static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
3748 const AccessorInfo& info) {
3749 ApiTestFuzzer::Fuzz();
3750 if (index == 37) {
3751 return v8::Handle<Value>(v8_num(625));
3752 }
3753 return v8::Handle<Value>();
3754}
3755
3756
3757static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
3758 Local<Value> value,
3759 const AccessorInfo& info) {
3760 ApiTestFuzzer::Fuzz();
3761 if (index == 39) {
3762 return value;
3763 }
3764 return v8::Handle<Value>();
3765}
3766
3767
3768THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
3769 v8::HandleScope scope;
3770 Local<ObjectTemplate> templ = ObjectTemplate::New();
3771 templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
3772 IndexedPropertySetter);
3773 LocalContext context;
3774 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3775 Local<Script> getter_script = Script::Compile(v8_str(
3776 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
3777 Local<Script> setter_script = Script::Compile(v8_str(
3778 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
3779 "obj[17] = 23;"
3780 "obj.foo;"));
3781 Local<Script> interceptor_setter_script = Script::Compile(v8_str(
3782 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
3783 "obj[39] = 47;"
3784 "obj.foo;")); // This setter should not run, due to the interceptor.
3785 Local<Script> interceptor_getter_script = Script::Compile(v8_str(
3786 "obj[37];"));
3787 Local<Value> result = getter_script->Run();
3788 CHECK_EQ(v8_num(5), result);
3789 result = setter_script->Run();
3790 CHECK_EQ(v8_num(23), result);
3791 result = interceptor_setter_script->Run();
3792 CHECK_EQ(v8_num(23), result);
3793 result = interceptor_getter_script->Run();
3794 CHECK_EQ(v8_num(625), result);
3795}
3796
3797
ricow@chromium.org9fa09672011-07-25 11:05:35 +00003798static v8::Handle<Value> UnboxedDoubleIndexedPropertyGetter(
3799 uint32_t index,
3800 const AccessorInfo& info) {
3801 ApiTestFuzzer::Fuzz();
3802 if (index < 25) {
3803 return v8::Handle<Value>(v8_num(index));
3804 }
3805 return v8::Handle<Value>();
3806}
3807
3808
3809static v8::Handle<Value> UnboxedDoubleIndexedPropertySetter(
3810 uint32_t index,
3811 Local<Value> value,
3812 const AccessorInfo& info) {
3813 ApiTestFuzzer::Fuzz();
3814 if (index < 25) {
3815 return v8::Handle<Value>(v8_num(index));
3816 }
3817 return v8::Handle<Value>();
3818}
3819
3820
3821Handle<v8::Array> UnboxedDoubleIndexedPropertyEnumerator(
3822 const AccessorInfo& info) {
3823 // Force the list of returned keys to be stored in a FastDoubleArray.
3824 Local<Script> indexed_property_names_script = Script::Compile(v8_str(
3825 "keys = new Array(); keys[125000] = 1;"
3826 "for(i = 0; i < 80000; i++) { keys[i] = i; };"
3827 "keys.length = 25; keys;"));
3828 Local<Value> result = indexed_property_names_script->Run();
3829 return Local<v8::Array>(::v8::Array::Cast(*result));
3830}
3831
3832
3833// Make sure that the the interceptor code in the runtime properly handles
3834// merging property name lists for double-array-backed arrays.
3835THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
3836 v8::HandleScope scope;
3837 Local<ObjectTemplate> templ = ObjectTemplate::New();
3838 templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
3839 UnboxedDoubleIndexedPropertySetter,
3840 0,
3841 0,
3842 UnboxedDoubleIndexedPropertyEnumerator);
3843 LocalContext context;
3844 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3845 // When obj is created, force it to be Stored in a FastDoubleArray.
3846 Local<Script> create_unboxed_double_script = Script::Compile(v8_str(
3847 "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
3848 "key_count = 0; "
3849 "for (x in obj) {key_count++;};"
3850 "obj;"));
3851 Local<Value> result = create_unboxed_double_script->Run();
3852 CHECK(result->ToObject()->HasRealIndexedProperty(2000));
3853 Local<Script> key_count_check = Script::Compile(v8_str(
3854 "key_count;"));
3855 result = key_count_check->Run();
3856 CHECK_EQ(v8_num(40013), result);
3857}
3858
3859
rossberg@chromium.org28a37082011-08-22 11:03:23 +00003860Handle<v8::Array> NonStrictArgsIndexedPropertyEnumerator(
3861 const AccessorInfo& info) {
3862 // Force the list of returned keys to be stored in a Arguments object.
3863 Local<Script> indexed_property_names_script = Script::Compile(v8_str(
3864 "function f(w,x) {"
3865 " return arguments;"
3866 "}"
3867 "keys = f(0, 1, 2, 3);"
3868 "keys;"));
3869 Local<Value> result = indexed_property_names_script->Run();
3870 return Local<v8::Array>(static_cast<v8::Array*>(::v8::Object::Cast(*result)));
3871}
3872
3873
3874static v8::Handle<Value> NonStrictIndexedPropertyGetter(
3875 uint32_t index,
3876 const AccessorInfo& info) {
3877 ApiTestFuzzer::Fuzz();
3878 if (index < 4) {
3879 return v8::Handle<Value>(v8_num(index));
3880 }
3881 return v8::Handle<Value>();
3882}
3883
3884
3885// Make sure that the the interceptor code in the runtime properly handles
3886// merging property name lists for non-string arguments arrays.
3887THREADED_TEST(IndexedInterceptorNonStrictArgsWithIndexedAccessor) {
3888 v8::HandleScope scope;
3889 Local<ObjectTemplate> templ = ObjectTemplate::New();
3890 templ->SetIndexedPropertyHandler(NonStrictIndexedPropertyGetter,
3891 0,
3892 0,
3893 0,
3894 NonStrictArgsIndexedPropertyEnumerator);
3895 LocalContext context;
3896 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3897 Local<Script> create_args_script =
3898 Script::Compile(v8_str(
3899 "var key_count = 0;"
3900 "for (x in obj) {key_count++;} key_count;"));
3901 Local<Value> result = create_args_script->Run();
3902 CHECK_EQ(v8_num(4), result);
3903}
3904
3905
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00003906static v8::Handle<Value> IdentityIndexedPropertyGetter(
3907 uint32_t index,
3908 const AccessorInfo& info) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003909 return v8::Integer::NewFromUnsigned(index);
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00003910}
3911
3912
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003913THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
3914 v8::HandleScope scope;
3915 Local<ObjectTemplate> templ = ObjectTemplate::New();
3916 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3917
3918 LocalContext context;
3919 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3920
3921 // Check fast object case.
3922 const char* fast_case_code =
3923 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
3924 ExpectString(fast_case_code, "0");
3925
3926 // Check slow case.
3927 const char* slow_case_code =
3928 "obj.x = 1; delete obj.x;"
3929 "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
3930 ExpectString(slow_case_code, "1");
3931}
3932
3933
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00003934THREADED_TEST(IndexedInterceptorWithNoSetter) {
3935 v8::HandleScope scope;
3936 Local<ObjectTemplate> templ = ObjectTemplate::New();
3937 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3938
3939 LocalContext context;
3940 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3941
3942 const char* code =
3943 "try {"
3944 " obj[0] = 239;"
3945 " for (var i = 0; i < 100; i++) {"
3946 " var v = obj[0];"
3947 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
3948 " }"
3949 " 'PASSED'"
3950 "} catch(e) {"
3951 " e"
3952 "}";
3953 ExpectString(code, "PASSED");
3954}
3955
3956
ager@chromium.org5c838252010-02-19 08:53:10 +00003957THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
3958 v8::HandleScope scope;
3959 Local<ObjectTemplate> templ = ObjectTemplate::New();
3960 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3961
3962 LocalContext context;
3963 Local<v8::Object> obj = templ->NewInstance();
3964 obj->TurnOnAccessCheck();
3965 context->Global()->Set(v8_str("obj"), obj);
3966
3967 const char* code =
3968 "try {"
3969 " for (var i = 0; i < 100; i++) {"
3970 " var v = obj[0];"
3971 " if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
3972 " }"
3973 " 'PASSED'"
3974 "} catch(e) {"
3975 " e"
3976 "}";
3977 ExpectString(code, "PASSED");
3978}
3979
3980
3981THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
3982 i::FLAG_allow_natives_syntax = true;
3983 v8::HandleScope scope;
3984 Local<ObjectTemplate> templ = ObjectTemplate::New();
3985 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3986
3987 LocalContext context;
3988 Local<v8::Object> obj = templ->NewInstance();
3989 context->Global()->Set(v8_str("obj"), obj);
3990
3991 const char* code =
3992 "try {"
3993 " for (var i = 0; i < 100; i++) {"
3994 " var expected = i;"
3995 " if (i == 5) {"
3996 " %EnableAccessChecks(obj);"
3997 " expected = undefined;"
3998 " }"
3999 " var v = obj[i];"
4000 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4001 " if (i == 5) %DisableAccessChecks(obj);"
4002 " }"
4003 " 'PASSED'"
4004 "} catch(e) {"
4005 " e"
4006 "}";
4007 ExpectString(code, "PASSED");
4008}
4009
4010
4011THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
4012 v8::HandleScope scope;
4013 Local<ObjectTemplate> templ = ObjectTemplate::New();
4014 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4015
4016 LocalContext context;
4017 Local<v8::Object> obj = templ->NewInstance();
4018 context->Global()->Set(v8_str("obj"), obj);
4019
4020 const char* code =
4021 "try {"
4022 " for (var i = 0; i < 100; i++) {"
4023 " var v = obj[i];"
4024 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
4025 " }"
4026 " 'PASSED'"
4027 "} catch(e) {"
4028 " e"
4029 "}";
4030 ExpectString(code, "PASSED");
4031}
4032
4033
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00004034THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
4035 v8::HandleScope scope;
4036 Local<ObjectTemplate> templ = ObjectTemplate::New();
4037 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4038
4039 LocalContext context;
4040 Local<v8::Object> obj = templ->NewInstance();
4041 context->Global()->Set(v8_str("obj"), obj);
4042
4043 const char* code =
4044 "try {"
4045 " for (var i = 0; i < 100; i++) {"
4046 " var expected = i;"
4047 " var key = i;"
4048 " if (i == 25) {"
4049 " key = -1;"
4050 " expected = undefined;"
4051 " }"
4052 " if (i == 50) {"
4053 " /* probe minimal Smi number on 32-bit platforms */"
4054 " key = -(1 << 30);"
4055 " expected = undefined;"
4056 " }"
4057 " if (i == 75) {"
4058 " /* probe minimal Smi number on 64-bit platforms */"
4059 " key = 1 << 31;"
4060 " expected = undefined;"
4061 " }"
4062 " var v = obj[key];"
4063 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4064 " }"
4065 " 'PASSED'"
4066 "} catch(e) {"
4067 " e"
4068 "}";
4069 ExpectString(code, "PASSED");
4070}
4071
4072
ager@chromium.org5c838252010-02-19 08:53:10 +00004073THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
4074 v8::HandleScope scope;
4075 Local<ObjectTemplate> templ = ObjectTemplate::New();
4076 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4077
4078 LocalContext context;
4079 Local<v8::Object> obj = templ->NewInstance();
4080 context->Global()->Set(v8_str("obj"), obj);
4081
4082 const char* code =
4083 "try {"
4084 " for (var i = 0; i < 100; i++) {"
4085 " var expected = i;"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00004086 " var key = i;"
ager@chromium.org5c838252010-02-19 08:53:10 +00004087 " if (i == 50) {"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00004088 " key = 'foobar';"
ager@chromium.org5c838252010-02-19 08:53:10 +00004089 " expected = undefined;"
4090 " }"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00004091 " var v = obj[key];"
ager@chromium.org5c838252010-02-19 08:53:10 +00004092 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4093 " }"
4094 " 'PASSED'"
4095 "} catch(e) {"
4096 " e"
4097 "}";
4098 ExpectString(code, "PASSED");
4099}
4100
4101
4102THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
4103 v8::HandleScope scope;
4104 Local<ObjectTemplate> templ = ObjectTemplate::New();
4105 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4106
4107 LocalContext context;
4108 Local<v8::Object> obj = templ->NewInstance();
4109 context->Global()->Set(v8_str("obj"), obj);
4110
4111 const char* code =
4112 "var original = obj;"
4113 "try {"
4114 " for (var i = 0; i < 100; i++) {"
4115 " var expected = i;"
4116 " if (i == 50) {"
4117 " obj = {50: 'foobar'};"
4118 " expected = 'foobar';"
4119 " }"
4120 " var v = obj[i];"
4121 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4122 " if (i == 50) obj = original;"
4123 " }"
4124 " 'PASSED'"
4125 "} catch(e) {"
4126 " e"
4127 "}";
4128 ExpectString(code, "PASSED");
4129}
4130
4131
4132THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
4133 v8::HandleScope scope;
4134 Local<ObjectTemplate> templ = ObjectTemplate::New();
4135 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4136
4137 LocalContext context;
4138 Local<v8::Object> obj = templ->NewInstance();
4139 context->Global()->Set(v8_str("obj"), obj);
4140
4141 const char* code =
4142 "var original = obj;"
4143 "try {"
4144 " for (var i = 0; i < 100; i++) {"
4145 " var expected = i;"
4146 " if (i == 5) {"
4147 " obj = 239;"
4148 " expected = undefined;"
4149 " }"
4150 " var v = obj[i];"
4151 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4152 " if (i == 5) obj = original;"
4153 " }"
4154 " 'PASSED'"
4155 "} catch(e) {"
4156 " e"
4157 "}";
4158 ExpectString(code, "PASSED");
4159}
4160
4161
4162THREADED_TEST(IndexedInterceptorOnProto) {
4163 v8::HandleScope scope;
4164 Local<ObjectTemplate> templ = ObjectTemplate::New();
4165 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4166
4167 LocalContext context;
4168 Local<v8::Object> obj = templ->NewInstance();
4169 context->Global()->Set(v8_str("obj"), obj);
4170
4171 const char* code =
4172 "var o = {__proto__: obj};"
4173 "try {"
4174 " for (var i = 0; i < 100; i++) {"
4175 " var v = o[i];"
4176 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
4177 " }"
4178 " 'PASSED'"
4179 "} catch(e) {"
4180 " e"
4181 "}";
4182 ExpectString(code, "PASSED");
4183}
4184
4185
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004186THREADED_TEST(MultiContexts) {
4187 v8::HandleScope scope;
4188 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
4189 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
4190
4191 Local<String> password = v8_str("Password");
4192
4193 // Create an environment
4194 LocalContext context0(0, templ);
4195 context0->SetSecurityToken(password);
4196 v8::Handle<v8::Object> global0 = context0->Global();
4197 global0->Set(v8_str("custom"), v8_num(1234));
4198 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
4199
4200 // Create an independent environment
4201 LocalContext context1(0, templ);
4202 context1->SetSecurityToken(password);
4203 v8::Handle<v8::Object> global1 = context1->Global();
4204 global1->Set(v8_str("custom"), v8_num(1234));
4205 CHECK_NE(global0, global1);
4206 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
4207 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
4208
4209 // Now create a new context with the old global
4210 LocalContext context2(0, templ, global1);
4211 context2->SetSecurityToken(password);
4212 v8::Handle<v8::Object> global2 = context2->Global();
4213 CHECK_EQ(global1, global2);
4214 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
4215 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
4216}
4217
4218
4219THREADED_TEST(FunctionPrototypeAcrossContexts) {
4220 // Make sure that functions created by cloning boilerplates cannot
4221 // communicate through their __proto__ field.
4222
4223 v8::HandleScope scope;
4224
4225 LocalContext env0;
4226 v8::Handle<v8::Object> global0 =
4227 env0->Global();
4228 v8::Handle<v8::Object> object0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004229 global0->Get(v8_str("Object")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004230 v8::Handle<v8::Object> tostring0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004231 object0->Get(v8_str("toString")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004232 v8::Handle<v8::Object> proto0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004233 tostring0->Get(v8_str("__proto__")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004234 proto0->Set(v8_str("custom"), v8_num(1234));
4235
4236 LocalContext env1;
4237 v8::Handle<v8::Object> global1 =
4238 env1->Global();
4239 v8::Handle<v8::Object> object1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004240 global1->Get(v8_str("Object")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004241 v8::Handle<v8::Object> tostring1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004242 object1->Get(v8_str("toString")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004243 v8::Handle<v8::Object> proto1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004244 tostring1->Get(v8_str("__proto__")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004245 CHECK(!proto1->Has(v8_str("custom")));
4246}
4247
4248
4249THREADED_TEST(Regress892105) {
4250 // Make sure that object and array literals created by cloning
4251 // boilerplates cannot communicate through their __proto__
4252 // field. This is rather difficult to check, but we try to add stuff
4253 // to Object.prototype and Array.prototype and create a new
4254 // environment. This should succeed.
4255
4256 v8::HandleScope scope;
4257
4258 Local<String> source = v8_str("Object.prototype.obj = 1234;"
4259 "Array.prototype.arr = 4567;"
4260 "8901");
4261
4262 LocalContext env0;
4263 Local<Script> script0 = Script::Compile(source);
4264 CHECK_EQ(8901.0, script0->Run()->NumberValue());
4265
4266 LocalContext env1;
4267 Local<Script> script1 = Script::Compile(source);
4268 CHECK_EQ(8901.0, script1->Run()->NumberValue());
4269}
4270
4271
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004272THREADED_TEST(UndetectableObject) {
4273 v8::HandleScope scope;
4274 LocalContext env;
4275
4276 Local<v8::FunctionTemplate> desc =
4277 v8::FunctionTemplate::New(0, v8::Handle<Value>());
4278 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4279
4280 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4281 env->Global()->Set(v8_str("undetectable"), obj);
4282
4283 ExpectString("undetectable.toString()", "[object Object]");
4284 ExpectString("typeof undetectable", "undefined");
4285 ExpectString("typeof(undetectable)", "undefined");
4286 ExpectBoolean("typeof undetectable == 'undefined'", true);
4287 ExpectBoolean("typeof undetectable == 'object'", false);
4288 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
4289 ExpectBoolean("!undetectable", true);
4290
4291 ExpectObject("true&&undetectable", obj);
4292 ExpectBoolean("false&&undetectable", false);
4293 ExpectBoolean("true||undetectable", true);
4294 ExpectObject("false||undetectable", obj);
4295
4296 ExpectObject("undetectable&&true", obj);
4297 ExpectObject("undetectable&&false", obj);
4298 ExpectBoolean("undetectable||true", true);
4299 ExpectBoolean("undetectable||false", false);
4300
4301 ExpectBoolean("undetectable==null", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004302 ExpectBoolean("null==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004303 ExpectBoolean("undetectable==undefined", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004304 ExpectBoolean("undefined==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004305 ExpectBoolean("undetectable==undetectable", true);
4306
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004307
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004308 ExpectBoolean("undetectable===null", false);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004309 ExpectBoolean("null===undetectable", false);
4310 ExpectBoolean("undetectable===undefined", false);
4311 ExpectBoolean("undefined===undetectable", false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004312 ExpectBoolean("undetectable===undetectable", true);
4313}
4314
4315
ager@chromium.org04921a82011-06-27 13:21:41 +00004316THREADED_TEST(VoidLiteral) {
4317 v8::HandleScope scope;
4318 LocalContext env;
4319
4320 Local<v8::FunctionTemplate> desc =
4321 v8::FunctionTemplate::New(0, v8::Handle<Value>());
4322 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4323
4324 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4325 env->Global()->Set(v8_str("undetectable"), obj);
4326
4327 ExpectBoolean("undefined == void 0", true);
4328 ExpectBoolean("undetectable == void 0", true);
4329 ExpectBoolean("null == void 0", true);
4330 ExpectBoolean("undefined === void 0", true);
4331 ExpectBoolean("undetectable === void 0", false);
4332 ExpectBoolean("null === void 0", false);
4333
4334 ExpectBoolean("void 0 == undefined", true);
4335 ExpectBoolean("void 0 == undetectable", true);
4336 ExpectBoolean("void 0 == null", true);
4337 ExpectBoolean("void 0 === undefined", true);
4338 ExpectBoolean("void 0 === undetectable", false);
4339 ExpectBoolean("void 0 === null", false);
4340
4341 ExpectString("(function() {"
4342 " try {"
4343 " return x === void 0;"
4344 " } catch(e) {"
4345 " return e.toString();"
4346 " }"
4347 "})()",
4348 "ReferenceError: x is not defined");
4349 ExpectString("(function() {"
4350 " try {"
4351 " return void 0 === x;"
4352 " } catch(e) {"
4353 " return e.toString();"
4354 " }"
4355 "})()",
4356 "ReferenceError: x is not defined");
4357}
4358
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00004359
4360THREADED_TEST(ExtensibleOnUndetectable) {
4361 v8::HandleScope scope;
4362 LocalContext env;
4363
4364 Local<v8::FunctionTemplate> desc =
4365 v8::FunctionTemplate::New(0, v8::Handle<Value>());
4366 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4367
4368 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4369 env->Global()->Set(v8_str("undetectable"), obj);
4370
4371 Local<String> source = v8_str("undetectable.x = 42;"
4372 "undetectable.x");
4373
4374 Local<Script> script = Script::Compile(source);
4375
4376 CHECK_EQ(v8::Integer::New(42), script->Run());
4377
4378 ExpectBoolean("Object.isExtensible(undetectable)", true);
4379
4380 source = v8_str("Object.preventExtensions(undetectable);");
4381 script = Script::Compile(source);
4382 script->Run();
4383 ExpectBoolean("Object.isExtensible(undetectable)", false);
4384
4385 source = v8_str("undetectable.y = 2000;");
4386 script = Script::Compile(source);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004387 Local<Value> result(script->Run());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004388 ExpectBoolean("undetectable.y == undefined", true);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00004389}
4390
4391
4392
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004393THREADED_TEST(UndetectableString) {
4394 v8::HandleScope scope;
4395 LocalContext env;
4396
4397 Local<String> obj = String::NewUndetectable("foo");
4398 env->Global()->Set(v8_str("undetectable"), obj);
4399
4400 ExpectString("undetectable", "foo");
4401 ExpectString("typeof undetectable", "undefined");
4402 ExpectString("typeof(undetectable)", "undefined");
4403 ExpectBoolean("typeof undetectable == 'undefined'", true);
4404 ExpectBoolean("typeof undetectable == 'string'", false);
4405 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
4406 ExpectBoolean("!undetectable", true);
4407
4408 ExpectObject("true&&undetectable", obj);
4409 ExpectBoolean("false&&undetectable", false);
4410 ExpectBoolean("true||undetectable", true);
4411 ExpectObject("false||undetectable", obj);
4412
4413 ExpectObject("undetectable&&true", obj);
4414 ExpectObject("undetectable&&false", obj);
4415 ExpectBoolean("undetectable||true", true);
4416 ExpectBoolean("undetectable||false", false);
4417
4418 ExpectBoolean("undetectable==null", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004419 ExpectBoolean("null==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004420 ExpectBoolean("undetectable==undefined", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004421 ExpectBoolean("undefined==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004422 ExpectBoolean("undetectable==undetectable", true);
4423
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004424
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004425 ExpectBoolean("undetectable===null", false);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004426 ExpectBoolean("null===undetectable", false);
4427 ExpectBoolean("undetectable===undefined", false);
4428 ExpectBoolean("undefined===undetectable", false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004429 ExpectBoolean("undetectable===undetectable", true);
4430}
4431
4432
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004433TEST(UndetectableOptimized) {
4434 i::FLAG_allow_natives_syntax = true;
4435 v8::HandleScope scope;
4436 LocalContext env;
4437
4438 Local<String> obj = String::NewUndetectable("foo");
4439 env->Global()->Set(v8_str("undetectable"), obj);
4440 env->Global()->Set(v8_str("detectable"), v8_str("bar"));
4441
4442 ExpectString(
4443 "function testBranch() {"
4444 " if (!%_IsUndetectableObject(undetectable)) throw 1;"
4445 " if (%_IsUndetectableObject(detectable)) throw 2;"
4446 "}\n"
4447 "function testBool() {"
4448 " var b1 = !%_IsUndetectableObject(undetectable);"
4449 " var b2 = %_IsUndetectableObject(detectable);"
4450 " if (b1) throw 3;"
4451 " if (b2) throw 4;"
4452 " return b1 == b2;"
4453 "}\n"
4454 "%OptimizeFunctionOnNextCall(testBranch);"
4455 "%OptimizeFunctionOnNextCall(testBool);"
4456 "for (var i = 0; i < 10; i++) {"
4457 " testBranch();"
4458 " testBool();"
4459 "}\n"
4460 "\"PASS\"",
4461 "PASS");
4462}
4463
4464
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004465template <typename T> static void USE(T) { }
4466
4467
4468// This test is not intended to be run, just type checked.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004469static inline void PersistentHandles() {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004470 USE(PersistentHandles);
4471 Local<String> str = v8_str("foo");
4472 v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
4473 USE(p_str);
4474 Local<Script> scr = Script::Compile(v8_str(""));
4475 v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
4476 USE(p_scr);
4477 Local<ObjectTemplate> templ = ObjectTemplate::New();
4478 v8::Persistent<ObjectTemplate> p_templ =
4479 v8::Persistent<ObjectTemplate>::New(templ);
4480 USE(p_templ);
4481}
4482
4483
4484static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
4485 ApiTestFuzzer::Fuzz();
4486 return v8::Undefined();
4487}
4488
4489
4490THREADED_TEST(GlobalObjectTemplate) {
4491 v8::HandleScope handle_scope;
4492 Local<ObjectTemplate> global_template = ObjectTemplate::New();
4493 global_template->Set(v8_str("JSNI_Log"),
4494 v8::FunctionTemplate::New(HandleLogDelegator));
4495 v8::Persistent<Context> context = Context::New(0, global_template);
4496 Context::Scope context_scope(context);
4497 Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
4498 context.Dispose();
4499}
4500
4501
4502static const char* kSimpleExtensionSource =
4503 "function Foo() {"
4504 " return 4;"
4505 "}";
4506
4507
4508THREADED_TEST(SimpleExtensions) {
4509 v8::HandleScope handle_scope;
4510 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
4511 const char* extension_names[] = { "simpletest" };
4512 v8::ExtensionConfiguration extensions(1, extension_names);
4513 v8::Handle<Context> context = Context::New(&extensions);
4514 Context::Scope lock(context);
4515 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
4516 CHECK_EQ(result, v8::Integer::New(4));
4517}
4518
4519
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004520static const char* kEmbeddedExtensionSource =
4521 "function Ret54321(){return 54321;}~~@@$"
4522 "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
4523static const int kEmbeddedExtensionSourceValidLen = 34;
4524
4525
4526THREADED_TEST(ExtensionMissingSourceLength) {
4527 v8::HandleScope handle_scope;
4528 v8::RegisterExtension(new Extension("srclentest_fail",
4529 kEmbeddedExtensionSource));
4530 const char* extension_names[] = { "srclentest_fail" };
4531 v8::ExtensionConfiguration extensions(1, extension_names);
4532 v8::Handle<Context> context = Context::New(&extensions);
4533 CHECK_EQ(0, *context);
4534}
4535
4536
4537THREADED_TEST(ExtensionWithSourceLength) {
4538 for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
4539 source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
4540 v8::HandleScope handle_scope;
4541 i::ScopedVector<char> extension_name(32);
4542 i::OS::SNPrintF(extension_name, "ext #%d", source_len);
4543 v8::RegisterExtension(new Extension(extension_name.start(),
4544 kEmbeddedExtensionSource, 0, 0,
4545 source_len));
4546 const char* extension_names[1] = { extension_name.start() };
4547 v8::ExtensionConfiguration extensions(1, extension_names);
4548 v8::Handle<Context> context = Context::New(&extensions);
4549 if (source_len == kEmbeddedExtensionSourceValidLen) {
4550 Context::Scope lock(context);
4551 v8::Handle<Value> result = Script::Compile(v8_str("Ret54321()"))->Run();
4552 CHECK_EQ(v8::Integer::New(54321), result);
4553 } else {
4554 // Anything but exactly the right length should fail to compile.
4555 CHECK_EQ(0, *context);
4556 }
4557 }
4558}
4559
4560
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004561static const char* kEvalExtensionSource1 =
4562 "function UseEval1() {"
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004563 " var x = 42;"
4564 " return eval('x');"
4565 "}";
4566
4567
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004568static const char* kEvalExtensionSource2 =
4569 "(function() {"
4570 " var x = 42;"
4571 " function e() {"
4572 " return eval('x');"
4573 " }"
4574 " this.UseEval2 = e;"
4575 "})()";
4576
4577
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004578THREADED_TEST(UseEvalFromExtension) {
4579 v8::HandleScope handle_scope;
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004580 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
4581 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
4582 const char* extension_names[] = { "evaltest1", "evaltest2" };
4583 v8::ExtensionConfiguration extensions(2, extension_names);
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004584 v8::Handle<Context> context = Context::New(&extensions);
4585 Context::Scope lock(context);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004586 v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
4587 CHECK_EQ(result, v8::Integer::New(42));
4588 result = Script::Compile(v8_str("UseEval2()"))->Run();
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004589 CHECK_EQ(result, v8::Integer::New(42));
4590}
4591
4592
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004593static const char* kWithExtensionSource1 =
4594 "function UseWith1() {"
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004595 " var x = 42;"
4596 " with({x:87}) { return x; }"
4597 "}";
4598
4599
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004600
4601static const char* kWithExtensionSource2 =
4602 "(function() {"
4603 " var x = 42;"
4604 " function e() {"
4605 " with ({x:87}) { return x; }"
4606 " }"
4607 " this.UseWith2 = e;"
4608 "})()";
4609
4610
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004611THREADED_TEST(UseWithFromExtension) {
4612 v8::HandleScope handle_scope;
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004613 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
4614 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
4615 const char* extension_names[] = { "withtest1", "withtest2" };
4616 v8::ExtensionConfiguration extensions(2, extension_names);
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004617 v8::Handle<Context> context = Context::New(&extensions);
4618 Context::Scope lock(context);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004619 v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
4620 CHECK_EQ(result, v8::Integer::New(87));
4621 result = Script::Compile(v8_str("UseWith2()"))->Run();
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004622 CHECK_EQ(result, v8::Integer::New(87));
4623}
4624
4625
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004626THREADED_TEST(AutoExtensions) {
4627 v8::HandleScope handle_scope;
4628 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
4629 extension->set_auto_enable(true);
4630 v8::RegisterExtension(extension);
4631 v8::Handle<Context> context = Context::New();
4632 Context::Scope lock(context);
4633 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
4634 CHECK_EQ(result, v8::Integer::New(4));
4635}
4636
4637
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004638static const char* kSyntaxErrorInExtensionSource =
4639 "[";
4640
4641
4642// Test that a syntax error in an extension does not cause a fatal
4643// error but results in an empty context.
4644THREADED_TEST(SyntaxErrorExtensions) {
4645 v8::HandleScope handle_scope;
4646 v8::RegisterExtension(new Extension("syntaxerror",
4647 kSyntaxErrorInExtensionSource));
4648 const char* extension_names[] = { "syntaxerror" };
4649 v8::ExtensionConfiguration extensions(1, extension_names);
4650 v8::Handle<Context> context = Context::New(&extensions);
4651 CHECK(context.IsEmpty());
4652}
4653
4654
4655static const char* kExceptionInExtensionSource =
4656 "throw 42";
4657
4658
4659// Test that an exception when installing an extension does not cause
4660// a fatal error but results in an empty context.
4661THREADED_TEST(ExceptionExtensions) {
4662 v8::HandleScope handle_scope;
4663 v8::RegisterExtension(new Extension("exception",
4664 kExceptionInExtensionSource));
4665 const char* extension_names[] = { "exception" };
4666 v8::ExtensionConfiguration extensions(1, extension_names);
4667 v8::Handle<Context> context = Context::New(&extensions);
4668 CHECK(context.IsEmpty());
4669}
4670
4671
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004672static const char* kNativeCallInExtensionSource =
4673 "function call_runtime_last_index_of(x) {"
4674 " return %StringLastIndexOf(x, 'bob', 10);"
4675 "}";
4676
4677
4678static const char* kNativeCallTest =
4679 "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
4680
4681// Test that a native runtime calls are supported in extensions.
4682THREADED_TEST(NativeCallInExtensions) {
4683 v8::HandleScope handle_scope;
4684 v8::RegisterExtension(new Extension("nativecall",
4685 kNativeCallInExtensionSource));
4686 const char* extension_names[] = { "nativecall" };
4687 v8::ExtensionConfiguration extensions(1, extension_names);
4688 v8::Handle<Context> context = Context::New(&extensions);
4689 Context::Scope lock(context);
4690 v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run();
4691 CHECK_EQ(result, v8::Integer::New(3));
4692}
4693
4694
whesse@chromium.org7b260152011-06-20 15:33:18 +00004695class NativeFunctionExtension : public Extension {
4696 public:
4697 NativeFunctionExtension(const char* name,
4698 const char* source,
4699 v8::InvocationCallback fun = &Echo)
4700 : Extension(name, source),
4701 function_(fun) { }
4702
4703 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
4704 v8::Handle<v8::String> name) {
4705 return v8::FunctionTemplate::New(function_);
4706 }
4707
4708 static v8::Handle<v8::Value> Echo(const v8::Arguments& args) {
4709 if (args.Length() >= 1) return (args[0]);
4710 return v8::Undefined();
4711 }
4712 private:
4713 v8::InvocationCallback function_;
4714};
4715
4716
4717THREADED_TEST(NativeFunctionDeclaration) {
4718 v8::HandleScope handle_scope;
4719 const char* name = "nativedecl";
4720 v8::RegisterExtension(new NativeFunctionExtension(name,
4721 "native function foo();"));
4722 const char* extension_names[] = { name };
4723 v8::ExtensionConfiguration extensions(1, extension_names);
4724 v8::Handle<Context> context = Context::New(&extensions);
4725 Context::Scope lock(context);
4726 v8::Handle<Value> result = Script::Compile(v8_str("foo(42);"))->Run();
4727 CHECK_EQ(result, v8::Integer::New(42));
4728}
4729
4730
4731THREADED_TEST(NativeFunctionDeclarationError) {
4732 v8::HandleScope handle_scope;
lrn@chromium.org67e236d2011-06-23 10:18:16 +00004733 const char* name = "nativedeclerr";
whesse@chromium.org7b260152011-06-20 15:33:18 +00004734 // Syntax error in extension code.
4735 v8::RegisterExtension(new NativeFunctionExtension(name,
4736 "native\nfunction foo();"));
4737 const char* extension_names[] = { name };
4738 v8::ExtensionConfiguration extensions(1, extension_names);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004739 v8::Handle<Context> context(Context::New(&extensions));
whesse@chromium.org7b260152011-06-20 15:33:18 +00004740 ASSERT(context.IsEmpty());
4741}
4742
4743THREADED_TEST(NativeFunctionDeclarationErrorEscape) {
4744 v8::HandleScope handle_scope;
lrn@chromium.org67e236d2011-06-23 10:18:16 +00004745 const char* name = "nativedeclerresc";
whesse@chromium.org7b260152011-06-20 15:33:18 +00004746 // Syntax error in extension code - escape code in "native" means that
4747 // it's not treated as a keyword.
4748 v8::RegisterExtension(new NativeFunctionExtension(
4749 name,
4750 "nativ\\u0065 function foo();"));
4751 const char* extension_names[] = { name };
4752 v8::ExtensionConfiguration extensions(1, extension_names);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004753 v8::Handle<Context> context(Context::New(&extensions));
whesse@chromium.org7b260152011-06-20 15:33:18 +00004754 ASSERT(context.IsEmpty());
4755}
4756
4757
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004758static void CheckDependencies(const char* name, const char* expected) {
4759 v8::HandleScope handle_scope;
4760 v8::ExtensionConfiguration config(1, &name);
4761 LocalContext context(&config);
4762 CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
4763}
4764
4765
4766/*
4767 * Configuration:
4768 *
4769 * /-- B <--\
4770 * A <- -- D <-- E
4771 * \-- C <--/
4772 */
4773THREADED_TEST(ExtensionDependency) {
4774 static const char* kEDeps[] = { "D" };
4775 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
4776 static const char* kDDeps[] = { "B", "C" };
4777 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
4778 static const char* kBCDeps[] = { "A" };
4779 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
4780 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
4781 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
4782 CheckDependencies("A", "undefinedA");
4783 CheckDependencies("B", "undefinedAB");
4784 CheckDependencies("C", "undefinedAC");
4785 CheckDependencies("D", "undefinedABCD");
4786 CheckDependencies("E", "undefinedABCDE");
4787 v8::HandleScope handle_scope;
4788 static const char* exts[2] = { "C", "E" };
4789 v8::ExtensionConfiguration config(2, exts);
4790 LocalContext context(&config);
4791 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
4792}
4793
4794
4795static const char* kExtensionTestScript =
4796 "native function A();"
4797 "native function B();"
4798 "native function C();"
4799 "function Foo(i) {"
4800 " if (i == 0) return A();"
4801 " if (i == 1) return B();"
4802 " if (i == 2) return C();"
4803 "}";
4804
4805
4806static v8::Handle<Value> CallFun(const v8::Arguments& args) {
4807 ApiTestFuzzer::Fuzz();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004808 if (args.IsConstructCall()) {
4809 args.This()->Set(v8_str("data"), args.Data());
4810 return v8::Null();
4811 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004812 return args.Data();
4813}
4814
4815
4816class FunctionExtension : public Extension {
4817 public:
4818 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
4819 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
4820 v8::Handle<String> name);
4821};
4822
4823
4824static int lookup_count = 0;
4825v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
4826 v8::Handle<String> name) {
4827 lookup_count++;
4828 if (name->Equals(v8_str("A"))) {
4829 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
4830 } else if (name->Equals(v8_str("B"))) {
4831 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
4832 } else if (name->Equals(v8_str("C"))) {
4833 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
4834 } else {
4835 return v8::Handle<v8::FunctionTemplate>();
4836 }
4837}
4838
4839
4840THREADED_TEST(FunctionLookup) {
4841 v8::RegisterExtension(new FunctionExtension());
4842 v8::HandleScope handle_scope;
4843 static const char* exts[1] = { "functiontest" };
4844 v8::ExtensionConfiguration config(1, exts);
4845 LocalContext context(&config);
4846 CHECK_EQ(3, lookup_count);
4847 CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
4848 CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
4849 CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
4850}
4851
4852
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004853THREADED_TEST(NativeFunctionConstructCall) {
4854 v8::RegisterExtension(new FunctionExtension());
4855 v8::HandleScope handle_scope;
4856 static const char* exts[1] = { "functiontest" };
4857 v8::ExtensionConfiguration config(1, exts);
4858 LocalContext context(&config);
4859 for (int i = 0; i < 10; i++) {
4860 // Run a few times to ensure that allocation of objects doesn't
4861 // change behavior of a constructor function.
4862 CHECK_EQ(v8::Integer::New(8),
4863 Script::Compile(v8_str("(new A()).data"))->Run());
4864 CHECK_EQ(v8::Integer::New(7),
4865 Script::Compile(v8_str("(new B()).data"))->Run());
4866 CHECK_EQ(v8::Integer::New(6),
4867 Script::Compile(v8_str("(new C()).data"))->Run());
4868 }
4869}
4870
4871
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004872static const char* last_location;
4873static const char* last_message;
4874void StoringErrorCallback(const char* location, const char* message) {
4875 if (last_location == NULL) {
4876 last_location = location;
4877 last_message = message;
4878 }
4879}
4880
4881
4882// ErrorReporting creates a circular extensions configuration and
4883// tests that the fatal error handler gets called. This renders V8
4884// unusable and therefore this test cannot be run in parallel.
4885TEST(ErrorReporting) {
4886 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
4887 static const char* aDeps[] = { "B" };
4888 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
4889 static const char* bDeps[] = { "A" };
4890 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
4891 last_location = NULL;
4892 v8::ExtensionConfiguration config(1, bDeps);
4893 v8::Handle<Context> context = Context::New(&config);
4894 CHECK(context.IsEmpty());
4895 CHECK_NE(last_location, NULL);
4896}
4897
4898
ager@chromium.org7c537e22008-10-16 08:43:32 +00004899static const char* js_code_causing_huge_string_flattening =
4900 "var str = 'X';"
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00004901 "for (var i = 0; i < 30; i++) {"
ager@chromium.org7c537e22008-10-16 08:43:32 +00004902 " str = str + str;"
4903 "}"
4904 "str.match(/X/);";
4905
4906
4907void OOMCallback(const char* location, const char* message) {
4908 exit(0);
4909}
4910
4911
4912TEST(RegexpOutOfMemory) {
4913 // Execute a script that causes out of memory when flattening a string.
4914 v8::HandleScope scope;
4915 v8::V8::SetFatalErrorHandler(OOMCallback);
4916 LocalContext context;
4917 Local<Script> script =
4918 Script::Compile(String::New(js_code_causing_huge_string_flattening));
4919 last_location = NULL;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004920 Local<Value> result(script->Run());
ager@chromium.org7c537e22008-10-16 08:43:32 +00004921
4922 CHECK(false); // Should not return.
4923}
4924
4925
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004926static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
4927 v8::Handle<Value> data) {
4928 CHECK_EQ(v8::Undefined(), data);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004929 CHECK(message->GetScriptResourceName()->IsUndefined());
4930 CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004931 message->GetLineNumber();
4932 message->GetSourceLine();
4933}
4934
4935
4936THREADED_TEST(ErrorWithMissingScriptInfo) {
4937 v8::HandleScope scope;
4938 LocalContext context;
4939 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
4940 Script::Compile(v8_str("throw Error()"))->Run();
4941 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
4942}
4943
4944
4945int global_index = 0;
4946
4947class Snorkel {
4948 public:
4949 Snorkel() { index_ = global_index++; }
4950 int index_;
4951};
4952
4953class Whammy {
4954 public:
4955 Whammy() {
4956 cursor_ = 0;
4957 }
4958 ~Whammy() {
4959 script_.Dispose();
4960 }
4961 v8::Handle<Script> getScript() {
4962 if (script_.IsEmpty())
4963 script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
4964 return Local<Script>(*script_);
4965 }
4966
4967 public:
4968 static const int kObjectCount = 256;
4969 int cursor_;
4970 v8::Persistent<v8::Object> objects_[kObjectCount];
4971 v8::Persistent<Script> script_;
4972};
4973
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004974static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004975 Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
4976 delete snorkel;
4977 obj.ClearWeak();
4978}
4979
4980v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
4981 const AccessorInfo& info) {
4982 Whammy* whammy =
4983 static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
4984
4985 v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
4986
4987 v8::Handle<v8::Object> obj = v8::Object::New();
4988 v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
4989 if (!prev.IsEmpty()) {
4990 prev->Set(v8_str("next"), obj);
4991 prev.MakeWeak(new Snorkel(), &HandleWeakReference);
4992 whammy->objects_[whammy->cursor_].Clear();
4993 }
4994 whammy->objects_[whammy->cursor_] = global;
4995 whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
4996 return whammy->getScript()->Run();
4997}
4998
4999THREADED_TEST(WeakReference) {
5000 v8::HandleScope handle_scope;
5001 v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005002 Whammy* whammy = new Whammy();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005003 templ->SetNamedPropertyHandler(WhammyPropertyGetter,
5004 0, 0, 0, 0,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005005 v8::External::New(whammy));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005006 const char* extension_list[] = { "v8/gc" };
5007 v8::ExtensionConfiguration extensions(1, extension_list);
5008 v8::Persistent<Context> context = Context::New(&extensions);
5009 Context::Scope context_scope(context);
5010
5011 v8::Handle<v8::Object> interceptor = templ->NewInstance();
5012 context->Global()->Set(v8_str("whammy"), interceptor);
5013 const char* code =
5014 "var last;"
5015 "for (var i = 0; i < 10000; i++) {"
5016 " var obj = whammy.length;"
5017 " if (last) last.next = obj;"
5018 " last = obj;"
5019 "}"
5020 "gc();"
5021 "4";
5022 v8::Handle<Value> result = CompileRun(code);
5023 CHECK_EQ(4.0, result->NumberValue());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005024 delete whammy;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005025 context.Dispose();
5026}
5027
5028
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005029static void DisposeAndSetFlag(v8::Persistent<v8::Value> obj, void* data) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005030 obj.Dispose();
5031 obj.Clear();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005032 *(reinterpret_cast<bool*>(data)) = true;
5033}
5034
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005035
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005036THREADED_TEST(IndependentWeakHandle) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005037 v8::Persistent<Context> context = Context::New();
5038 Context::Scope context_scope(context);
5039
5040 v8::Persistent<v8::Object> object_a;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005041
5042 {
5043 v8::HandleScope handle_scope;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005044 object_a = v8::Persistent<v8::Object>::New(v8::Object::New());
5045 }
5046
5047 bool object_a_disposed = false;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005048 object_a.MakeWeak(&object_a_disposed, &DisposeAndSetFlag);
5049 object_a.MarkIndependent();
5050 HEAP->PerformScavenge();
5051 CHECK(object_a_disposed);
5052}
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005053
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005054
5055static void InvokeScavenge() {
5056 HEAP->PerformScavenge();
5057}
5058
5059
5060static void InvokeMarkSweep() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005061 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005062}
5063
5064
5065static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
5066 obj.Dispose();
5067 obj.Clear();
5068 *(reinterpret_cast<bool*>(data)) = true;
5069 InvokeScavenge();
5070}
5071
5072
5073static void ForceMarkSweep(v8::Persistent<v8::Value> obj, void* data) {
5074 obj.Dispose();
5075 obj.Clear();
5076 *(reinterpret_cast<bool*>(data)) = true;
5077 InvokeMarkSweep();
5078}
5079
5080
5081THREADED_TEST(GCFromWeakCallbacks) {
5082 v8::Persistent<Context> context = Context::New();
5083 Context::Scope context_scope(context);
5084
5085 static const int kNumberOfGCTypes = 2;
5086 v8::WeakReferenceCallback gc_forcing_callback[kNumberOfGCTypes] =
5087 {&ForceScavenge, &ForceMarkSweep};
5088
5089 typedef void (*GCInvoker)();
5090 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
5091
5092 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
5093 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
5094 v8::Persistent<v8::Object> object;
5095 {
5096 v8::HandleScope handle_scope;
5097 object = v8::Persistent<v8::Object>::New(v8::Object::New());
5098 }
5099 bool disposed = false;
5100 object.MakeWeak(&disposed, gc_forcing_callback[inner_gc]);
5101 object.MarkIndependent();
5102 invoke_gc[outer_gc]();
5103 CHECK(disposed);
5104 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005105 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005106}
5107
5108
5109static void RevivingCallback(v8::Persistent<v8::Value> obj, void* data) {
5110 obj.ClearWeak();
5111 *(reinterpret_cast<bool*>(data)) = true;
5112}
5113
5114
5115THREADED_TEST(IndependentHandleRevival) {
5116 v8::Persistent<Context> context = Context::New();
5117 Context::Scope context_scope(context);
5118
5119 v8::Persistent<v8::Object> object;
5120 {
5121 v8::HandleScope handle_scope;
5122 object = v8::Persistent<v8::Object>::New(v8::Object::New());
5123 object->Set(v8_str("x"), v8::Integer::New(1));
5124 v8::Local<String> y_str = v8_str("y");
5125 object->Set(y_str, y_str);
5126 }
5127 bool revived = false;
5128 object.MakeWeak(&revived, &RevivingCallback);
5129 object.MarkIndependent();
5130 HEAP->PerformScavenge();
5131 CHECK(revived);
5132 HEAP->CollectAllGarbage(true);
5133 {
5134 v8::HandleScope handle_scope;
5135 v8::Local<String> y_str = v8_str("y");
5136 CHECK_EQ(v8::Integer::New(1), object->Get(v8_str("x")));
5137 CHECK(object->Get(y_str)->Equals(y_str));
5138 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005139}
5140
5141
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005142v8::Handle<Function> args_fun;
5143
5144
5145static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
5146 ApiTestFuzzer::Fuzz();
5147 CHECK_EQ(args_fun, args.Callee());
5148 CHECK_EQ(3, args.Length());
5149 CHECK_EQ(v8::Integer::New(1), args[0]);
5150 CHECK_EQ(v8::Integer::New(2), args[1]);
5151 CHECK_EQ(v8::Integer::New(3), args[2]);
5152 CHECK_EQ(v8::Undefined(), args[3]);
5153 v8::HandleScope scope;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005154 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005155 return v8::Undefined();
5156}
5157
5158
5159THREADED_TEST(Arguments) {
5160 v8::HandleScope scope;
5161 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
5162 global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
5163 LocalContext context(NULL, global);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005164 args_fun = context->Global()->Get(v8_str("f")).As<Function>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005165 v8_compile("f(1, 2, 3)")->Run();
5166}
5167
5168
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005169static v8::Handle<Value> NoBlockGetterX(Local<String> name,
5170 const AccessorInfo&) {
5171 return v8::Handle<Value>();
5172}
5173
5174
5175static v8::Handle<Value> NoBlockGetterI(uint32_t index,
5176 const AccessorInfo&) {
5177 return v8::Handle<Value>();
5178}
5179
5180
5181static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
5182 const AccessorInfo&) {
5183 if (!name->Equals(v8_str("foo"))) {
5184 return v8::Handle<v8::Boolean>(); // not intercepted
5185 }
5186
5187 return v8::False(); // intercepted, and don't delete the property
5188}
5189
5190
5191static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
5192 if (index != 2) {
5193 return v8::Handle<v8::Boolean>(); // not intercepted
5194 }
5195
5196 return v8::False(); // intercepted, and don't delete the property
5197}
5198
5199
5200THREADED_TEST(Deleter) {
5201 v8::HandleScope scope;
5202 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5203 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
5204 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
5205 LocalContext context;
5206 context->Global()->Set(v8_str("k"), obj->NewInstance());
5207 CompileRun(
5208 "k.foo = 'foo';"
5209 "k.bar = 'bar';"
5210 "k[2] = 2;"
5211 "k[4] = 4;");
5212 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
5213 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
5214
5215 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
5216 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
5217
5218 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
5219 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
5220
5221 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
5222 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
5223}
5224
5225
5226static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
5227 ApiTestFuzzer::Fuzz();
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005228 if (name->Equals(v8_str("foo")) ||
5229 name->Equals(v8_str("bar")) ||
5230 name->Equals(v8_str("baz"))) {
5231 return v8::Undefined();
5232 }
5233 return v8::Handle<Value>();
5234}
5235
5236
5237static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
5238 ApiTestFuzzer::Fuzz();
5239 if (index == 0 || index == 1) return v8::Undefined();
5240 return v8::Handle<Value>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005241}
5242
5243
5244static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
5245 ApiTestFuzzer::Fuzz();
5246 v8::Handle<v8::Array> result = v8::Array::New(3);
5247 result->Set(v8::Integer::New(0), v8_str("foo"));
5248 result->Set(v8::Integer::New(1), v8_str("bar"));
5249 result->Set(v8::Integer::New(2), v8_str("baz"));
5250 return result;
5251}
5252
5253
5254static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
5255 ApiTestFuzzer::Fuzz();
5256 v8::Handle<v8::Array> result = v8::Array::New(2);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005257 result->Set(v8::Integer::New(0), v8_str("0"));
5258 result->Set(v8::Integer::New(1), v8_str("1"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005259 return result;
5260}
5261
5262
5263THREADED_TEST(Enumerators) {
5264 v8::HandleScope scope;
5265 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5266 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005267 obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005268 LocalContext context;
5269 context->Global()->Set(v8_str("k"), obj->NewInstance());
5270 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005271 "k[10] = 0;"
5272 "k.a = 0;"
5273 "k[5] = 0;"
5274 "k.b = 0;"
5275 "k[4294967295] = 0;"
5276 "k.c = 0;"
5277 "k[4294967296] = 0;"
5278 "k.d = 0;"
5279 "k[140000] = 0;"
5280 "k.e = 0;"
5281 "k[30000000000] = 0;"
5282 "k.f = 0;"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005283 "var result = [];"
5284 "for (var prop in k) {"
5285 " result.push(prop);"
5286 "}"
5287 "result"));
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005288 // Check that we get all the property names returned including the
5289 // ones from the enumerators in the right order: indexed properties
5290 // in numerical order, indexed interceptor properties, named
5291 // properties in insertion order, named interceptor properties.
5292 // This order is not mandated by the spec, so this test is just
5293 // documenting our behavior.
5294 CHECK_EQ(17, result->Length());
5295 // Indexed properties in numerical order.
5296 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
5297 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
5298 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
5299 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
5300 // Indexed interceptor properties in the order they are returned
5301 // from the enumerator interceptor.
5302 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
5303 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
5304 // Named properties in insertion order.
5305 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
5306 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
5307 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
5308 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
5309 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
5310 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
5311 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
5312 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
5313 // Named interceptor properties.
5314 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
5315 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
5316 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005317}
5318
5319
5320int p_getter_count;
5321int p_getter_count2;
5322
5323
5324static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
5325 ApiTestFuzzer::Fuzz();
5326 p_getter_count++;
5327 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5328 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
5329 if (name->Equals(v8_str("p1"))) {
5330 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
5331 } else if (name->Equals(v8_str("p2"))) {
5332 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
5333 } else if (name->Equals(v8_str("p3"))) {
5334 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
5335 } else if (name->Equals(v8_str("p4"))) {
5336 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
5337 }
5338 return v8::Undefined();
5339}
5340
5341
5342static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
5343 ApiTestFuzzer::Fuzz();
5344 LocalContext context;
5345 context->Global()->Set(v8_str("o1"), obj->NewInstance());
5346 CompileRun(
5347 "o1.__proto__ = { };"
5348 "var o2 = { __proto__: o1 };"
5349 "var o3 = { __proto__: o2 };"
5350 "var o4 = { __proto__: o3 };"
5351 "for (var i = 0; i < 10; i++) o4.p4;"
5352 "for (var i = 0; i < 10; i++) o3.p3;"
5353 "for (var i = 0; i < 10; i++) o2.p2;"
5354 "for (var i = 0; i < 10; i++) o1.p1;");
5355}
5356
5357
5358static v8::Handle<Value> PGetter2(Local<String> name,
5359 const AccessorInfo& info) {
5360 ApiTestFuzzer::Fuzz();
5361 p_getter_count2++;
5362 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5363 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
5364 if (name->Equals(v8_str("p1"))) {
5365 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
5366 } else if (name->Equals(v8_str("p2"))) {
5367 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
5368 } else if (name->Equals(v8_str("p3"))) {
5369 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
5370 } else if (name->Equals(v8_str("p4"))) {
5371 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
5372 }
5373 return v8::Undefined();
5374}
5375
5376
5377THREADED_TEST(GetterHolders) {
5378 v8::HandleScope scope;
5379 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5380 obj->SetAccessor(v8_str("p1"), PGetter);
5381 obj->SetAccessor(v8_str("p2"), PGetter);
5382 obj->SetAccessor(v8_str("p3"), PGetter);
5383 obj->SetAccessor(v8_str("p4"), PGetter);
5384 p_getter_count = 0;
5385 RunHolderTest(obj);
5386 CHECK_EQ(40, p_getter_count);
5387}
5388
5389
5390THREADED_TEST(PreInterceptorHolders) {
5391 v8::HandleScope scope;
5392 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5393 obj->SetNamedPropertyHandler(PGetter2);
5394 p_getter_count2 = 0;
5395 RunHolderTest(obj);
5396 CHECK_EQ(40, p_getter_count2);
5397}
5398
5399
5400THREADED_TEST(ObjectInstantiation) {
5401 v8::HandleScope scope;
5402 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5403 templ->SetAccessor(v8_str("t"), PGetter2);
5404 LocalContext context;
5405 context->Global()->Set(v8_str("o"), templ->NewInstance());
5406 for (int i = 0; i < 100; i++) {
5407 v8::HandleScope inner_scope;
5408 v8::Handle<v8::Object> obj = templ->NewInstance();
5409 CHECK_NE(obj, context->Global()->Get(v8_str("o")));
5410 context->Global()->Set(v8_str("o2"), obj);
5411 v8::Handle<Value> value =
5412 Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
5413 CHECK_EQ(v8::True(), value);
5414 context->Global()->Set(v8_str("o"), obj);
5415 }
5416}
5417
5418
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005419static int StrCmp16(uint16_t* a, uint16_t* b) {
5420 while (true) {
5421 if (*a == 0 && *b == 0) return 0;
5422 if (*a != *b) return 0 + *a - *b;
5423 a++;
5424 b++;
5425 }
5426}
5427
5428
5429static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
5430 while (true) {
5431 if (n-- == 0) return 0;
5432 if (*a == 0 && *b == 0) return 0;
5433 if (*a != *b) return 0 + *a - *b;
5434 a++;
5435 b++;
5436 }
5437}
5438
5439
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005440THREADED_TEST(StringWrite) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005441 LocalContext context;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005442 v8::HandleScope scope;
5443 v8::Handle<String> str = v8_str("abcde");
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005444 // abc<Icelandic eth><Unicode snowman>.
5445 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005446 const int kStride = 4; // Must match stride in for loops in JS below.
5447 CompileRun(
5448 "var left = '';"
5449 "for (var i = 0; i < 0xd800; i += 4) {"
5450 " left = left + String.fromCharCode(i);"
5451 "}");
5452 CompileRun(
5453 "var right = '';"
5454 "for (var i = 0; i < 0xd800; i += 4) {"
5455 " right = String.fromCharCode(i) + right;"
5456 "}");
5457 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5458 Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
5459 Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005460
5461 CHECK_EQ(5, str2->Length());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005462 CHECK_EQ(0xd800 / kStride, left_tree->Length());
5463 CHECK_EQ(0xd800 / kStride, right_tree->Length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005464
5465 char buf[100];
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005466 char utf8buf[0xd800 * 3];
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005467 uint16_t wbuf[100];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005468 int len;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005469 int charlen;
5470
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005471 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005472 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005473 CHECK_EQ(9, len);
5474 CHECK_EQ(5, charlen);
5475 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005476
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005477 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005478 len = str2->WriteUtf8(utf8buf, 8, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005479 CHECK_EQ(8, len);
5480 CHECK_EQ(5, charlen);
5481 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005482
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005483 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005484 len = str2->WriteUtf8(utf8buf, 7, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005485 CHECK_EQ(5, len);
5486 CHECK_EQ(4, charlen);
5487 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005488
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005489 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005490 len = str2->WriteUtf8(utf8buf, 6, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005491 CHECK_EQ(5, len);
5492 CHECK_EQ(4, charlen);
5493 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005494
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005495 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005496 len = str2->WriteUtf8(utf8buf, 5, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005497 CHECK_EQ(5, len);
5498 CHECK_EQ(4, charlen);
5499 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005500
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005501 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005502 len = str2->WriteUtf8(utf8buf, 4, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005503 CHECK_EQ(3, len);
5504 CHECK_EQ(3, charlen);
5505 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005506
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005507 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005508 len = str2->WriteUtf8(utf8buf, 3, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005509 CHECK_EQ(3, len);
5510 CHECK_EQ(3, charlen);
5511 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005512
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005513 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005514 len = str2->WriteUtf8(utf8buf, 2, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005515 CHECK_EQ(2, len);
5516 CHECK_EQ(2, charlen);
5517 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005518
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005519 memset(utf8buf, 0x1, sizeof(utf8buf));
5520 len = left_tree->Utf8Length();
5521 int utf8_expected =
5522 (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
5523 CHECK_EQ(utf8_expected, len);
5524 len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
5525 CHECK_EQ(utf8_expected, len);
5526 CHECK_EQ(0xd800 / kStride, charlen);
5527 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
5528 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
5529 CHECK_EQ(0xc0 - kStride,
5530 static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
5531 CHECK_EQ(1, utf8buf[utf8_expected]);
5532
5533 memset(utf8buf, 0x1, sizeof(utf8buf));
5534 len = right_tree->Utf8Length();
5535 CHECK_EQ(utf8_expected, len);
5536 len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
5537 CHECK_EQ(utf8_expected, len);
5538 CHECK_EQ(0xd800 / kStride, charlen);
5539 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
5540 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
5541 CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
5542 CHECK_EQ(1, utf8buf[utf8_expected]);
5543
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005544 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005545 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005546 len = str->WriteAscii(buf);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005547 CHECK_EQ(5, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005548 len = str->Write(wbuf);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005549 CHECK_EQ(5, len);
5550 CHECK_EQ(0, strcmp("abcde", buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005551 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005552 CHECK_EQ(0, StrCmp16(answer1, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005553
5554 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005555 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005556 len = str->WriteAscii(buf, 0, 4);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005557 CHECK_EQ(4, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005558 len = str->Write(wbuf, 0, 4);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005559 CHECK_EQ(4, len);
5560 CHECK_EQ(0, strncmp("abcd\1", buf, 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005561 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005562 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005563
5564 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005565 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005566 len = str->WriteAscii(buf, 0, 5);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005567 CHECK_EQ(5, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005568 len = str->Write(wbuf, 0, 5);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005569 CHECK_EQ(5, len);
5570 CHECK_EQ(0, strncmp("abcde\1", buf, 6));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005571 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005572 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005573
5574 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005575 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005576 len = str->WriteAscii(buf, 0, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005577 CHECK_EQ(5, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005578 len = str->Write(wbuf, 0, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005579 CHECK_EQ(5, len);
5580 CHECK_EQ(0, strcmp("abcde", buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005581 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005582 CHECK_EQ(0, StrCmp16(answer4, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005583
5584 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005585 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005586 len = str->WriteAscii(buf, 4, -1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005587 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005588 len = str->Write(wbuf, 4, -1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005589 CHECK_EQ(1, len);
5590 CHECK_EQ(0, strcmp("e", buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005591 uint16_t answer5[] = {'e', '\0'};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005592 CHECK_EQ(0, StrCmp16(answer5, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005593
5594 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005595 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005596 len = str->WriteAscii(buf, 4, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005597 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005598 len = str->Write(wbuf, 4, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005599 CHECK_EQ(1, len);
5600 CHECK_EQ(0, strcmp("e", buf));
5601 CHECK_EQ(0, StrCmp16(answer5, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005602
5603 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005604 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005605 len = str->WriteAscii(buf, 4, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005606 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005607 len = str->Write(wbuf, 4, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005608 CHECK_EQ(1, len);
5609 CHECK_EQ(0, strncmp("e\1", buf, 2));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005610 uint16_t answer6[] = {'e', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005611 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005612
5613 memset(buf, 0x1, sizeof(buf));
5614 memset(wbuf, 0x1, sizeof(wbuf));
5615 len = str->WriteAscii(buf, 3, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005616 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005617 len = str->Write(wbuf, 3, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005618 CHECK_EQ(1, len);
5619 CHECK_EQ(0, strncmp("d\1", buf, 2));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005620 uint16_t answer7[] = {'d', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005621 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005622
5623 memset(wbuf, 0x1, sizeof(wbuf));
5624 wbuf[5] = 'X';
5625 len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
5626 CHECK_EQ(5, len);
5627 CHECK_EQ('X', wbuf[5]);
5628 uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
5629 uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
5630 CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
5631 CHECK_NE(0, StrCmp16(answer8b, wbuf));
5632 wbuf[5] = '\0';
5633 CHECK_EQ(0, StrCmp16(answer8b, wbuf));
5634
5635 memset(buf, 0x1, sizeof(buf));
5636 buf[5] = 'X';
5637 len = str->WriteAscii(buf, 0, 6, String::NO_NULL_TERMINATION);
5638 CHECK_EQ(5, len);
5639 CHECK_EQ('X', buf[5]);
5640 CHECK_EQ(0, strncmp("abcde", buf, 5));
5641 CHECK_NE(0, strcmp("abcde", buf));
5642 buf[5] = '\0';
5643 CHECK_EQ(0, strcmp("abcde", buf));
5644
5645 memset(utf8buf, 0x1, sizeof(utf8buf));
5646 utf8buf[8] = 'X';
5647 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
5648 String::NO_NULL_TERMINATION);
5649 CHECK_EQ(8, len);
5650 CHECK_EQ('X', utf8buf[8]);
5651 CHECK_EQ(5, charlen);
5652 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
5653 CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
5654 utf8buf[8] = '\0';
5655 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005656}
5657
5658
5659THREADED_TEST(ToArrayIndex) {
5660 v8::HandleScope scope;
5661 LocalContext context;
5662
5663 v8::Handle<String> str = v8_str("42");
5664 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
5665 CHECK(!index.IsEmpty());
5666 CHECK_EQ(42.0, index->Uint32Value());
5667 str = v8_str("42asdf");
5668 index = str->ToArrayIndex();
5669 CHECK(index.IsEmpty());
5670 str = v8_str("-42");
5671 index = str->ToArrayIndex();
5672 CHECK(index.IsEmpty());
5673 str = v8_str("4294967295");
5674 index = str->ToArrayIndex();
5675 CHECK(!index.IsEmpty());
5676 CHECK_EQ(4294967295.0, index->Uint32Value());
5677 v8::Handle<v8::Number> num = v8::Number::New(1);
5678 index = num->ToArrayIndex();
5679 CHECK(!index.IsEmpty());
5680 CHECK_EQ(1.0, index->Uint32Value());
5681 num = v8::Number::New(-1);
5682 index = num->ToArrayIndex();
5683 CHECK(index.IsEmpty());
5684 v8::Handle<v8::Object> obj = v8::Object::New();
5685 index = obj->ToArrayIndex();
5686 CHECK(index.IsEmpty());
5687}
5688
5689
5690THREADED_TEST(ErrorConstruction) {
5691 v8::HandleScope scope;
5692 LocalContext context;
5693
5694 v8::Handle<String> foo = v8_str("foo");
5695 v8::Handle<String> message = v8_str("message");
5696 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
5697 CHECK(range_error->IsObject());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005698 v8::Handle<v8::Object> range_obj(range_error.As<v8::Object>());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005699 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005700 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
5701 CHECK(reference_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005702 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005703 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
5704 CHECK(syntax_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005705 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005706 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
5707 CHECK(type_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005708 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005709 v8::Handle<Value> error = v8::Exception::Error(foo);
5710 CHECK(error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005711 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005712}
5713
5714
5715static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
5716 ApiTestFuzzer::Fuzz();
5717 return v8_num(10);
5718}
5719
5720
5721static void YSetter(Local<String> name,
5722 Local<Value> value,
5723 const AccessorInfo& info) {
5724 if (info.This()->Has(name)) {
5725 info.This()->Delete(name);
5726 }
5727 info.This()->Set(name, value);
5728}
5729
5730
5731THREADED_TEST(DeleteAccessor) {
5732 v8::HandleScope scope;
5733 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5734 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
5735 LocalContext context;
5736 v8::Handle<v8::Object> holder = obj->NewInstance();
5737 context->Global()->Set(v8_str("holder"), holder);
5738 v8::Handle<Value> result = CompileRun(
5739 "holder.y = 11; holder.y = 12; holder.y");
5740 CHECK_EQ(12, result->Uint32Value());
5741}
5742
5743
5744THREADED_TEST(TypeSwitch) {
5745 v8::HandleScope scope;
5746 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
5747 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
5748 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
5749 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
5750 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
5751 LocalContext context;
5752 v8::Handle<v8::Object> obj0 = v8::Object::New();
5753 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
5754 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
5755 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
5756 for (int i = 0; i < 10; i++) {
5757 CHECK_EQ(0, type_switch->match(obj0));
5758 CHECK_EQ(1, type_switch->match(obj1));
5759 CHECK_EQ(2, type_switch->match(obj2));
5760 CHECK_EQ(3, type_switch->match(obj3));
5761 CHECK_EQ(3, type_switch->match(obj3));
5762 CHECK_EQ(2, type_switch->match(obj2));
5763 CHECK_EQ(1, type_switch->match(obj1));
5764 CHECK_EQ(0, type_switch->match(obj0));
5765 }
5766}
5767
5768
5769// For use within the TestSecurityHandler() test.
5770static bool g_security_callback_result = false;
5771static bool NamedSecurityTestCallback(Local<v8::Object> global,
5772 Local<Value> name,
5773 v8::AccessType type,
5774 Local<Value> data) {
5775 // Always allow read access.
5776 if (type == v8::ACCESS_GET)
5777 return true;
5778
5779 // Sometimes allow other access.
5780 return g_security_callback_result;
5781}
5782
5783
5784static bool IndexedSecurityTestCallback(Local<v8::Object> global,
5785 uint32_t key,
5786 v8::AccessType type,
5787 Local<Value> data) {
5788 // Always allow read access.
5789 if (type == v8::ACCESS_GET)
5790 return true;
5791
5792 // Sometimes allow other access.
5793 return g_security_callback_result;
5794}
5795
5796
5797static int trouble_nesting = 0;
5798static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
5799 ApiTestFuzzer::Fuzz();
5800 trouble_nesting++;
5801
5802 // Call a JS function that throws an uncaught exception.
5803 Local<v8::Object> arg_this = Context::GetCurrent()->Global();
5804 Local<Value> trouble_callee = (trouble_nesting == 3) ?
5805 arg_this->Get(v8_str("trouble_callee")) :
5806 arg_this->Get(v8_str("trouble_caller"));
5807 CHECK(trouble_callee->IsFunction());
5808 return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
5809}
5810
5811
5812static int report_count = 0;
5813static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
5814 v8::Handle<Value>) {
5815 report_count++;
5816}
5817
5818
5819// Counts uncaught exceptions, but other tests running in parallel
5820// also have uncaught exceptions.
5821TEST(ApiUncaughtException) {
ager@chromium.org8bb60582008-12-11 12:02:20 +00005822 report_count = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005823 v8::HandleScope scope;
5824 LocalContext env;
5825 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
5826
5827 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
5828 v8::Local<v8::Object> global = env->Global();
5829 global->Set(v8_str("trouble"), fun->GetFunction());
5830
5831 Script::Compile(v8_str("function trouble_callee() {"
5832 " var x = null;"
5833 " return x.foo;"
5834 "};"
5835 "function trouble_caller() {"
5836 " trouble();"
5837 "};"))->Run();
5838 Local<Value> trouble = global->Get(v8_str("trouble"));
5839 CHECK(trouble->IsFunction());
5840 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
5841 CHECK(trouble_callee->IsFunction());
5842 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
5843 CHECK(trouble_caller->IsFunction());
5844 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
5845 CHECK_EQ(1, report_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00005846 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
5847}
5848
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005849static const char* script_resource_name = "ExceptionInNativeScript.js";
5850static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
5851 v8::Handle<Value>) {
5852 v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
5853 CHECK(!name_val.IsEmpty() && name_val->IsString());
5854 v8::String::AsciiValue name(message->GetScriptResourceName());
5855 CHECK_EQ(script_resource_name, *name);
5856 CHECK_EQ(3, message->GetLineNumber());
5857 v8::String::AsciiValue source_line(message->GetSourceLine());
5858 CHECK_EQ(" new o.foo();", *source_line);
5859}
5860
5861TEST(ExceptionInNativeScript) {
5862 v8::HandleScope scope;
5863 LocalContext env;
5864 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
5865
5866 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
5867 v8::Local<v8::Object> global = env->Global();
5868 global->Set(v8_str("trouble"), fun->GetFunction());
5869
5870 Script::Compile(v8_str("function trouble() {\n"
5871 " var o = {};\n"
5872 " new o.foo();\n"
5873 "};"), v8::String::New(script_resource_name))->Run();
5874 Local<Value> trouble = global->Get(v8_str("trouble"));
5875 CHECK(trouble->IsFunction());
5876 Function::Cast(*trouble)->Call(global, 0, NULL);
5877 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
5878}
5879
ager@chromium.org8bb60582008-12-11 12:02:20 +00005880
5881TEST(CompilationErrorUsingTryCatchHandler) {
5882 v8::HandleScope scope;
5883 LocalContext env;
5884 v8::TryCatch try_catch;
5885 Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
5886 CHECK_NE(NULL, *try_catch.Exception());
5887 CHECK(try_catch.HasCaught());
5888}
5889
5890
5891TEST(TryCatchFinallyUsingTryCatchHandler) {
5892 v8::HandleScope scope;
5893 LocalContext env;
5894 v8::TryCatch try_catch;
5895 Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
5896 CHECK(!try_catch.HasCaught());
5897 Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
5898 CHECK(try_catch.HasCaught());
5899 try_catch.Reset();
5900 Script::Compile(v8_str("(function() {"
5901 "try { throw ''; } finally { return; }"
5902 "})()"))->Run();
5903 CHECK(!try_catch.HasCaught());
5904 Script::Compile(v8_str("(function()"
5905 " { try { throw ''; } finally { throw 0; }"
5906 "})()"))->Run();
5907 CHECK(try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005908}
5909
5910
5911// SecurityHandler can't be run twice
5912TEST(SecurityHandler) {
5913 v8::HandleScope scope0;
5914 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
5915 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
5916 IndexedSecurityTestCallback);
5917 // Create an environment
5918 v8::Persistent<Context> context0 =
5919 Context::New(NULL, global_template);
5920 context0->Enter();
5921
5922 v8::Handle<v8::Object> global0 = context0->Global();
5923 v8::Handle<Script> script0 = v8_compile("foo = 111");
5924 script0->Run();
5925 global0->Set(v8_str("0"), v8_num(999));
5926 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
5927 CHECK_EQ(111, foo0->Int32Value());
5928 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
5929 CHECK_EQ(999, z0->Int32Value());
5930
5931 // Create another environment, should fail security checks.
5932 v8::HandleScope scope1;
5933
5934 v8::Persistent<Context> context1 =
5935 Context::New(NULL, global_template);
5936 context1->Enter();
5937
5938 v8::Handle<v8::Object> global1 = context1->Global();
5939 global1->Set(v8_str("othercontext"), global0);
5940 // This set will fail the security check.
5941 v8::Handle<Script> script1 =
5942 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
5943 script1->Run();
5944 // This read will pass the security check.
5945 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
5946 CHECK_EQ(111, foo1->Int32Value());
5947 // This read will pass the security check.
5948 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
5949 CHECK_EQ(999, z1->Int32Value());
5950
5951 // Create another environment, should pass security checks.
5952 { g_security_callback_result = true; // allow security handler to pass.
5953 v8::HandleScope scope2;
5954 LocalContext context2;
5955 v8::Handle<v8::Object> global2 = context2->Global();
5956 global2->Set(v8_str("othercontext"), global0);
5957 v8::Handle<Script> script2 =
5958 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
5959 script2->Run();
5960 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
5961 CHECK_EQ(333, foo2->Int32Value());
5962 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
5963 CHECK_EQ(888, z2->Int32Value());
5964 }
5965
5966 context1->Exit();
5967 context1.Dispose();
5968
5969 context0->Exit();
5970 context0.Dispose();
5971}
5972
5973
5974THREADED_TEST(SecurityChecks) {
5975 v8::HandleScope handle_scope;
5976 LocalContext env1;
5977 v8::Persistent<Context> env2 = Context::New();
5978
5979 Local<Value> foo = v8_str("foo");
5980 Local<Value> bar = v8_str("bar");
5981
5982 // Set to the same domain.
5983 env1->SetSecurityToken(foo);
5984
5985 // Create a function in env1.
5986 Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
5987 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
5988 CHECK(spy->IsFunction());
5989
5990 // Create another function accessing global objects.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005991 Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005992 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
5993 CHECK(spy2->IsFunction());
5994
5995 // Switch to env2 in the same domain and invoke spy on env2.
5996 {
5997 env2->SetSecurityToken(foo);
5998 // Enter env2
5999 Context::Scope scope_env2(env2);
6000 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
6001 CHECK(result->IsFunction());
6002 }
6003
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006004 {
6005 env2->SetSecurityToken(bar);
6006 Context::Scope scope_env2(env2);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006007
6008 // Call cross_domain_call, it should throw an exception
6009 v8::TryCatch try_catch;
6010 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
6011 CHECK(try_catch.HasCaught());
6012 }
6013
6014 env2.Dispose();
6015}
6016
6017
6018// Regression test case for issue 1183439.
6019THREADED_TEST(SecurityChecksForPrototypeChain) {
6020 v8::HandleScope scope;
6021 LocalContext current;
6022 v8::Persistent<Context> other = Context::New();
6023
6024 // Change context to be able to get to the Object function in the
6025 // other context without hitting the security checks.
6026 v8::Local<Value> other_object;
6027 { Context::Scope scope(other);
6028 other_object = other->Global()->Get(v8_str("Object"));
6029 other->Global()->Set(v8_num(42), v8_num(87));
6030 }
6031
6032 current->Global()->Set(v8_str("other"), other->Global());
6033 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
6034
6035 // Make sure the security check fails here and we get an undefined
6036 // result instead of getting the Object function. Repeat in a loop
6037 // to make sure to exercise the IC code.
6038 v8::Local<Script> access_other0 = v8_compile("other.Object");
6039 v8::Local<Script> access_other1 = v8_compile("other[42]");
6040 for (int i = 0; i < 5; i++) {
6041 CHECK(!access_other0->Run()->Equals(other_object));
6042 CHECK(access_other0->Run()->IsUndefined());
6043 CHECK(!access_other1->Run()->Equals(v8_num(87)));
6044 CHECK(access_other1->Run()->IsUndefined());
6045 }
6046
6047 // Create an object that has 'other' in its prototype chain and make
6048 // sure we cannot access the Object function indirectly through
6049 // that. Repeat in a loop to make sure to exercise the IC code.
6050 v8_compile("function F() { };"
6051 "F.prototype = other;"
6052 "var f = new F();")->Run();
6053 v8::Local<Script> access_f0 = v8_compile("f.Object");
6054 v8::Local<Script> access_f1 = v8_compile("f[42]");
6055 for (int j = 0; j < 5; j++) {
6056 CHECK(!access_f0->Run()->Equals(other_object));
6057 CHECK(access_f0->Run()->IsUndefined());
6058 CHECK(!access_f1->Run()->Equals(v8_num(87)));
6059 CHECK(access_f1->Run()->IsUndefined());
6060 }
6061
6062 // Now it gets hairy: Set the prototype for the other global object
6063 // to be the current global object. The prototype chain for 'f' now
6064 // goes through 'other' but ends up in the current global object.
6065 { Context::Scope scope(other);
6066 other->Global()->Set(v8_str("__proto__"), current->Global());
6067 }
6068 // Set a named and an index property on the current global
6069 // object. To force the lookup to go through the other global object,
6070 // the properties must not exist in the other global object.
6071 current->Global()->Set(v8_str("foo"), v8_num(100));
6072 current->Global()->Set(v8_num(99), v8_num(101));
6073 // Try to read the properties from f and make sure that the access
6074 // gets stopped by the security checks on the other global object.
6075 Local<Script> access_f2 = v8_compile("f.foo");
6076 Local<Script> access_f3 = v8_compile("f[99]");
6077 for (int k = 0; k < 5; k++) {
6078 CHECK(!access_f2->Run()->Equals(v8_num(100)));
6079 CHECK(access_f2->Run()->IsUndefined());
6080 CHECK(!access_f3->Run()->Equals(v8_num(101)));
6081 CHECK(access_f3->Run()->IsUndefined());
6082 }
6083 other.Dispose();
6084}
6085
6086
6087THREADED_TEST(CrossDomainDelete) {
6088 v8::HandleScope handle_scope;
6089 LocalContext env1;
6090 v8::Persistent<Context> env2 = Context::New();
6091
6092 Local<Value> foo = v8_str("foo");
6093 Local<Value> bar = v8_str("bar");
6094
6095 // Set to the same domain.
6096 env1->SetSecurityToken(foo);
6097 env2->SetSecurityToken(foo);
6098
6099 env1->Global()->Set(v8_str("prop"), v8_num(3));
6100 env2->Global()->Set(v8_str("env1"), env1->Global());
6101
6102 // Change env2 to a different domain and delete env1.prop.
6103 env2->SetSecurityToken(bar);
6104 {
6105 Context::Scope scope_env2(env2);
6106 Local<Value> result =
6107 Script::Compile(v8_str("delete env1.prop"))->Run();
6108 CHECK(result->IsFalse());
6109 }
6110
6111 // Check that env1.prop still exists.
6112 Local<Value> v = env1->Global()->Get(v8_str("prop"));
6113 CHECK(v->IsNumber());
6114 CHECK_EQ(3, v->Int32Value());
6115
6116 env2.Dispose();
6117}
6118
6119
ager@chromium.org870a0b62008-11-04 11:43:05 +00006120THREADED_TEST(CrossDomainIsPropertyEnumerable) {
6121 v8::HandleScope handle_scope;
6122 LocalContext env1;
6123 v8::Persistent<Context> env2 = Context::New();
6124
6125 Local<Value> foo = v8_str("foo");
6126 Local<Value> bar = v8_str("bar");
6127
6128 // Set to the same domain.
6129 env1->SetSecurityToken(foo);
6130 env2->SetSecurityToken(foo);
6131
6132 env1->Global()->Set(v8_str("prop"), v8_num(3));
6133 env2->Global()->Set(v8_str("env1"), env1->Global());
6134
6135 // env1.prop is enumerable in env2.
6136 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
6137 {
6138 Context::Scope scope_env2(env2);
6139 Local<Value> result = Script::Compile(test)->Run();
6140 CHECK(result->IsTrue());
6141 }
6142
6143 // Change env2 to a different domain and test again.
6144 env2->SetSecurityToken(bar);
6145 {
6146 Context::Scope scope_env2(env2);
6147 Local<Value> result = Script::Compile(test)->Run();
6148 CHECK(result->IsFalse());
6149 }
6150
6151 env2.Dispose();
6152}
6153
6154
ager@chromium.org236ad962008-09-25 09:45:57 +00006155THREADED_TEST(CrossDomainForIn) {
6156 v8::HandleScope handle_scope;
6157 LocalContext env1;
6158 v8::Persistent<Context> env2 = Context::New();
6159
6160 Local<Value> foo = v8_str("foo");
6161 Local<Value> bar = v8_str("bar");
6162
6163 // Set to the same domain.
6164 env1->SetSecurityToken(foo);
6165 env2->SetSecurityToken(foo);
6166
6167 env1->Global()->Set(v8_str("prop"), v8_num(3));
6168 env2->Global()->Set(v8_str("env1"), env1->Global());
6169
6170 // Change env2 to a different domain and set env1's global object
6171 // as the __proto__ of an object in env2 and enumerate properties
6172 // in for-in. It shouldn't enumerate properties on env1's global
6173 // object.
6174 env2->SetSecurityToken(bar);
6175 {
6176 Context::Scope scope_env2(env2);
6177 Local<Value> result =
6178 CompileRun("(function(){var obj = {'__proto__':env1};"
6179 "for (var p in obj)"
6180 " if (p == 'prop') return false;"
6181 "return true;})()");
6182 CHECK(result->IsTrue());
6183 }
6184 env2.Dispose();
6185}
6186
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006187
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006188TEST(ContextDetachGlobal) {
6189 v8::HandleScope handle_scope;
6190 LocalContext env1;
6191 v8::Persistent<Context> env2 = Context::New();
6192
6193 Local<v8::Object> global1 = env1->Global();
6194
6195 Local<Value> foo = v8_str("foo");
6196
6197 // Set to the same domain.
6198 env1->SetSecurityToken(foo);
6199 env2->SetSecurityToken(foo);
6200
6201 // Enter env2
6202 env2->Enter();
6203
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00006204 // Create a function in env2 and add a reference to it in env1.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006205 Local<v8::Object> global2 = env2->Global();
6206 global2->Set(v8_str("prop"), v8::Integer::New(1));
6207 CompileRun("function getProp() {return prop;}");
6208
6209 env1->Global()->Set(v8_str("getProp"),
6210 global2->Get(v8_str("getProp")));
6211
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00006212 // Detach env2's global, and reuse the global object of env2
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006213 env2->Exit();
6214 env2->DetachGlobal();
6215 // env2 has a new global object.
6216 CHECK(!env2->Global()->Equals(global2));
6217
6218 v8::Persistent<Context> env3 =
6219 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
6220 env3->SetSecurityToken(v8_str("bar"));
6221 env3->Enter();
6222
6223 Local<v8::Object> global3 = env3->Global();
6224 CHECK_EQ(global2, global3);
6225 CHECK(global3->Get(v8_str("prop"))->IsUndefined());
6226 CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
6227 global3->Set(v8_str("prop"), v8::Integer::New(-1));
6228 global3->Set(v8_str("prop2"), v8::Integer::New(2));
6229 env3->Exit();
6230
6231 // Call getProp in env1, and it should return the value 1
6232 {
6233 Local<Value> get_prop = global1->Get(v8_str("getProp"));
6234 CHECK(get_prop->IsFunction());
6235 v8::TryCatch try_catch;
6236 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
6237 CHECK(!try_catch.HasCaught());
6238 CHECK_EQ(1, r->Int32Value());
6239 }
6240
6241 // Check that env3 is not accessible from env1
6242 {
6243 Local<Value> r = global3->Get(v8_str("prop2"));
6244 CHECK(r->IsUndefined());
6245 }
6246
6247 env2.Dispose();
6248 env3.Dispose();
6249}
6250
6251
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00006252TEST(DetachAndReattachGlobal) {
6253 v8::HandleScope scope;
6254 LocalContext env1;
6255
6256 // Create second environment.
6257 v8::Persistent<Context> env2 = Context::New();
6258
6259 Local<Value> foo = v8_str("foo");
6260
6261 // Set same security token for env1 and env2.
6262 env1->SetSecurityToken(foo);
6263 env2->SetSecurityToken(foo);
6264
6265 // Create a property on the global object in env2.
6266 {
6267 v8::Context::Scope scope(env2);
6268 env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
6269 }
6270
6271 // Create a reference to env2 global from env1 global.
6272 env1->Global()->Set(v8_str("other"), env2->Global());
6273
6274 // Check that we have access to other.p in env2 from env1.
6275 Local<Value> result = CompileRun("other.p");
6276 CHECK(result->IsInt32());
6277 CHECK_EQ(42, result->Int32Value());
6278
6279 // Hold on to global from env2 and detach global from env2.
6280 Local<v8::Object> global2 = env2->Global();
6281 env2->DetachGlobal();
6282
6283 // Check that the global has been detached. No other.p property can
6284 // be found.
6285 result = CompileRun("other.p");
6286 CHECK(result->IsUndefined());
6287
6288 // Reuse global2 for env3.
6289 v8::Persistent<Context> env3 =
6290 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
6291 CHECK_EQ(global2, env3->Global());
6292
6293 // Start by using the same security token for env3 as for env1 and env2.
6294 env3->SetSecurityToken(foo);
6295
6296 // Create a property on the global object in env3.
6297 {
6298 v8::Context::Scope scope(env3);
6299 env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
6300 }
6301
6302 // Check that other.p is now the property in env3 and that we have access.
6303 result = CompileRun("other.p");
6304 CHECK(result->IsInt32());
6305 CHECK_EQ(24, result->Int32Value());
6306
6307 // Change security token for env3 to something different from env1 and env2.
6308 env3->SetSecurityToken(v8_str("bar"));
6309
6310 // Check that we do not have access to other.p in env1. |other| is now
6311 // the global object for env3 which has a different security token,
6312 // so access should be blocked.
6313 result = CompileRun("other.p");
6314 CHECK(result->IsUndefined());
6315
6316 // Detach the global for env3 and reattach it to env2.
6317 env3->DetachGlobal();
6318 env2->ReattachGlobal(global2);
6319
6320 // Check that we have access to other.p again in env1. |other| is now
6321 // the global object for env2 which has the same security token as env1.
6322 result = CompileRun("other.p");
6323 CHECK(result->IsInt32());
6324 CHECK_EQ(42, result->Int32Value());
6325
6326 env2.Dispose();
6327 env3.Dispose();
6328}
6329
6330
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006331static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006332static bool NamedAccessBlocker(Local<v8::Object> global,
6333 Local<Value> name,
6334 v8::AccessType type,
6335 Local<Value> data) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006336 return Context::GetCurrent()->Global()->Equals(global) ||
6337 allowed_access_type[type];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006338}
6339
6340
6341static bool IndexedAccessBlocker(Local<v8::Object> global,
6342 uint32_t key,
6343 v8::AccessType type,
6344 Local<Value> data) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006345 return Context::GetCurrent()->Global()->Equals(global) ||
6346 allowed_access_type[type];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006347}
6348
6349
6350static int g_echo_value = -1;
6351static v8::Handle<Value> EchoGetter(Local<String> name,
6352 const AccessorInfo& info) {
6353 return v8_num(g_echo_value);
6354}
6355
6356
6357static void EchoSetter(Local<String> name,
6358 Local<Value> value,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006359 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006360 if (value->IsNumber())
6361 g_echo_value = value->Int32Value();
6362}
6363
6364
6365static v8::Handle<Value> UnreachableGetter(Local<String> name,
6366 const AccessorInfo& info) {
6367 CHECK(false); // This function should not be called..
6368 return v8::Undefined();
6369}
6370
6371
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006372static void UnreachableSetter(Local<String>, Local<Value>,
6373 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006374 CHECK(false); // This function should nto be called.
6375}
6376
6377
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006378TEST(AccessControl) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006379 v8::HandleScope handle_scope;
6380 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
6381
6382 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
6383 IndexedAccessBlocker);
6384
6385 // Add an accessor accessible by cross-domain JS code.
6386 global_template->SetAccessor(
6387 v8_str("accessible_prop"),
6388 EchoGetter, EchoSetter,
6389 v8::Handle<Value>(),
6390 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
6391
6392 // Add an accessor that is not accessible by cross-domain JS code.
ager@chromium.org870a0b62008-11-04 11:43:05 +00006393 global_template->SetAccessor(v8_str("blocked_prop"),
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006394 UnreachableGetter, UnreachableSetter,
6395 v8::Handle<Value>(),
6396 v8::DEFAULT);
6397
6398 // Create an environment
6399 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6400 context0->Enter();
6401
6402 v8::Handle<v8::Object> global0 = context0->Global();
6403
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006404 // Define a property with JS getter and setter.
6405 CompileRun(
6406 "function getter() { return 'getter'; };\n"
6407 "function setter() { return 'setter'; }\n"
6408 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
6409
6410 Local<Value> getter = global0->Get(v8_str("getter"));
6411 Local<Value> setter = global0->Get(v8_str("setter"));
6412
6413 // And define normal element.
6414 global0->Set(239, v8_str("239"));
6415
6416 // Define an element with JS getter and setter.
6417 CompileRun(
6418 "function el_getter() { return 'el_getter'; };\n"
6419 "function el_setter() { return 'el_setter'; };\n"
6420 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
6421
6422 Local<Value> el_getter = global0->Get(v8_str("el_getter"));
6423 Local<Value> el_setter = global0->Get(v8_str("el_setter"));
6424
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006425 v8::HandleScope scope1;
6426
6427 v8::Persistent<Context> context1 = Context::New();
6428 context1->Enter();
6429
6430 v8::Handle<v8::Object> global1 = context1->Global();
6431 global1->Set(v8_str("other"), global0);
6432
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006433 // Access blocked property.
6434 CompileRun("other.blocked_prop = 1");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006435
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006436 ExpectUndefined("other.blocked_prop");
6437 ExpectUndefined(
6438 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
6439 ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006440
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006441 // Enable ACCESS_HAS
6442 allowed_access_type[v8::ACCESS_HAS] = true;
6443 ExpectUndefined("other.blocked_prop");
6444 // ... and now we can get the descriptor...
6445 ExpectUndefined(
antonm@chromium.orgdca01352011-01-31 17:15:05 +00006446 "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006447 // ... and enumerate the property.
6448 ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
6449 allowed_access_type[v8::ACCESS_HAS] = false;
antonm@chromium.orgdca01352011-01-31 17:15:05 +00006450
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006451 // Access blocked element.
6452 CompileRun("other[239] = 1");
6453
6454 ExpectUndefined("other[239]");
6455 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
6456 ExpectFalse("propertyIsEnumerable.call(other, '239')");
6457
6458 // Enable ACCESS_HAS
6459 allowed_access_type[v8::ACCESS_HAS] = true;
6460 ExpectUndefined("other[239]");
6461 // ... and now we can get the descriptor...
6462 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
6463 // ... and enumerate the property.
6464 ExpectTrue("propertyIsEnumerable.call(other, '239')");
6465 allowed_access_type[v8::ACCESS_HAS] = false;
6466
6467 // Access a property with JS accessor.
6468 CompileRun("other.js_accessor_p = 2");
6469
6470 ExpectUndefined("other.js_accessor_p");
6471 ExpectUndefined(
6472 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
6473
6474 // Enable ACCESS_HAS.
6475 allowed_access_type[v8::ACCESS_HAS] = true;
6476 ExpectUndefined("other.js_accessor_p");
6477 ExpectUndefined(
6478 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
6479 ExpectUndefined(
6480 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
6481 ExpectUndefined(
6482 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6483 allowed_access_type[v8::ACCESS_HAS] = false;
6484
6485 // Enable both ACCESS_HAS and ACCESS_GET.
6486 allowed_access_type[v8::ACCESS_HAS] = true;
6487 allowed_access_type[v8::ACCESS_GET] = true;
6488
6489 ExpectString("other.js_accessor_p", "getter");
6490 ExpectObject(
6491 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
6492 ExpectUndefined(
6493 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
6494 ExpectUndefined(
6495 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6496
6497 allowed_access_type[v8::ACCESS_GET] = false;
6498 allowed_access_type[v8::ACCESS_HAS] = false;
6499
6500 // Enable both ACCESS_HAS and ACCESS_SET.
6501 allowed_access_type[v8::ACCESS_HAS] = true;
6502 allowed_access_type[v8::ACCESS_SET] = true;
6503
6504 ExpectUndefined("other.js_accessor_p");
6505 ExpectUndefined(
6506 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
6507 ExpectObject(
6508 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
6509 ExpectUndefined(
6510 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6511
6512 allowed_access_type[v8::ACCESS_SET] = false;
6513 allowed_access_type[v8::ACCESS_HAS] = false;
6514
6515 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
6516 allowed_access_type[v8::ACCESS_HAS] = true;
6517 allowed_access_type[v8::ACCESS_GET] = true;
6518 allowed_access_type[v8::ACCESS_SET] = true;
6519
6520 ExpectString("other.js_accessor_p", "getter");
6521 ExpectObject(
6522 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
6523 ExpectObject(
6524 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
6525 ExpectUndefined(
6526 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6527
6528 allowed_access_type[v8::ACCESS_SET] = false;
6529 allowed_access_type[v8::ACCESS_GET] = false;
6530 allowed_access_type[v8::ACCESS_HAS] = false;
6531
6532 // Access an element with JS accessor.
6533 CompileRun("other[42] = 2");
6534
6535 ExpectUndefined("other[42]");
6536 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
6537
6538 // Enable ACCESS_HAS.
6539 allowed_access_type[v8::ACCESS_HAS] = true;
6540 ExpectUndefined("other[42]");
6541 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
6542 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
6543 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6544 allowed_access_type[v8::ACCESS_HAS] = false;
6545
6546 // Enable both ACCESS_HAS and ACCESS_GET.
6547 allowed_access_type[v8::ACCESS_HAS] = true;
6548 allowed_access_type[v8::ACCESS_GET] = true;
6549
6550 ExpectString("other[42]", "el_getter");
6551 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
6552 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
6553 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6554
6555 allowed_access_type[v8::ACCESS_GET] = false;
6556 allowed_access_type[v8::ACCESS_HAS] = false;
6557
6558 // Enable both ACCESS_HAS and ACCESS_SET.
6559 allowed_access_type[v8::ACCESS_HAS] = true;
6560 allowed_access_type[v8::ACCESS_SET] = true;
6561
6562 ExpectUndefined("other[42]");
6563 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
6564 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
6565 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6566
6567 allowed_access_type[v8::ACCESS_SET] = false;
6568 allowed_access_type[v8::ACCESS_HAS] = false;
6569
6570 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
6571 allowed_access_type[v8::ACCESS_HAS] = true;
6572 allowed_access_type[v8::ACCESS_GET] = true;
6573 allowed_access_type[v8::ACCESS_SET] = true;
6574
6575 ExpectString("other[42]", "el_getter");
6576 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
6577 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
6578 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6579
6580 allowed_access_type[v8::ACCESS_SET] = false;
6581 allowed_access_type[v8::ACCESS_GET] = false;
6582 allowed_access_type[v8::ACCESS_HAS] = false;
6583
6584 v8::Handle<Value> value;
ager@chromium.org870a0b62008-11-04 11:43:05 +00006585
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006586 // Access accessible property
antonm@chromium.orgdca01352011-01-31 17:15:05 +00006587 value = CompileRun("other.accessible_prop = 3");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006588 CHECK(value->IsNumber());
6589 CHECK_EQ(3, value->Int32Value());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006590 CHECK_EQ(3, g_echo_value);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006591
antonm@chromium.orgdca01352011-01-31 17:15:05 +00006592 value = CompileRun("other.accessible_prop");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006593 CHECK(value->IsNumber());
6594 CHECK_EQ(3, value->Int32Value());
6595
antonm@chromium.orgdca01352011-01-31 17:15:05 +00006596 value = CompileRun(
6597 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
6598 CHECK(value->IsNumber());
6599 CHECK_EQ(3, value->Int32Value());
6600
6601 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
ager@chromium.org870a0b62008-11-04 11:43:05 +00006602 CHECK(value->IsTrue());
6603
6604 // Enumeration doesn't enumerate accessors from inaccessible objects in
6605 // the prototype chain even if the accessors are in themselves accessible.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00006606 value =
ager@chromium.org870a0b62008-11-04 11:43:05 +00006607 CompileRun("(function(){var obj = {'__proto__':other};"
6608 "for (var p in obj)"
6609 " if (p == 'accessible_prop' || p == 'blocked_prop') {"
6610 " return false;"
6611 " }"
6612 "return true;})()");
antonm@chromium.orgdca01352011-01-31 17:15:05 +00006613 CHECK(value->IsTrue());
ager@chromium.org870a0b62008-11-04 11:43:05 +00006614
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006615 context1->Exit();
6616 context0->Exit();
6617 context1.Dispose();
6618 context0.Dispose();
6619}
6620
6621
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006622TEST(AccessControlES5) {
ricow@chromium.org65001782011-02-15 13:36:41 +00006623 v8::HandleScope handle_scope;
6624 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
6625
6626 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
6627 IndexedAccessBlocker);
6628
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00006629 // Add accessible accessor.
6630 global_template->SetAccessor(
6631 v8_str("accessible_prop"),
6632 EchoGetter, EchoSetter,
6633 v8::Handle<Value>(),
6634 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
6635
6636
ricow@chromium.org65001782011-02-15 13:36:41 +00006637 // Add an accessor that is not accessible by cross-domain JS code.
6638 global_template->SetAccessor(v8_str("blocked_prop"),
6639 UnreachableGetter, UnreachableSetter,
6640 v8::Handle<Value>(),
6641 v8::DEFAULT);
6642
6643 // Create an environment
6644 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6645 context0->Enter();
6646
6647 v8::Handle<v8::Object> global0 = context0->Global();
6648
6649 v8::Persistent<Context> context1 = Context::New();
6650 context1->Enter();
6651 v8::Handle<v8::Object> global1 = context1->Global();
6652 global1->Set(v8_str("other"), global0);
6653
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006654 // Regression test for issue 1154.
ricow@chromium.org65001782011-02-15 13:36:41 +00006655 ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006656
6657 ExpectUndefined("other.blocked_prop");
6658
6659 // Regression test for issue 1027.
6660 CompileRun("Object.defineProperty(\n"
6661 " other, 'blocked_prop', {configurable: false})");
6662 ExpectUndefined("other.blocked_prop");
6663 ExpectUndefined(
6664 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
6665
6666 // Regression test for issue 1171.
6667 ExpectTrue("Object.isExtensible(other)");
6668 CompileRun("Object.preventExtensions(other)");
6669 ExpectTrue("Object.isExtensible(other)");
6670
6671 // Object.seal and Object.freeze.
6672 CompileRun("Object.freeze(other)");
6673 ExpectTrue("Object.isExtensible(other)");
6674
6675 CompileRun("Object.seal(other)");
6676 ExpectTrue("Object.isExtensible(other)");
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00006677
6678 // Regression test for issue 1250.
6679 // Make sure that we can set the accessible accessors value using normal
6680 // assignment.
6681 CompileRun("other.accessible_prop = 42");
6682 CHECK_EQ(42, g_echo_value);
6683
6684 v8::Handle<Value> value;
6685 // We follow Safari in ignoring assignments to host object accessors.
6686 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
6687 value = CompileRun("other.accessible_prop == 42");
6688 CHECK(value->IsTrue());
ricow@chromium.org65001782011-02-15 13:36:41 +00006689}
6690
6691
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006692static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
6693 Local<Value> name,
6694 v8::AccessType type,
6695 Local<Value> data) {
6696 return false;
6697}
6698
6699
6700static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
6701 uint32_t key,
6702 v8::AccessType type,
6703 Local<Value> data) {
6704 return false;
6705}
6706
6707
6708THREADED_TEST(AccessControlGetOwnPropertyNames) {
6709 v8::HandleScope handle_scope;
6710 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
6711
6712 obj_template->Set(v8_str("x"), v8::Integer::New(42));
6713 obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
6714 GetOwnPropertyNamesIndexedBlocker);
6715
6716 // Create an environment
6717 v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
6718 context0->Enter();
6719
6720 v8::Handle<v8::Object> global0 = context0->Global();
6721
6722 v8::HandleScope scope1;
6723
6724 v8::Persistent<Context> context1 = Context::New();
6725 context1->Enter();
6726
6727 v8::Handle<v8::Object> global1 = context1->Global();
6728 global1->Set(v8_str("other"), global0);
6729 global1->Set(v8_str("object"), obj_template->NewInstance());
6730
6731 v8::Handle<Value> value;
6732
6733 // Attempt to get the property names of the other global object and
6734 // of an object that requires access checks. Accessing the other
6735 // global object should be blocked by access checks on the global
6736 // proxy object. Accessing the object that requires access checks
6737 // is blocked by the access checks on the object itself.
6738 value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
6739 CHECK(value->IsTrue());
6740
6741 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
6742 CHECK(value->IsTrue());
6743
6744 context1->Exit();
6745 context0->Exit();
6746 context1.Dispose();
6747 context0.Dispose();
6748}
6749
6750
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00006751static v8::Handle<v8::Array> NamedPropertyEnumerator(const AccessorInfo& info) {
6752 v8::Handle<v8::Array> result = v8::Array::New(1);
6753 result->Set(0, v8_str("x"));
6754 return result;
6755}
6756
6757
6758THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
6759 v8::HandleScope handle_scope;
6760 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
6761
6762 obj_template->Set(v8_str("x"), v8::Integer::New(42));
6763 obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
6764 NamedPropertyEnumerator);
6765
6766 LocalContext context;
6767 v8::Handle<v8::Object> global = context->Global();
6768 global->Set(v8_str("object"), obj_template->NewInstance());
6769
6770 v8::Handle<Value> value =
6771 CompileRun("Object.getOwnPropertyNames(object).join(',')");
6772 CHECK_EQ(v8_str("x"), value);
6773}
6774
6775
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006776static v8::Handle<Value> ConstTenGetter(Local<String> name,
6777 const AccessorInfo& info) {
6778 return v8_num(10);
6779}
6780
6781
6782THREADED_TEST(CrossDomainAccessors) {
6783 v8::HandleScope handle_scope;
6784
6785 v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
6786
6787 v8::Handle<v8::ObjectTemplate> global_template =
6788 func_template->InstanceTemplate();
6789
6790 v8::Handle<v8::ObjectTemplate> proto_template =
6791 func_template->PrototypeTemplate();
6792
6793 // Add an accessor to proto that's accessible by cross-domain JS code.
6794 proto_template->SetAccessor(v8_str("accessible"),
6795 ConstTenGetter, 0,
6796 v8::Handle<Value>(),
6797 v8::ALL_CAN_READ);
6798
6799 // Add an accessor that is not accessible by cross-domain JS code.
6800 global_template->SetAccessor(v8_str("unreachable"),
6801 UnreachableGetter, 0,
6802 v8::Handle<Value>(),
6803 v8::DEFAULT);
6804
6805 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6806 context0->Enter();
6807
6808 Local<v8::Object> global = context0->Global();
6809 // Add a normal property that shadows 'accessible'
6810 global->Set(v8_str("accessible"), v8_num(11));
6811
6812 // Enter a new context.
6813 v8::HandleScope scope1;
6814 v8::Persistent<Context> context1 = Context::New();
6815 context1->Enter();
6816
6817 v8::Handle<v8::Object> global1 = context1->Global();
6818 global1->Set(v8_str("other"), global);
6819
6820 // Should return 10, instead of 11
6821 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
6822 CHECK(value->IsNumber());
6823 CHECK_EQ(10, value->Int32Value());
6824
6825 value = v8_compile("other.unreachable")->Run();
6826 CHECK(value->IsUndefined());
6827
6828 context1->Exit();
6829 context0->Exit();
6830 context1.Dispose();
6831 context0.Dispose();
6832}
6833
6834
6835static int named_access_count = 0;
6836static int indexed_access_count = 0;
6837
6838static bool NamedAccessCounter(Local<v8::Object> global,
6839 Local<Value> name,
6840 v8::AccessType type,
6841 Local<Value> data) {
6842 named_access_count++;
6843 return true;
6844}
6845
6846
6847static bool IndexedAccessCounter(Local<v8::Object> global,
6848 uint32_t key,
6849 v8::AccessType type,
6850 Local<Value> data) {
6851 indexed_access_count++;
6852 return true;
6853}
6854
6855
6856// This one is too easily disturbed by other tests.
6857TEST(AccessControlIC) {
6858 named_access_count = 0;
6859 indexed_access_count = 0;
6860
6861 v8::HandleScope handle_scope;
6862
6863 // Create an environment.
6864 v8::Persistent<Context> context0 = Context::New();
6865 context0->Enter();
6866
6867 // Create an object that requires access-check functions to be
6868 // called for cross-domain access.
6869 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
6870 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
6871 IndexedAccessCounter);
6872 Local<v8::Object> object = object_template->NewInstance();
6873
6874 v8::HandleScope scope1;
6875
6876 // Create another environment.
6877 v8::Persistent<Context> context1 = Context::New();
6878 context1->Enter();
6879
6880 // Make easy access to the object from the other environment.
6881 v8::Handle<v8::Object> global1 = context1->Global();
6882 global1->Set(v8_str("obj"), object);
6883
6884 v8::Handle<Value> value;
6885
6886 // Check that the named access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00006887 CompileRun("function testProp(obj) {"
6888 " for (var i = 0; i < 10; i++) obj.prop = 1;"
6889 " for (var j = 0; j < 10; j++) obj.prop;"
6890 " return obj.prop"
6891 "}");
6892 value = CompileRun("testProp(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006893 CHECK(value->IsNumber());
6894 CHECK_EQ(1, value->Int32Value());
6895 CHECK_EQ(21, named_access_count);
6896
6897 // Check that the named access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00006898 CompileRun("var p = 'prop';"
6899 "function testKeyed(obj) {"
6900 " for (var i = 0; i < 10; i++) obj[p] = 1;"
6901 " for (var j = 0; j < 10; j++) obj[p];"
6902 " return obj[p];"
6903 "}");
6904 // Use obj which requires access checks. No inline caching is used
6905 // in that case.
6906 value = CompileRun("testKeyed(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006907 CHECK(value->IsNumber());
6908 CHECK_EQ(1, value->Int32Value());
6909 CHECK_EQ(42, named_access_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00006910 // Force the inline caches into generic state and try again.
6911 CompileRun("testKeyed({ a: 0 })");
6912 CompileRun("testKeyed({ b: 0 })");
6913 value = CompileRun("testKeyed(obj)");
6914 CHECK(value->IsNumber());
6915 CHECK_EQ(1, value->Int32Value());
6916 CHECK_EQ(63, named_access_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006917
6918 // Check that the indexed access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00006919 CompileRun("function testIndexed(obj) {"
6920 " for (var i = 0; i < 10; i++) obj[0] = 1;"
6921 " for (var j = 0; j < 10; j++) obj[0];"
6922 " return obj[0]"
6923 "}");
6924 value = CompileRun("testIndexed(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006925 CHECK(value->IsNumber());
6926 CHECK_EQ(1, value->Int32Value());
6927 CHECK_EQ(21, indexed_access_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00006928 // Force the inline caches into generic state.
6929 CompileRun("testIndexed(new Array(1))");
6930 // Test that the indexed access check is called.
6931 value = CompileRun("testIndexed(obj)");
6932 CHECK(value->IsNumber());
6933 CHECK_EQ(1, value->Int32Value());
6934 CHECK_EQ(42, indexed_access_count);
6935
6936 // Check that the named access check is called when invoking
6937 // functions on an object that requires access checks.
6938 CompileRun("obj.f = function() {}");
6939 CompileRun("function testCallNormal(obj) {"
6940 " for (var i = 0; i < 10; i++) obj.f();"
6941 "}");
6942 CompileRun("testCallNormal(obj)");
6943 CHECK_EQ(74, named_access_count);
6944
6945 // Force obj into slow case.
6946 value = CompileRun("delete obj.prop");
6947 CHECK(value->BooleanValue());
6948 // Force inline caches into dictionary probing mode.
6949 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
6950 // Test that the named access check is called.
6951 value = CompileRun("testProp(obj);");
6952 CHECK(value->IsNumber());
6953 CHECK_EQ(1, value->Int32Value());
6954 CHECK_EQ(96, named_access_count);
6955
6956 // Force the call inline cache into dictionary probing mode.
6957 CompileRun("o.f = function() {}; testCallNormal(o)");
6958 // Test that the named access check is still called for each
6959 // invocation of the function.
6960 value = CompileRun("testCallNormal(obj)");
6961 CHECK_EQ(106, named_access_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006962
6963 context1->Exit();
6964 context0->Exit();
6965 context1.Dispose();
6966 context0.Dispose();
6967}
6968
6969
6970static bool NamedAccessFlatten(Local<v8::Object> global,
6971 Local<Value> name,
6972 v8::AccessType type,
6973 Local<Value> data) {
6974 char buf[100];
6975 int len;
6976
6977 CHECK(name->IsString());
6978
6979 memset(buf, 0x1, sizeof(buf));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006980 len = name.As<String>()->WriteAscii(buf);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006981 CHECK_EQ(4, len);
6982
6983 uint16_t buf2[100];
6984
6985 memset(buf, 0x1, sizeof(buf));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006986 len = name.As<String>()->Write(buf2);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006987 CHECK_EQ(4, len);
6988
6989 return true;
6990}
6991
6992
6993static bool IndexedAccessFlatten(Local<v8::Object> global,
6994 uint32_t key,
6995 v8::AccessType type,
6996 Local<Value> data) {
6997 return true;
6998}
6999
7000
7001// Regression test. In access checks, operations that may cause
7002// garbage collection are not allowed. It used to be the case that
7003// using the Write operation on a string could cause a garbage
7004// collection due to flattening of the string. This is no longer the
7005// case.
7006THREADED_TEST(AccessControlFlatten) {
7007 named_access_count = 0;
7008 indexed_access_count = 0;
7009
7010 v8::HandleScope handle_scope;
7011
7012 // Create an environment.
7013 v8::Persistent<Context> context0 = Context::New();
7014 context0->Enter();
7015
7016 // Create an object that requires access-check functions to be
7017 // called for cross-domain access.
7018 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
7019 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
7020 IndexedAccessFlatten);
7021 Local<v8::Object> object = object_template->NewInstance();
7022
7023 v8::HandleScope scope1;
7024
7025 // Create another environment.
7026 v8::Persistent<Context> context1 = Context::New();
7027 context1->Enter();
7028
7029 // Make easy access to the object from the other environment.
7030 v8::Handle<v8::Object> global1 = context1->Global();
7031 global1->Set(v8_str("obj"), object);
7032
7033 v8::Handle<Value> value;
7034
7035 value = v8_compile("var p = 'as' + 'df';")->Run();
7036 value = v8_compile("obj[p];")->Run();
7037
7038 context1->Exit();
7039 context0->Exit();
7040 context1.Dispose();
7041 context0.Dispose();
7042}
7043
7044
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007045static v8::Handle<Value> AccessControlNamedGetter(
7046 Local<String>, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007047 return v8::Integer::New(42);
7048}
7049
7050
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007051static v8::Handle<Value> AccessControlNamedSetter(
7052 Local<String>, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007053 return value;
7054}
7055
7056
7057static v8::Handle<Value> AccessControlIndexedGetter(
7058 uint32_t index,
7059 const AccessorInfo& info) {
7060 return v8_num(42);
7061}
7062
7063
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007064static v8::Handle<Value> AccessControlIndexedSetter(
7065 uint32_t, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007066 return value;
7067}
7068
7069
7070THREADED_TEST(AccessControlInterceptorIC) {
7071 named_access_count = 0;
7072 indexed_access_count = 0;
7073
7074 v8::HandleScope handle_scope;
7075
7076 // Create an environment.
7077 v8::Persistent<Context> context0 = Context::New();
7078 context0->Enter();
7079
7080 // Create an object that requires access-check functions to be
7081 // called for cross-domain access. The object also has interceptors
7082 // interceptor.
7083 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
7084 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
7085 IndexedAccessCounter);
7086 object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
7087 AccessControlNamedSetter);
7088 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
7089 AccessControlIndexedSetter);
7090 Local<v8::Object> object = object_template->NewInstance();
7091
7092 v8::HandleScope scope1;
7093
7094 // Create another environment.
7095 v8::Persistent<Context> context1 = Context::New();
7096 context1->Enter();
7097
7098 // Make easy access to the object from the other environment.
7099 v8::Handle<v8::Object> global1 = context1->Global();
7100 global1->Set(v8_str("obj"), object);
7101
7102 v8::Handle<Value> value;
7103
7104 // Check that the named access-control function is called every time
7105 // eventhough there is an interceptor on the object.
7106 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
7107 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
7108 "obj.x")->Run();
7109 CHECK(value->IsNumber());
7110 CHECK_EQ(42, value->Int32Value());
7111 CHECK_EQ(21, named_access_count);
7112
7113 value = v8_compile("var p = 'x';")->Run();
7114 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
7115 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
7116 "obj[p]")->Run();
7117 CHECK(value->IsNumber());
7118 CHECK_EQ(42, value->Int32Value());
7119 CHECK_EQ(42, named_access_count);
7120
7121 // Check that the indexed access-control function is called every
7122 // time eventhough there is an interceptor on the object.
7123 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
7124 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
7125 "obj[0]")->Run();
7126 CHECK(value->IsNumber());
7127 CHECK_EQ(42, value->Int32Value());
7128 CHECK_EQ(21, indexed_access_count);
7129
7130 context1->Exit();
7131 context0->Exit();
7132 context1.Dispose();
7133 context0.Dispose();
7134}
7135
7136
7137THREADED_TEST(Version) {
7138 v8::V8::GetVersion();
7139}
7140
7141
7142static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
7143 ApiTestFuzzer::Fuzz();
7144 return v8_num(12);
7145}
7146
7147
7148THREADED_TEST(InstanceProperties) {
7149 v8::HandleScope handle_scope;
7150 LocalContext context;
7151
7152 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7153 Local<ObjectTemplate> instance = t->InstanceTemplate();
7154
7155 instance->Set(v8_str("x"), v8_num(42));
7156 instance->Set(v8_str("f"),
7157 v8::FunctionTemplate::New(InstanceFunctionCallback));
7158
7159 Local<Value> o = t->GetFunction()->NewInstance();
7160
7161 context->Global()->Set(v8_str("i"), o);
7162 Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
7163 CHECK_EQ(42, value->Int32Value());
7164
7165 value = Script::Compile(v8_str("i.f()"))->Run();
7166 CHECK_EQ(12, value->Int32Value());
7167}
7168
7169
7170static v8::Handle<Value>
7171GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
7172 ApiTestFuzzer::Fuzz();
7173 return v8::Handle<Value>();
7174}
7175
7176
7177THREADED_TEST(GlobalObjectInstanceProperties) {
7178 v8::HandleScope handle_scope;
7179
7180 Local<Value> global_object;
7181
7182 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7183 t->InstanceTemplate()->SetNamedPropertyHandler(
7184 GlobalObjectInstancePropertiesGet);
7185 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7186 instance_template->Set(v8_str("x"), v8_num(42));
7187 instance_template->Set(v8_str("f"),
7188 v8::FunctionTemplate::New(InstanceFunctionCallback));
7189
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007190 // The script to check how Crankshaft compiles missing global function
7191 // invocations. function g is not defined and should throw on call.
7192 const char* script =
7193 "function wrapper(call) {"
7194 " var x = 0, y = 1;"
7195 " for (var i = 0; i < 1000; i++) {"
7196 " x += i * 100;"
7197 " y += i * 100;"
7198 " }"
7199 " if (call) g();"
7200 "}"
7201 "for (var i = 0; i < 17; i++) wrapper(false);"
7202 "var thrown = 0;"
7203 "try { wrapper(true); } catch (e) { thrown = 1; };"
7204 "thrown";
7205
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007206 {
7207 LocalContext env(NULL, instance_template);
7208 // Hold on to the global object so it can be used again in another
7209 // environment initialization.
7210 global_object = env->Global();
7211
7212 Local<Value> value = Script::Compile(v8_str("x"))->Run();
7213 CHECK_EQ(42, value->Int32Value());
7214 value = Script::Compile(v8_str("f()"))->Run();
7215 CHECK_EQ(12, value->Int32Value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007216 value = Script::Compile(v8_str(script))->Run();
7217 CHECK_EQ(1, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007218 }
7219
7220 {
7221 // Create new environment reusing the global object.
7222 LocalContext env(NULL, instance_template, global_object);
7223 Local<Value> value = Script::Compile(v8_str("x"))->Run();
7224 CHECK_EQ(42, value->Int32Value());
7225 value = Script::Compile(v8_str("f()"))->Run();
7226 CHECK_EQ(12, value->Int32Value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007227 value = Script::Compile(v8_str(script))->Run();
7228 CHECK_EQ(1, value->Int32Value());
7229 }
7230}
7231
7232
7233THREADED_TEST(CallKnownGlobalReceiver) {
7234 v8::HandleScope handle_scope;
7235
7236 Local<Value> global_object;
7237
7238 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7239 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7240
7241 // The script to check that we leave global object not
7242 // global object proxy on stack when we deoptimize from inside
7243 // arguments evaluation.
7244 // To provoke error we need to both force deoptimization
7245 // from arguments evaluation and to force CallIC to take
7246 // CallIC_Miss code path that can't cope with global proxy.
7247 const char* script =
7248 "function bar(x, y) { try { } finally { } }"
7249 "function baz(x) { try { } finally { } }"
7250 "function bom(x) { try { } finally { } }"
7251 "function foo(x) { bar([x], bom(2)); }"
7252 "for (var i = 0; i < 10000; i++) foo(1);"
7253 "foo";
7254
7255 Local<Value> foo;
7256 {
7257 LocalContext env(NULL, instance_template);
7258 // Hold on to the global object so it can be used again in another
7259 // environment initialization.
7260 global_object = env->Global();
7261 foo = Script::Compile(v8_str(script))->Run();
7262 }
7263
7264 {
7265 // Create new environment reusing the global object.
7266 LocalContext env(NULL, instance_template, global_object);
7267 env->Global()->Set(v8_str("foo"), foo);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007268 Local<Value> value(Script::Compile(v8_str("foo()"))->Run());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007269 }
7270}
7271
7272
7273static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
7274 ApiTestFuzzer::Fuzz();
7275 return v8_num(42);
7276}
7277
7278
7279static int shadow_y;
7280static int shadow_y_setter_call_count;
7281static int shadow_y_getter_call_count;
7282
7283
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007284static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007285 shadow_y_setter_call_count++;
7286 shadow_y = 42;
7287}
7288
7289
7290static v8::Handle<Value> ShadowYGetter(Local<String> name,
7291 const AccessorInfo& info) {
7292 ApiTestFuzzer::Fuzz();
7293 shadow_y_getter_call_count++;
7294 return v8_num(shadow_y);
7295}
7296
7297
7298static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
7299 const AccessorInfo& info) {
7300 return v8::Handle<Value>();
7301}
7302
7303
7304static v8::Handle<Value> ShadowNamedGet(Local<String> key,
7305 const AccessorInfo&) {
7306 return v8::Handle<Value>();
7307}
7308
7309
7310THREADED_TEST(ShadowObject) {
7311 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
7312 v8::HandleScope handle_scope;
7313
7314 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
7315 LocalContext context(NULL, global_template);
7316
7317 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7318 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
7319 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
7320 Local<ObjectTemplate> proto = t->PrototypeTemplate();
7321 Local<ObjectTemplate> instance = t->InstanceTemplate();
7322
7323 // Only allow calls of f on instances of t.
7324 Local<v8::Signature> signature = v8::Signature::New(t);
7325 proto->Set(v8_str("f"),
7326 v8::FunctionTemplate::New(ShadowFunctionCallback,
7327 Local<Value>(),
7328 signature));
7329 proto->Set(v8_str("x"), v8_num(12));
7330
7331 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
7332
7333 Local<Value> o = t->GetFunction()->NewInstance();
7334 context->Global()->Set(v8_str("__proto__"), o);
7335
7336 Local<Value> value =
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00007337 Script::Compile(v8_str("this.propertyIsEnumerable(0)"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007338 CHECK(value->IsBoolean());
7339 CHECK(!value->BooleanValue());
7340
7341 value = Script::Compile(v8_str("x"))->Run();
7342 CHECK_EQ(12, value->Int32Value());
7343
7344 value = Script::Compile(v8_str("f()"))->Run();
7345 CHECK_EQ(42, value->Int32Value());
7346
7347 Script::Compile(v8_str("y = 42"))->Run();
7348 CHECK_EQ(1, shadow_y_setter_call_count);
7349 value = Script::Compile(v8_str("y"))->Run();
7350 CHECK_EQ(1, shadow_y_getter_call_count);
7351 CHECK_EQ(42, value->Int32Value());
7352}
7353
7354
7355THREADED_TEST(HiddenPrototype) {
7356 v8::HandleScope handle_scope;
7357 LocalContext context;
7358
7359 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
7360 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
7361 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
7362 t1->SetHiddenPrototype(true);
7363 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
7364 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
7365 t2->SetHiddenPrototype(true);
7366 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
7367 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
7368 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
7369
7370 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
7371 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
7372 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
7373 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
7374
7375 // Setting the prototype on an object skips hidden prototypes.
7376 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7377 o0->Set(v8_str("__proto__"), o1);
7378 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7379 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7380 o0->Set(v8_str("__proto__"), o2);
7381 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7382 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7383 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7384 o0->Set(v8_str("__proto__"), o3);
7385 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7386 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7387 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7388 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
7389
7390 // Getting the prototype of o0 should get the first visible one
7391 // which is o3. Therefore, z should not be defined on the prototype
7392 // object.
7393 Local<Value> proto = o0->Get(v8_str("__proto__"));
7394 CHECK(proto->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007395 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007396}
7397
7398
ager@chromium.org5c838252010-02-19 08:53:10 +00007399THREADED_TEST(SetPrototype) {
7400 v8::HandleScope handle_scope;
7401 LocalContext context;
7402
7403 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
7404 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
7405 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
7406 t1->SetHiddenPrototype(true);
7407 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
7408 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
7409 t2->SetHiddenPrototype(true);
7410 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
7411 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
7412 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
7413
7414 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
7415 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
7416 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
7417 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
7418
7419 // Setting the prototype on an object does not skip hidden prototypes.
7420 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7421 CHECK(o0->SetPrototype(o1));
7422 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7423 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7424 CHECK(o1->SetPrototype(o2));
7425 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7426 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7427 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7428 CHECK(o2->SetPrototype(o3));
7429 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7430 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7431 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7432 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
7433
7434 // Getting the prototype of o0 should get the first visible one
7435 // which is o3. Therefore, z should not be defined on the prototype
7436 // object.
7437 Local<Value> proto = o0->Get(v8_str("__proto__"));
7438 CHECK(proto->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007439 CHECK_EQ(proto.As<v8::Object>(), o3);
ager@chromium.org5c838252010-02-19 08:53:10 +00007440
7441 // However, Object::GetPrototype ignores hidden prototype.
7442 Local<Value> proto0 = o0->GetPrototype();
7443 CHECK(proto0->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007444 CHECK_EQ(proto0.As<v8::Object>(), o1);
ager@chromium.org5c838252010-02-19 08:53:10 +00007445
7446 Local<Value> proto1 = o1->GetPrototype();
7447 CHECK(proto1->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007448 CHECK_EQ(proto1.As<v8::Object>(), o2);
ager@chromium.org5c838252010-02-19 08:53:10 +00007449
7450 Local<Value> proto2 = o2->GetPrototype();
7451 CHECK(proto2->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007452 CHECK_EQ(proto2.As<v8::Object>(), o3);
ager@chromium.org5c838252010-02-19 08:53:10 +00007453}
7454
7455
ricow@chromium.org27bf2882011-11-17 08:34:43 +00007456// Getting property names of an object with a prototype chain that
7457// triggers dictionary elements in GetLocalPropertyNames() shouldn't
7458// crash the runtime.
7459THREADED_TEST(Regress91517) {
7460 i::FLAG_allow_natives_syntax = true;
7461 v8::HandleScope handle_scope;
7462 LocalContext context;
7463
7464 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
7465 t1->SetHiddenPrototype(true);
7466 t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
7467 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
7468 t2->SetHiddenPrototype(true);
7469 t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
7470 t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New());
7471 t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
7472 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
7473 t3->SetHiddenPrototype(true);
7474 t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
7475 Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New();
7476 t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
7477
7478 // Force dictionary-based properties.
7479 i::ScopedVector<char> name_buf(1024);
7480 for (int i = 1; i <= 1000; i++) {
7481 i::OS::SNPrintF(name_buf, "sdf%d", i);
7482 t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
7483 }
7484
7485 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
7486 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
7487 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
7488 Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
7489
7490 // Create prototype chain of hidden prototypes.
7491 CHECK(o4->SetPrototype(o3));
7492 CHECK(o3->SetPrototype(o2));
7493 CHECK(o2->SetPrototype(o1));
7494
7495 // Call the runtime version of GetLocalPropertyNames() on the natively
7496 // created object through JavaScript.
7497 context->Global()->Set(v8_str("obj"), o4);
7498 CompileRun("var names = %GetLocalPropertyNames(obj);");
7499
7500 ExpectInt32("names.length", 1006);
7501 ExpectTrue("names.indexOf(\"baz\") >= 0");
7502 ExpectTrue("names.indexOf(\"boo\") >= 0");
7503 ExpectTrue("names.indexOf(\"foo\") >= 0");
7504 ExpectTrue("names.indexOf(\"fuz1\") >= 0");
7505 ExpectTrue("names.indexOf(\"fuz2\") >= 0");
7506 ExpectFalse("names[1005] == undefined");
7507}
7508
7509
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007510THREADED_TEST(FunctionReadOnlyPrototype) {
ager@chromium.org04921a82011-06-27 13:21:41 +00007511 v8::HandleScope handle_scope;
7512 LocalContext context;
7513
7514 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007515 t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
7516 t1->ReadOnlyPrototype();
ager@chromium.org04921a82011-06-27 13:21:41 +00007517 context->Global()->Set(v8_str("func1"), t1->GetFunction());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007518 // Configured value of ReadOnly flag.
ager@chromium.org04921a82011-06-27 13:21:41 +00007519 CHECK(CompileRun(
7520 "(function() {"
7521 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007522 " return (descriptor['writable'] == false);"
ager@chromium.org04921a82011-06-27 13:21:41 +00007523 "})()")->BooleanValue());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007524 CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
7525 CHECK_EQ(42,
7526 CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
ager@chromium.org04921a82011-06-27 13:21:41 +00007527
7528 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007529 t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
ager@chromium.org04921a82011-06-27 13:21:41 +00007530 context->Global()->Set(v8_str("func2"), t2->GetFunction());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007531 // Default value of ReadOnly flag.
ager@chromium.org04921a82011-06-27 13:21:41 +00007532 CHECK(CompileRun(
7533 "(function() {"
7534 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007535 " return (descriptor['writable'] == true);"
ager@chromium.org04921a82011-06-27 13:21:41 +00007536 "})()")->BooleanValue());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007537 CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
ager@chromium.org04921a82011-06-27 13:21:41 +00007538}
7539
7540
ager@chromium.org5c838252010-02-19 08:53:10 +00007541THREADED_TEST(SetPrototypeThrows) {
7542 v8::HandleScope handle_scope;
7543 LocalContext context;
7544
7545 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7546
7547 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
7548 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
7549
7550 CHECK(o0->SetPrototype(o1));
7551 // If setting the prototype leads to the cycle, SetPrototype should
7552 // return false and keep VM in sane state.
7553 v8::TryCatch try_catch;
7554 CHECK(!o1->SetPrototype(o0));
7555 CHECK(!try_catch.HasCaught());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007556 ASSERT(!i::Isolate::Current()->has_pending_exception());
ager@chromium.org5c838252010-02-19 08:53:10 +00007557
7558 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
7559}
7560
7561
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007562THREADED_TEST(GetterSetterExceptions) {
7563 v8::HandleScope handle_scope;
7564 LocalContext context;
7565 CompileRun(
7566 "function Foo() { };"
7567 "function Throw() { throw 5; };"
7568 "var x = { };"
7569 "x.__defineSetter__('set', Throw);"
7570 "x.__defineGetter__('get', Throw);");
7571 Local<v8::Object> x =
7572 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
7573 v8::TryCatch try_catch;
7574 x->Set(v8_str("set"), v8::Integer::New(8));
7575 x->Get(v8_str("get"));
7576 x->Set(v8_str("set"), v8::Integer::New(8));
7577 x->Get(v8_str("get"));
7578 x->Set(v8_str("set"), v8::Integer::New(8));
7579 x->Get(v8_str("get"));
7580 x->Set(v8_str("set"), v8::Integer::New(8));
7581 x->Get(v8_str("get"));
7582}
7583
7584
7585THREADED_TEST(Constructor) {
7586 v8::HandleScope handle_scope;
7587 LocalContext context;
7588 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7589 templ->SetClassName(v8_str("Fun"));
7590 Local<Function> cons = templ->GetFunction();
7591 context->Global()->Set(v8_str("Fun"), cons);
7592 Local<v8::Object> inst = cons->NewInstance();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007593 i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007594 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
7595 CHECK(value->BooleanValue());
7596}
7597
lrn@chromium.org1c092762011-05-09 09:42:16 +00007598
7599static Handle<Value> ConstructorCallback(const Arguments& args) {
7600 ApiTestFuzzer::Fuzz();
7601 Local<Object> This;
7602
7603 if (args.IsConstructCall()) {
7604 Local<Object> Holder = args.Holder();
7605 This = Object::New();
7606 Local<Value> proto = Holder->GetPrototype();
7607 if (proto->IsObject()) {
7608 This->SetPrototype(proto);
7609 }
7610 } else {
7611 This = args.This();
7612 }
7613
7614 This->Set(v8_str("a"), args[0]);
7615 return This;
7616}
7617
7618
7619static Handle<Value> FakeConstructorCallback(const Arguments& args) {
7620 ApiTestFuzzer::Fuzz();
7621 return args[0];
7622}
7623
7624
7625THREADED_TEST(ConstructorForObject) {
7626 v8::HandleScope handle_scope;
7627 LocalContext context;
7628
7629 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7630 instance_template->SetCallAsFunctionHandler(ConstructorCallback);
7631 Local<Object> instance = instance_template->NewInstance();
7632 context->Global()->Set(v8_str("obj"), instance);
7633 v8::TryCatch try_catch;
7634 Local<Value> value;
7635 CHECK(!try_catch.HasCaught());
7636
7637 // Call the Object's constructor with a 32-bit signed integer.
7638 value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
7639 CHECK(!try_catch.HasCaught());
7640 CHECK(value->IsInt32());
7641 CHECK_EQ(28, value->Int32Value());
7642
7643 Local<Value> args1[] = { v8_num(28) };
7644 Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
7645 CHECK(value_obj1->IsObject());
7646 Local<Object> object1 = Local<Object>::Cast(value_obj1);
7647 value = object1->Get(v8_str("a"));
7648 CHECK(value->IsInt32());
7649 CHECK(!try_catch.HasCaught());
7650 CHECK_EQ(28, value->Int32Value());
7651
7652 // Call the Object's constructor with a String.
7653 value = CompileRun(
7654 "(function() { var o = new obj('tipli'); return o.a; })()");
7655 CHECK(!try_catch.HasCaught());
7656 CHECK(value->IsString());
7657 String::AsciiValue string_value1(value->ToString());
7658 CHECK_EQ("tipli", *string_value1);
7659
7660 Local<Value> args2[] = { v8_str("tipli") };
7661 Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
7662 CHECK(value_obj2->IsObject());
7663 Local<Object> object2 = Local<Object>::Cast(value_obj2);
7664 value = object2->Get(v8_str("a"));
7665 CHECK(!try_catch.HasCaught());
7666 CHECK(value->IsString());
7667 String::AsciiValue string_value2(value->ToString());
7668 CHECK_EQ("tipli", *string_value2);
7669
7670 // Call the Object's constructor with a Boolean.
7671 value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
7672 CHECK(!try_catch.HasCaught());
7673 CHECK(value->IsBoolean());
7674 CHECK_EQ(true, value->BooleanValue());
7675
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00007676 Handle<Value> args3[] = { v8::True() };
lrn@chromium.org1c092762011-05-09 09:42:16 +00007677 Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
7678 CHECK(value_obj3->IsObject());
7679 Local<Object> object3 = Local<Object>::Cast(value_obj3);
7680 value = object3->Get(v8_str("a"));
7681 CHECK(!try_catch.HasCaught());
7682 CHECK(value->IsBoolean());
7683 CHECK_EQ(true, value->BooleanValue());
7684
7685 // Call the Object's constructor with undefined.
7686 Handle<Value> args4[] = { v8::Undefined() };
7687 Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
7688 CHECK(value_obj4->IsObject());
7689 Local<Object> object4 = Local<Object>::Cast(value_obj4);
7690 value = object4->Get(v8_str("a"));
7691 CHECK(!try_catch.HasCaught());
7692 CHECK(value->IsUndefined());
7693
7694 // Call the Object's constructor with null.
7695 Handle<Value> args5[] = { v8::Null() };
7696 Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
7697 CHECK(value_obj5->IsObject());
7698 Local<Object> object5 = Local<Object>::Cast(value_obj5);
7699 value = object5->Get(v8_str("a"));
7700 CHECK(!try_catch.HasCaught());
7701 CHECK(value->IsNull());
7702 }
7703
7704 // Check exception handling when there is no constructor set for the Object.
7705 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7706 Local<Object> instance = instance_template->NewInstance();
7707 context->Global()->Set(v8_str("obj2"), instance);
7708 v8::TryCatch try_catch;
7709 Local<Value> value;
7710 CHECK(!try_catch.HasCaught());
7711
7712 value = CompileRun("new obj2(28)");
7713 CHECK(try_catch.HasCaught());
7714 String::AsciiValue exception_value1(try_catch.Exception());
7715 CHECK_EQ("TypeError: object is not a function", *exception_value1);
7716 try_catch.Reset();
7717
7718 Local<Value> args[] = { v8_num(29) };
7719 value = instance->CallAsConstructor(1, args);
7720 CHECK(try_catch.HasCaught());
7721 String::AsciiValue exception_value2(try_catch.Exception());
7722 CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
7723 try_catch.Reset();
7724 }
7725
7726 // Check the case when constructor throws exception.
7727 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7728 instance_template->SetCallAsFunctionHandler(ThrowValue);
7729 Local<Object> instance = instance_template->NewInstance();
7730 context->Global()->Set(v8_str("obj3"), instance);
7731 v8::TryCatch try_catch;
7732 Local<Value> value;
7733 CHECK(!try_catch.HasCaught());
7734
7735 value = CompileRun("new obj3(22)");
7736 CHECK(try_catch.HasCaught());
7737 String::AsciiValue exception_value1(try_catch.Exception());
7738 CHECK_EQ("22", *exception_value1);
7739 try_catch.Reset();
7740
7741 Local<Value> args[] = { v8_num(23) };
7742 value = instance->CallAsConstructor(1, args);
7743 CHECK(try_catch.HasCaught());
7744 String::AsciiValue exception_value2(try_catch.Exception());
7745 CHECK_EQ("23", *exception_value2);
7746 try_catch.Reset();
7747 }
7748
7749 // Check whether constructor returns with an object or non-object.
7750 { Local<FunctionTemplate> function_template =
7751 FunctionTemplate::New(FakeConstructorCallback);
7752 Local<Function> function = function_template->GetFunction();
7753 Local<Object> instance1 = function;
7754 context->Global()->Set(v8_str("obj4"), instance1);
7755 v8::TryCatch try_catch;
7756 Local<Value> value;
7757 CHECK(!try_catch.HasCaught());
7758
7759 CHECK(instance1->IsObject());
7760 CHECK(instance1->IsFunction());
7761
7762 value = CompileRun("new obj4(28)");
7763 CHECK(!try_catch.HasCaught());
7764 CHECK(value->IsObject());
7765
7766 Local<Value> args1[] = { v8_num(28) };
7767 value = instance1->CallAsConstructor(1, args1);
7768 CHECK(!try_catch.HasCaught());
7769 CHECK(value->IsObject());
7770
7771 Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7772 instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
7773 Local<Object> instance2 = instance_template->NewInstance();
7774 context->Global()->Set(v8_str("obj5"), instance2);
7775 CHECK(!try_catch.HasCaught());
7776
7777 CHECK(instance2->IsObject());
7778 CHECK(!instance2->IsFunction());
7779
7780 value = CompileRun("new obj5(28)");
7781 CHECK(!try_catch.HasCaught());
7782 CHECK(!value->IsObject());
7783
7784 Local<Value> args2[] = { v8_num(28) };
7785 value = instance2->CallAsConstructor(1, args2);
7786 CHECK(!try_catch.HasCaught());
7787 CHECK(!value->IsObject());
7788 }
7789}
7790
7791
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007792THREADED_TEST(FunctionDescriptorException) {
7793 v8::HandleScope handle_scope;
7794 LocalContext context;
7795 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7796 templ->SetClassName(v8_str("Fun"));
7797 Local<Function> cons = templ->GetFunction();
7798 context->Global()->Set(v8_str("Fun"), cons);
7799 Local<Value> value = CompileRun(
7800 "function test() {"
7801 " try {"
7802 " (new Fun()).blah()"
7803 " } catch (e) {"
7804 " var str = String(e);"
7805 " if (str.indexOf('TypeError') == -1) return 1;"
7806 " if (str.indexOf('[object Fun]') != -1) return 2;"
whesse@chromium.org7a392b32011-01-31 11:30:36 +00007807 " if (str.indexOf('#<Fun>') == -1) return 3;"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007808 " return 0;"
7809 " }"
7810 " return 4;"
7811 "}"
7812 "test();");
7813 CHECK_EQ(0, value->Int32Value());
7814}
7815
7816
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007817THREADED_TEST(EvalAliasedDynamic) {
7818 v8::HandleScope scope;
7819 LocalContext current;
7820
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007821 // Tests where aliased eval can only be resolved dynamically.
7822 Local<Script> script =
7823 Script::Compile(v8_str("function f(x) { "
7824 " var foo = 2;"
7825 " with (x) { return eval('foo'); }"
7826 "}"
7827 "foo = 0;"
7828 "result1 = f(new Object());"
ager@chromium.orge2902be2009-06-08 12:21:35 +00007829 "result2 = f(this);"
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007830 "var x = new Object();"
7831 "x.eval = function(x) { return 1; };"
7832 "result3 = f(x);"));
7833 script->Run();
7834 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
7835 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
7836 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
7837
7838 v8::TryCatch try_catch;
7839 script =
7840 Script::Compile(v8_str("function f(x) { "
7841 " var bar = 2;"
7842 " with (x) { return eval('bar'); }"
7843 "}"
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007844 "result4 = f(this)"));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007845 script->Run();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007846 CHECK(!try_catch.HasCaught());
7847 CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
7848
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007849 try_catch.Reset();
7850}
7851
7852
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007853THREADED_TEST(CrossEval) {
7854 v8::HandleScope scope;
7855 LocalContext other;
7856 LocalContext current;
7857
7858 Local<String> token = v8_str("<security token>");
7859 other->SetSecurityToken(token);
7860 current->SetSecurityToken(token);
7861
7862 // Setup reference from current to other.
7863 current->Global()->Set(v8_str("other"), other->Global());
7864
7865 // Check that new variables are introduced in other context.
7866 Local<Script> script =
7867 Script::Compile(v8_str("other.eval('var foo = 1234')"));
7868 script->Run();
7869 Local<Value> foo = other->Global()->Get(v8_str("foo"));
7870 CHECK_EQ(1234, foo->Int32Value());
7871 CHECK(!current->Global()->Has(v8_str("foo")));
7872
7873 // Check that writing to non-existing properties introduces them in
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007874 // the other context.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007875 script =
7876 Script::Compile(v8_str("other.eval('na = 1234')"));
7877 script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007878 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
7879 CHECK(!current->Global()->Has(v8_str("na")));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007880
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007881 // Check that global variables in current context are not visible in other
7882 // context.
7883 v8::TryCatch try_catch;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007884 script =
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007885 Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007886 Local<Value> result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007887 CHECK(try_catch.HasCaught());
7888 try_catch.Reset();
7889
7890 // Check that local variables in current context are not visible in other
7891 // context.
7892 script =
7893 Script::Compile(v8_str("(function() { "
7894 " var baz = 87;"
7895 " return other.eval('baz');"
7896 "})();"));
7897 result = script->Run();
7898 CHECK(try_catch.HasCaught());
7899 try_catch.Reset();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007900
7901 // Check that global variables in the other environment are visible
7902 // when evaluting code.
7903 other->Global()->Set(v8_str("bis"), v8_num(1234));
7904 script = Script::Compile(v8_str("other.eval('bis')"));
7905 CHECK_EQ(1234, script->Run()->Int32Value());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007906 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007907
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007908 // Check that the 'this' pointer points to the global object evaluating
7909 // code.
7910 other->Global()->Set(v8_str("t"), other->Global());
7911 script = Script::Compile(v8_str("other.eval('this == t')"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007912 result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007913 CHECK(result->IsTrue());
7914 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007915
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007916 // Check that variables introduced in with-statement are not visible in
7917 // other context.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007918 script =
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007919 Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007920 result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007921 CHECK(try_catch.HasCaught());
7922 try_catch.Reset();
ager@chromium.org3bf7b912008-11-17 09:09:45 +00007923
7924 // Check that you cannot use 'eval.call' with another object than the
7925 // current global object.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00007926 script =
7927 Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
7928 result = script->Run();
7929 CHECK(try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007930}
7931
7932
ager@chromium.orge2902be2009-06-08 12:21:35 +00007933// Test that calling eval in a context which has been detached from
7934// its global throws an exception. This behavior is consistent with
7935// other JavaScript implementations.
7936THREADED_TEST(EvalInDetachedGlobal) {
7937 v8::HandleScope scope;
7938
7939 v8::Persistent<Context> context0 = Context::New();
7940 v8::Persistent<Context> context1 = Context::New();
7941
7942 // Setup function in context0 that uses eval from context0.
7943 context0->Enter();
7944 v8::Handle<v8::Value> fun =
7945 CompileRun("var x = 42;"
7946 "(function() {"
7947 " var e = eval;"
7948 " return function(s) { return e(s); }"
7949 "})()");
7950 context0->Exit();
7951
7952 // Put the function into context1 and call it before and after
7953 // detaching the global. Before detaching, the call succeeds and
7954 // after detaching and exception is thrown.
7955 context1->Enter();
7956 context1->Global()->Set(v8_str("fun"), fun);
7957 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
7958 CHECK_EQ(42, x_value->Int32Value());
7959 context0->DetachGlobal();
7960 v8::TryCatch catcher;
7961 x_value = CompileRun("fun('x')");
7962 CHECK(x_value.IsEmpty());
7963 CHECK(catcher.HasCaught());
7964 context1->Exit();
7965
7966 context1.Dispose();
7967 context0.Dispose();
7968}
7969
7970
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007971THREADED_TEST(CrossLazyLoad) {
7972 v8::HandleScope scope;
7973 LocalContext other;
7974 LocalContext current;
7975
7976 Local<String> token = v8_str("<security token>");
7977 other->SetSecurityToken(token);
7978 current->SetSecurityToken(token);
7979
7980 // Setup reference from current to other.
7981 current->Global()->Set(v8_str("other"), other->Global());
7982
7983 // Trigger lazy loading in other context.
7984 Local<Script> script =
7985 Script::Compile(v8_str("other.eval('new Date(42)')"));
7986 Local<Value> value = script->Run();
7987 CHECK_EQ(42.0, value->NumberValue());
7988}
7989
7990
7991static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
7992 ApiTestFuzzer::Fuzz();
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00007993 if (args.IsConstructCall()) {
7994 if (args[0]->IsInt32()) {
7995 return v8_num(-args[0]->Int32Value());
7996 }
7997 }
7998
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007999 return args[0];
8000}
8001
8002
8003// Test that a call handler can be set for objects which will allow
8004// non-function objects created through the API to be called as
8005// functions.
8006THREADED_TEST(CallAsFunction) {
8007 v8::HandleScope scope;
8008 LocalContext context;
8009
lrn@chromium.org1c092762011-05-09 09:42:16 +00008010 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8011 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
8012 instance_template->SetCallAsFunctionHandler(call_as_function);
8013 Local<v8::Object> instance = t->GetFunction()->NewInstance();
8014 context->Global()->Set(v8_str("obj"), instance);
8015 v8::TryCatch try_catch;
8016 Local<Value> value;
8017 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008018
lrn@chromium.org1c092762011-05-09 09:42:16 +00008019 value = CompileRun("obj(42)");
8020 CHECK(!try_catch.HasCaught());
8021 CHECK_EQ(42, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008022
lrn@chromium.org1c092762011-05-09 09:42:16 +00008023 value = CompileRun("(function(o){return o(49)})(obj)");
8024 CHECK(!try_catch.HasCaught());
8025 CHECK_EQ(49, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008026
lrn@chromium.org1c092762011-05-09 09:42:16 +00008027 // test special case of call as function
8028 value = CompileRun("[obj]['0'](45)");
8029 CHECK(!try_catch.HasCaught());
8030 CHECK_EQ(45, value->Int32Value());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008031
lrn@chromium.org1c092762011-05-09 09:42:16 +00008032 value = CompileRun("obj.call = Function.prototype.call;"
8033 "obj.call(null, 87)");
8034 CHECK(!try_catch.HasCaught());
8035 CHECK_EQ(87, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008036
lrn@chromium.org1c092762011-05-09 09:42:16 +00008037 // Regression tests for bug #1116356: Calling call through call/apply
8038 // must work for non-function receivers.
8039 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
8040 value = CompileRun(apply_99);
8041 CHECK(!try_catch.HasCaught());
8042 CHECK_EQ(99, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008043
lrn@chromium.org1c092762011-05-09 09:42:16 +00008044 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
8045 value = CompileRun(call_17);
8046 CHECK(!try_catch.HasCaught());
8047 CHECK_EQ(17, value->Int32Value());
ager@chromium.org9085a012009-05-11 19:22:57 +00008048
lrn@chromium.org1c092762011-05-09 09:42:16 +00008049 // Check that the call-as-function handler can be called through
8050 // new.
8051 value = CompileRun("new obj(43)");
8052 CHECK(!try_catch.HasCaught());
8053 CHECK_EQ(-43, value->Int32Value());
8054
8055 // Check that the call-as-function handler can be called through
8056 // the API.
8057 v8::Handle<Value> args[] = { v8_num(28) };
8058 value = instance->CallAsFunction(instance, 1, args);
8059 CHECK(!try_catch.HasCaught());
8060 CHECK_EQ(28, value->Int32Value());
8061 }
8062
8063 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008064 Local<ObjectTemplate> instance_template(t->InstanceTemplate());
lrn@chromium.org1c092762011-05-09 09:42:16 +00008065 Local<v8::Object> instance = t->GetFunction()->NewInstance();
8066 context->Global()->Set(v8_str("obj2"), instance);
8067 v8::TryCatch try_catch;
8068 Local<Value> value;
8069 CHECK(!try_catch.HasCaught());
8070
8071 // Call an object without call-as-function handler through the JS
8072 value = CompileRun("obj2(28)");
8073 CHECK(value.IsEmpty());
8074 CHECK(try_catch.HasCaught());
8075 String::AsciiValue exception_value1(try_catch.Exception());
8076 CHECK_EQ("TypeError: Property 'obj2' of object #<Object> is not a function",
8077 *exception_value1);
8078 try_catch.Reset();
8079
8080 // Call an object without call-as-function handler through the API
8081 value = CompileRun("obj2(28)");
8082 v8::Handle<Value> args[] = { v8_num(28) };
8083 value = instance->CallAsFunction(instance, 1, args);
8084 CHECK(value.IsEmpty());
8085 CHECK(try_catch.HasCaught());
8086 String::AsciiValue exception_value2(try_catch.Exception());
8087 CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
8088 try_catch.Reset();
8089 }
8090
8091 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8092 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
8093 instance_template->SetCallAsFunctionHandler(ThrowValue);
8094 Local<v8::Object> instance = t->GetFunction()->NewInstance();
8095 context->Global()->Set(v8_str("obj3"), instance);
8096 v8::TryCatch try_catch;
8097 Local<Value> value;
8098 CHECK(!try_catch.HasCaught());
8099
8100 // Catch the exception which is thrown by call-as-function handler
8101 value = CompileRun("obj3(22)");
8102 CHECK(try_catch.HasCaught());
8103 String::AsciiValue exception_value1(try_catch.Exception());
8104 CHECK_EQ("22", *exception_value1);
8105 try_catch.Reset();
8106
8107 v8::Handle<Value> args[] = { v8_num(23) };
8108 value = instance->CallAsFunction(instance, 1, args);
8109 CHECK(try_catch.HasCaught());
8110 String::AsciiValue exception_value2(try_catch.Exception());
8111 CHECK_EQ("23", *exception_value2);
8112 try_catch.Reset();
8113 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008114}
8115
8116
karlklose@chromium.org83a47282011-05-11 11:54:09 +00008117// Check whether a non-function object is callable.
8118THREADED_TEST(CallableObject) {
8119 v8::HandleScope scope;
8120 LocalContext context;
8121
8122 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8123 instance_template->SetCallAsFunctionHandler(call_as_function);
8124 Local<Object> instance = instance_template->NewInstance();
8125 v8::TryCatch try_catch;
8126
8127 CHECK(instance->IsCallable());
8128 CHECK(!try_catch.HasCaught());
8129 }
8130
8131 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8132 Local<Object> instance = instance_template->NewInstance();
8133 v8::TryCatch try_catch;
8134
8135 CHECK(!instance->IsCallable());
8136 CHECK(!try_catch.HasCaught());
8137 }
8138
8139 { Local<FunctionTemplate> function_template =
8140 FunctionTemplate::New(call_as_function);
8141 Local<Function> function = function_template->GetFunction();
8142 Local<Object> instance = function;
8143 v8::TryCatch try_catch;
8144
8145 CHECK(instance->IsCallable());
8146 CHECK(!try_catch.HasCaught());
8147 }
8148
8149 { Local<FunctionTemplate> function_template = FunctionTemplate::New();
8150 Local<Function> function = function_template->GetFunction();
8151 Local<Object> instance = function;
8152 v8::TryCatch try_catch;
8153
8154 CHECK(instance->IsCallable());
8155 CHECK(!try_catch.HasCaught());
8156 }
8157}
8158
8159
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008160static int CountHandles() {
8161 return v8::HandleScope::NumberOfHandles();
8162}
8163
8164
8165static int Recurse(int depth, int iterations) {
8166 v8::HandleScope scope;
8167 if (depth == 0) return CountHandles();
8168 for (int i = 0; i < iterations; i++) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008169 Local<v8::Number> n(v8::Integer::New(42));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008170 }
8171 return Recurse(depth - 1, iterations);
8172}
8173
8174
8175THREADED_TEST(HandleIteration) {
8176 static const int kIterations = 500;
8177 static const int kNesting = 200;
8178 CHECK_EQ(0, CountHandles());
8179 {
8180 v8::HandleScope scope1;
8181 CHECK_EQ(0, CountHandles());
8182 for (int i = 0; i < kIterations; i++) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008183 Local<v8::Number> n(v8::Integer::New(42));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008184 CHECK_EQ(i + 1, CountHandles());
8185 }
8186
8187 CHECK_EQ(kIterations, CountHandles());
8188 {
8189 v8::HandleScope scope2;
8190 for (int j = 0; j < kIterations; j++) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008191 Local<v8::Number> n(v8::Integer::New(42));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008192 CHECK_EQ(j + 1 + kIterations, CountHandles());
8193 }
8194 }
8195 CHECK_EQ(kIterations, CountHandles());
8196 }
8197 CHECK_EQ(0, CountHandles());
8198 CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
8199}
8200
8201
8202static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
8203 Local<String> name,
8204 const AccessorInfo& info) {
8205 ApiTestFuzzer::Fuzz();
8206 return v8::Handle<Value>();
8207}
8208
8209
8210THREADED_TEST(InterceptorHasOwnProperty) {
8211 v8::HandleScope scope;
8212 LocalContext context;
8213 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8214 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
8215 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
8216 Local<Function> function = fun_templ->GetFunction();
8217 context->Global()->Set(v8_str("constructor"), function);
8218 v8::Handle<Value> value = CompileRun(
8219 "var o = new constructor();"
8220 "o.hasOwnProperty('ostehaps');");
8221 CHECK_EQ(false, value->BooleanValue());
8222 value = CompileRun(
8223 "o.ostehaps = 42;"
8224 "o.hasOwnProperty('ostehaps');");
8225 CHECK_EQ(true, value->BooleanValue());
8226 value = CompileRun(
8227 "var p = new constructor();"
8228 "p.hasOwnProperty('ostehaps');");
8229 CHECK_EQ(false, value->BooleanValue());
8230}
8231
8232
ager@chromium.org9085a012009-05-11 19:22:57 +00008233static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
8234 Local<String> name,
8235 const AccessorInfo& info) {
8236 ApiTestFuzzer::Fuzz();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008237 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org9085a012009-05-11 19:22:57 +00008238 return v8::Handle<Value>();
8239}
8240
8241
8242THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
8243 v8::HandleScope scope;
8244 LocalContext context;
8245 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8246 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
8247 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
8248 Local<Function> function = fun_templ->GetFunction();
8249 context->Global()->Set(v8_str("constructor"), function);
8250 // Let's first make some stuff so we can be sure to get a good GC.
8251 CompileRun(
8252 "function makestr(size) {"
8253 " switch (size) {"
8254 " case 1: return 'f';"
8255 " case 2: return 'fo';"
8256 " case 3: return 'foo';"
8257 " }"
8258 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
8259 "}"
8260 "var x = makestr(12345);"
8261 "x = makestr(31415);"
8262 "x = makestr(23456);");
8263 v8::Handle<Value> value = CompileRun(
8264 "var o = new constructor();"
8265 "o.__proto__ = new String(x);"
8266 "o.hasOwnProperty('ostehaps');");
8267 CHECK_EQ(false, value->BooleanValue());
8268}
8269
8270
ager@chromium.orge2902be2009-06-08 12:21:35 +00008271typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
8272 const AccessorInfo& info);
8273
8274
8275static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
8276 const char* source,
8277 int expected) {
8278 v8::HandleScope scope;
8279 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008280 templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
ager@chromium.orge2902be2009-06-08 12:21:35 +00008281 LocalContext context;
8282 context->Global()->Set(v8_str("o"), templ->NewInstance());
8283 v8::Handle<Value> value = CompileRun(source);
8284 CHECK_EQ(expected, value->Int32Value());
8285}
8286
8287
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008288static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
8289 const AccessorInfo& info) {
8290 ApiTestFuzzer::Fuzz();
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008291 CHECK_EQ(v8_str("data"), info.Data());
8292 CHECK_EQ(v8_str("x"), name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008293 return v8::Integer::New(42);
8294}
8295
8296
8297// This test should hit the load IC for the interceptor case.
8298THREADED_TEST(InterceptorLoadIC) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00008299 CheckInterceptorLoadIC(InterceptorLoadICGetter,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008300 "var result = 0;"
8301 "for (var i = 0; i < 1000; i++) {"
8302 " result = o.x;"
ager@chromium.orge2902be2009-06-08 12:21:35 +00008303 "}",
8304 42);
8305}
8306
8307
8308// Below go several tests which verify that JITing for various
8309// configurations of interceptor and explicit fields works fine
8310// (those cases are special cased to get better performance).
8311
8312static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
8313 const AccessorInfo& info) {
8314 ApiTestFuzzer::Fuzz();
8315 return v8_str("x")->Equals(name)
8316 ? v8::Integer::New(42) : v8::Handle<v8::Value>();
8317}
8318
8319
8320THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
8321 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8322 "var result = 0;"
8323 "o.y = 239;"
8324 "for (var i = 0; i < 1000; i++) {"
8325 " result = o.y;"
8326 "}",
8327 239);
8328}
8329
8330
8331THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
8332 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8333 "var result = 0;"
8334 "o.__proto__ = { 'y': 239 };"
8335 "for (var i = 0; i < 1000; i++) {"
8336 " result = o.y + o.x;"
8337 "}",
8338 239 + 42);
8339}
8340
8341
8342THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
8343 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8344 "var result = 0;"
8345 "o.__proto__.y = 239;"
8346 "for (var i = 0; i < 1000; i++) {"
8347 " result = o.y + o.x;"
8348 "}",
8349 239 + 42);
8350}
8351
8352
8353THREADED_TEST(InterceptorLoadICUndefined) {
8354 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8355 "var result = 0;"
8356 "for (var i = 0; i < 1000; i++) {"
8357 " result = (o.y == undefined) ? 239 : 42;"
8358 "}",
8359 239);
8360}
8361
8362
8363THREADED_TEST(InterceptorLoadICWithOverride) {
8364 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8365 "fst = new Object(); fst.__proto__ = o;"
8366 "snd = new Object(); snd.__proto__ = fst;"
8367 "var result1 = 0;"
8368 "for (var i = 0; i < 1000; i++) {"
8369 " result1 = snd.x;"
8370 "}"
8371 "fst.x = 239;"
8372 "var result = 0;"
8373 "for (var i = 0; i < 1000; i++) {"
8374 " result = snd.x;"
8375 "}"
8376 "result + result1",
8377 239 + 42);
8378}
8379
8380
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008381// Test the case when we stored field into
8382// a stub, but interceptor produced value on its own.
8383THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
8384 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8385 "proto = new Object();"
8386 "o.__proto__ = proto;"
8387 "proto.x = 239;"
8388 "for (var i = 0; i < 1000; i++) {"
8389 " o.x;"
8390 // Now it should be ICed and keep a reference to x defined on proto
8391 "}"
8392 "var result = 0;"
8393 "for (var i = 0; i < 1000; i++) {"
8394 " result += o.x;"
8395 "}"
8396 "result;",
8397 42 * 1000);
8398}
8399
8400
8401// Test the case when we stored field into
8402// a stub, but it got invalidated later on.
8403THREADED_TEST(InterceptorLoadICInvalidatedField) {
8404 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8405 "proto1 = new Object();"
8406 "proto2 = new Object();"
8407 "o.__proto__ = proto1;"
8408 "proto1.__proto__ = proto2;"
8409 "proto2.y = 239;"
8410 "for (var i = 0; i < 1000; i++) {"
8411 " o.y;"
8412 // Now it should be ICed and keep a reference to y defined on proto2
8413 "}"
8414 "proto1.y = 42;"
8415 "var result = 0;"
8416 "for (var i = 0; i < 1000; i++) {"
8417 " result += o.y;"
8418 "}"
8419 "result;",
8420 42 * 1000);
8421}
8422
8423
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00008424static int interceptor_load_not_handled_calls = 0;
8425static v8::Handle<Value> InterceptorLoadNotHandled(Local<String> name,
8426 const AccessorInfo& info) {
8427 ++interceptor_load_not_handled_calls;
8428 return v8::Handle<v8::Value>();
8429}
8430
8431
8432// Test how post-interceptor lookups are done in the non-cacheable
8433// case: the interceptor should not be invoked during this lookup.
8434THREADED_TEST(InterceptorLoadICPostInterceptor) {
8435 interceptor_load_not_handled_calls = 0;
8436 CheckInterceptorLoadIC(InterceptorLoadNotHandled,
8437 "receiver = new Object();"
8438 "receiver.__proto__ = o;"
8439 "proto = new Object();"
8440 "/* Make proto a slow-case object. */"
8441 "for (var i = 0; i < 1000; i++) {"
8442 " proto[\"xxxxxxxx\" + i] = [];"
8443 "}"
8444 "proto.x = 17;"
8445 "o.__proto__ = proto;"
8446 "var result = 0;"
8447 "for (var i = 0; i < 1000; i++) {"
8448 " result += receiver.x;"
8449 "}"
8450 "result;",
8451 17 * 1000);
8452 CHECK_EQ(1000, interceptor_load_not_handled_calls);
8453}
8454
8455
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008456// Test the case when we stored field into
8457// a stub, but it got invalidated later on due to override on
8458// global object which is between interceptor and fields' holders.
8459THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
8460 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8461 "o.__proto__ = this;" // set a global to be a proto of o.
8462 "this.__proto__.y = 239;"
8463 "for (var i = 0; i < 10; i++) {"
8464 " if (o.y != 239) throw 'oops: ' + o.y;"
8465 // Now it should be ICed and keep a reference to y defined on field_holder.
8466 "}"
8467 "this.y = 42;" // Assign on a global.
8468 "var result = 0;"
8469 "for (var i = 0; i < 10; i++) {"
8470 " result += o.y;"
8471 "}"
8472 "result;",
8473 42 * 10);
8474}
8475
8476
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008477static void SetOnThis(Local<String> name,
8478 Local<Value> value,
8479 const AccessorInfo& info) {
8480 info.This()->ForceSet(name, value);
8481}
8482
8483
8484THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
8485 v8::HandleScope scope;
8486 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8487 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8488 templ->SetAccessor(v8_str("y"), Return239);
8489 LocalContext context;
8490 context->Global()->Set(v8_str("o"), templ->NewInstance());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008491
8492 // Check the case when receiver and interceptor's holder
8493 // are the same objects.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008494 v8::Handle<Value> value = CompileRun(
8495 "var result = 0;"
8496 "for (var i = 0; i < 7; i++) {"
8497 " result = o.y;"
8498 "}");
8499 CHECK_EQ(239, value->Int32Value());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008500
8501 // Check the case when interceptor's holder is in proto chain
8502 // of receiver.
8503 value = CompileRun(
8504 "r = { __proto__: o };"
8505 "var result = 0;"
8506 "for (var i = 0; i < 7; i++) {"
8507 " result = r.y;"
8508 "}");
8509 CHECK_EQ(239, value->Int32Value());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008510}
8511
8512
8513THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
8514 v8::HandleScope scope;
8515 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8516 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8517 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8518 templ_p->SetAccessor(v8_str("y"), Return239);
8519
8520 LocalContext context;
8521 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8522 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8523
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008524 // Check the case when receiver and interceptor's holder
8525 // are the same objects.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008526 v8::Handle<Value> value = CompileRun(
8527 "o.__proto__ = p;"
8528 "var result = 0;"
8529 "for (var i = 0; i < 7; i++) {"
8530 " result = o.x + o.y;"
8531 "}");
8532 CHECK_EQ(239 + 42, value->Int32Value());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008533
8534 // Check the case when interceptor's holder is in proto chain
8535 // of receiver.
8536 value = CompileRun(
8537 "r = { __proto__: o };"
8538 "var result = 0;"
8539 "for (var i = 0; i < 7; i++) {"
8540 " result = r.x + r.y;"
8541 "}");
8542 CHECK_EQ(239 + 42, value->Int32Value());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008543}
8544
8545
8546THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
8547 v8::HandleScope scope;
8548 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8549 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8550 templ->SetAccessor(v8_str("y"), Return239);
8551
8552 LocalContext context;
8553 context->Global()->Set(v8_str("o"), templ->NewInstance());
8554
8555 v8::Handle<Value> value = CompileRun(
8556 "fst = new Object(); fst.__proto__ = o;"
8557 "snd = new Object(); snd.__proto__ = fst;"
8558 "var result1 = 0;"
8559 "for (var i = 0; i < 7; i++) {"
8560 " result1 = snd.x;"
8561 "}"
8562 "fst.x = 239;"
8563 "var result = 0;"
8564 "for (var i = 0; i < 7; i++) {"
8565 " result = snd.x;"
8566 "}"
8567 "result + result1");
8568 CHECK_EQ(239 + 42, value->Int32Value());
8569}
8570
8571
8572// Test the case when we stored callback into
8573// a stub, but interceptor produced value on its own.
8574THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
8575 v8::HandleScope scope;
8576 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8577 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8578 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8579 templ_p->SetAccessor(v8_str("y"), Return239);
8580
8581 LocalContext context;
8582 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8583 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8584
8585 v8::Handle<Value> value = CompileRun(
8586 "o.__proto__ = p;"
8587 "for (var i = 0; i < 7; i++) {"
8588 " o.x;"
8589 // Now it should be ICed and keep a reference to x defined on p
8590 "}"
8591 "var result = 0;"
8592 "for (var i = 0; i < 7; i++) {"
8593 " result += o.x;"
8594 "}"
8595 "result");
8596 CHECK_EQ(42 * 7, value->Int32Value());
8597}
8598
8599
8600// Test the case when we stored callback into
8601// a stub, but it got invalidated later on.
8602THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
8603 v8::HandleScope scope;
8604 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8605 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8606 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8607 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
8608
8609 LocalContext context;
8610 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8611 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8612
8613 v8::Handle<Value> value = CompileRun(
8614 "inbetween = new Object();"
8615 "o.__proto__ = inbetween;"
8616 "inbetween.__proto__ = p;"
8617 "for (var i = 0; i < 10; i++) {"
8618 " o.y;"
8619 // Now it should be ICed and keep a reference to y defined on p
8620 "}"
8621 "inbetween.y = 42;"
8622 "var result = 0;"
8623 "for (var i = 0; i < 10; i++) {"
8624 " result += o.y;"
8625 "}"
8626 "result");
8627 CHECK_EQ(42 * 10, value->Int32Value());
8628}
8629
8630
8631// Test the case when we stored callback into
8632// a stub, but it got invalidated later on due to override on
8633// global object which is between interceptor and callbacks' holders.
8634THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
8635 v8::HandleScope scope;
8636 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8637 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8638 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8639 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
8640
8641 LocalContext context;
8642 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8643 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8644
8645 v8::Handle<Value> value = CompileRun(
8646 "o.__proto__ = this;"
8647 "this.__proto__ = p;"
8648 "for (var i = 0; i < 10; i++) {"
8649 " if (o.y != 239) throw 'oops: ' + o.y;"
8650 // Now it should be ICed and keep a reference to y defined on p
8651 "}"
8652 "this.y = 42;"
8653 "var result = 0;"
8654 "for (var i = 0; i < 10; i++) {"
8655 " result += o.y;"
8656 "}"
8657 "result");
8658 CHECK_EQ(42 * 10, value->Int32Value());
8659}
8660
8661
ager@chromium.orge2902be2009-06-08 12:21:35 +00008662static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
8663 const AccessorInfo& info) {
8664 ApiTestFuzzer::Fuzz();
8665 CHECK(v8_str("x")->Equals(name));
8666 return v8::Integer::New(0);
8667}
8668
8669
8670THREADED_TEST(InterceptorReturningZero) {
8671 CheckInterceptorLoadIC(InterceptorLoadICGetter0,
8672 "o.x == undefined ? 1 : 0",
8673 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008674}
8675
8676
8677static v8::Handle<Value> InterceptorStoreICSetter(
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008678 Local<String> key, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008679 CHECK(v8_str("x")->Equals(key));
8680 CHECK_EQ(42, value->Int32Value());
8681 return value;
8682}
8683
8684
8685// This test should hit the store IC for the interceptor case.
8686THREADED_TEST(InterceptorStoreIC) {
8687 v8::HandleScope scope;
8688 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8689 templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008690 InterceptorStoreICSetter,
8691 0, 0, 0, v8_str("data"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008692 LocalContext context;
8693 context->Global()->Set(v8_str("o"), templ->NewInstance());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008694 v8::Handle<Value> value(CompileRun(
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008695 "for (var i = 0; i < 1000; i++) {"
8696 " o.x = 42;"
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008697 "}"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008698}
8699
8700
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008701THREADED_TEST(InterceptorStoreICWithNoSetter) {
8702 v8::HandleScope scope;
8703 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8704 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8705 LocalContext context;
8706 context->Global()->Set(v8_str("o"), templ->NewInstance());
8707 v8::Handle<Value> value = CompileRun(
8708 "for (var i = 0; i < 1000; i++) {"
8709 " o.y = 239;"
8710 "}"
8711 "42 + o.y");
8712 CHECK_EQ(239 + 42, value->Int32Value());
8713}
8714
8715
8716
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008717
8718v8::Handle<Value> call_ic_function;
8719v8::Handle<Value> call_ic_function2;
8720v8::Handle<Value> call_ic_function3;
8721
8722static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
8723 const AccessorInfo& info) {
8724 ApiTestFuzzer::Fuzz();
8725 CHECK(v8_str("x")->Equals(name));
8726 return call_ic_function;
8727}
8728
8729
8730// This test should hit the call IC for the interceptor case.
8731THREADED_TEST(InterceptorCallIC) {
8732 v8::HandleScope scope;
8733 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8734 templ->SetNamedPropertyHandler(InterceptorCallICGetter);
8735 LocalContext context;
8736 context->Global()->Set(v8_str("o"), templ->NewInstance());
8737 call_ic_function =
8738 v8_compile("function f(x) { return x + 1; }; f")->Run();
8739 v8::Handle<Value> value = CompileRun(
8740 "var result = 0;"
8741 "for (var i = 0; i < 1000; i++) {"
8742 " result = o.x(41);"
8743 "}");
8744 CHECK_EQ(42, value->Int32Value());
8745}
8746
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008747
8748// This test checks that if interceptor doesn't provide
8749// a value, we can fetch regular value.
8750THREADED_TEST(InterceptorCallICSeesOthers) {
8751 v8::HandleScope scope;
8752 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8753 templ->SetNamedPropertyHandler(NoBlockGetterX);
8754 LocalContext context;
8755 context->Global()->Set(v8_str("o"), templ->NewInstance());
8756 v8::Handle<Value> value = CompileRun(
8757 "o.x = function f(x) { return x + 1; };"
8758 "var result = 0;"
8759 "for (var i = 0; i < 7; i++) {"
8760 " result = o.x(41);"
8761 "}");
8762 CHECK_EQ(42, value->Int32Value());
8763}
8764
8765
8766static v8::Handle<Value> call_ic_function4;
8767static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
8768 const AccessorInfo& info) {
8769 ApiTestFuzzer::Fuzz();
8770 CHECK(v8_str("x")->Equals(name));
8771 return call_ic_function4;
8772}
8773
8774
8775// This test checks that if interceptor provides a function,
8776// even if we cached shadowed variant, interceptor's function
8777// is invoked
8778THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
8779 v8::HandleScope scope;
8780 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8781 templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
8782 LocalContext context;
8783 context->Global()->Set(v8_str("o"), templ->NewInstance());
8784 call_ic_function4 =
8785 v8_compile("function f(x) { return x - 1; }; f")->Run();
8786 v8::Handle<Value> value = CompileRun(
8787 "o.__proto__.x = function(x) { return x + 1; };"
8788 "var result = 0;"
8789 "for (var i = 0; i < 1000; i++) {"
8790 " result = o.x(42);"
8791 "}");
8792 CHECK_EQ(41, value->Int32Value());
8793}
8794
8795
8796// Test the case when we stored cacheable lookup into
8797// a stub, but it got invalidated later on
8798THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
8799 v8::HandleScope scope;
8800 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8801 templ->SetNamedPropertyHandler(NoBlockGetterX);
8802 LocalContext context;
8803 context->Global()->Set(v8_str("o"), templ->NewInstance());
8804 v8::Handle<Value> value = CompileRun(
8805 "proto1 = new Object();"
8806 "proto2 = new Object();"
8807 "o.__proto__ = proto1;"
8808 "proto1.__proto__ = proto2;"
8809 "proto2.y = function(x) { return x + 1; };"
8810 // Invoke it many times to compile a stub
8811 "for (var i = 0; i < 7; i++) {"
8812 " o.y(42);"
8813 "}"
8814 "proto1.y = function(x) { return x - 1; };"
8815 "var result = 0;"
8816 "for (var i = 0; i < 7; i++) {"
8817 " result += o.y(42);"
8818 "}");
8819 CHECK_EQ(41 * 7, value->Int32Value());
8820}
8821
8822
8823static v8::Handle<Value> call_ic_function5;
8824static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
8825 const AccessorInfo& info) {
8826 ApiTestFuzzer::Fuzz();
8827 if (v8_str("x")->Equals(name))
8828 return call_ic_function5;
8829 else
8830 return Local<Value>();
8831}
8832
8833
8834// This test checks that if interceptor doesn't provide a function,
8835// cached constant function is used
8836THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
8837 v8::HandleScope scope;
8838 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8839 templ->SetNamedPropertyHandler(NoBlockGetterX);
8840 LocalContext context;
8841 context->Global()->Set(v8_str("o"), templ->NewInstance());
8842 v8::Handle<Value> value = CompileRun(
8843 "function inc(x) { return x + 1; };"
8844 "inc(1);"
8845 "o.x = inc;"
8846 "var result = 0;"
8847 "for (var i = 0; i < 1000; i++) {"
8848 " result = o.x(42);"
8849 "}");
8850 CHECK_EQ(43, value->Int32Value());
8851}
8852
8853
8854// This test checks that if interceptor provides a function,
8855// even if we cached constant function, interceptor's function
8856// is invoked
8857THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
8858 v8::HandleScope scope;
8859 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8860 templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
8861 LocalContext context;
8862 context->Global()->Set(v8_str("o"), templ->NewInstance());
8863 call_ic_function5 =
8864 v8_compile("function f(x) { return x - 1; }; f")->Run();
8865 v8::Handle<Value> value = CompileRun(
8866 "function inc(x) { return x + 1; };"
8867 "inc(1);"
8868 "o.x = inc;"
8869 "var result = 0;"
8870 "for (var i = 0; i < 1000; i++) {"
8871 " result = o.x(42);"
8872 "}");
8873 CHECK_EQ(41, value->Int32Value());
8874}
8875
8876
8877// Test the case when we stored constant function into
8878// a stub, but it got invalidated later on
8879THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
8880 v8::HandleScope scope;
8881 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8882 templ->SetNamedPropertyHandler(NoBlockGetterX);
8883 LocalContext context;
8884 context->Global()->Set(v8_str("o"), templ->NewInstance());
8885 v8::Handle<Value> value = CompileRun(
8886 "function inc(x) { return x + 1; };"
8887 "inc(1);"
8888 "proto1 = new Object();"
8889 "proto2 = new Object();"
8890 "o.__proto__ = proto1;"
8891 "proto1.__proto__ = proto2;"
8892 "proto2.y = inc;"
8893 // Invoke it many times to compile a stub
8894 "for (var i = 0; i < 7; i++) {"
8895 " o.y(42);"
8896 "}"
8897 "proto1.y = function(x) { return x - 1; };"
8898 "var result = 0;"
8899 "for (var i = 0; i < 7; i++) {"
8900 " result += o.y(42);"
8901 "}");
8902 CHECK_EQ(41 * 7, value->Int32Value());
8903}
8904
8905
8906// Test the case when we stored constant function into
8907// a stub, but it got invalidated later on due to override on
8908// global object which is between interceptor and constant function' holders.
8909THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
8910 v8::HandleScope scope;
8911 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8912 templ->SetNamedPropertyHandler(NoBlockGetterX);
8913 LocalContext context;
8914 context->Global()->Set(v8_str("o"), templ->NewInstance());
8915 v8::Handle<Value> value = CompileRun(
8916 "function inc(x) { return x + 1; };"
8917 "inc(1);"
8918 "o.__proto__ = this;"
8919 "this.__proto__.y = inc;"
8920 // Invoke it many times to compile a stub
8921 "for (var i = 0; i < 7; i++) {"
8922 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
8923 "}"
8924 "this.y = function(x) { return x - 1; };"
8925 "var result = 0;"
8926 "for (var i = 0; i < 7; i++) {"
8927 " result += o.y(42);"
8928 "}");
8929 CHECK_EQ(41 * 7, value->Int32Value());
8930}
8931
8932
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008933// Test the case when actual function to call sits on global object.
8934THREADED_TEST(InterceptorCallICCachedFromGlobal) {
8935 v8::HandleScope scope;
8936 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8937 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
8938
8939 LocalContext context;
8940 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8941
8942 v8::Handle<Value> value = CompileRun(
8943 "try {"
8944 " o.__proto__ = this;"
8945 " for (var i = 0; i < 10; i++) {"
8946 " var v = o.parseFloat('239');"
8947 " if (v != 239) throw v;"
8948 // Now it should be ICed and keep a reference to parseFloat.
8949 " }"
8950 " var result = 0;"
8951 " for (var i = 0; i < 10; i++) {"
8952 " result += o.parseFloat('239');"
8953 " }"
8954 " result"
8955 "} catch(e) {"
8956 " e"
8957 "};");
8958 CHECK_EQ(239 * 10, value->Int32Value());
8959}
8960
ager@chromium.org5c838252010-02-19 08:53:10 +00008961static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
8962 const AccessorInfo& info) {
8963 ApiTestFuzzer::Fuzz();
8964 int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data()));
8965 ++(*call_count);
8966 if ((*call_count) % 20 == 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008967 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org5c838252010-02-19 08:53:10 +00008968 }
8969 return v8::Handle<Value>();
8970}
8971
8972static v8::Handle<Value> FastApiCallback_TrivialSignature(
8973 const v8::Arguments& args) {
8974 ApiTestFuzzer::Fuzz();
8975 CHECK_EQ(args.This(), args.Holder());
8976 CHECK(args.Data()->Equals(v8_str("method_data")));
8977 return v8::Integer::New(args[0]->Int32Value() + 1);
8978}
8979
8980static v8::Handle<Value> FastApiCallback_SimpleSignature(
8981 const v8::Arguments& args) {
8982 ApiTestFuzzer::Fuzz();
8983 CHECK_EQ(args.This()->GetPrototype(), args.Holder());
8984 CHECK(args.Data()->Equals(v8_str("method_data")));
8985 // Note, we're using HasRealNamedProperty instead of Has to avoid
8986 // invoking the interceptor again.
8987 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
8988 return v8::Integer::New(args[0]->Int32Value() + 1);
8989}
8990
8991// Helper to maximize the odds of object moving.
8992static void GenerateSomeGarbage() {
8993 CompileRun(
8994 "var garbage;"
8995 "for (var i = 0; i < 1000; i++) {"
8996 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
8997 "}"
8998 "garbage = undefined;");
8999}
9000
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009001
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009002v8::Handle<v8::Value> DirectApiCallback(const v8::Arguments& args) {
9003 static int count = 0;
9004 if (count++ % 3 == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009005 HEAP-> CollectAllGarbage(true); // This should move the stub
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009006 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
9007 }
9008 return v8::Handle<v8::Value>();
9009}
9010
9011
9012THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
9013 v8::HandleScope scope;
9014 LocalContext context;
9015 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
9016 nativeobject_templ->Set("callback",
9017 v8::FunctionTemplate::New(DirectApiCallback));
9018 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
9019 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
9020 // call the api function multiple times to ensure direct call stub creation.
9021 CompileRun(
9022 "function f() {"
9023 " for (var i = 1; i <= 30; i++) {"
9024 " nativeobject.callback();"
9025 " }"
9026 "}"
9027 "f();");
9028}
9029
9030
9031v8::Handle<v8::Value> ThrowingDirectApiCallback(const v8::Arguments& args) {
9032 return v8::ThrowException(v8_str("g"));
9033}
9034
9035
9036THREADED_TEST(CallICFastApi_DirectCall_Throw) {
9037 v8::HandleScope scope;
9038 LocalContext context;
9039 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
9040 nativeobject_templ->Set("callback",
9041 v8::FunctionTemplate::New(ThrowingDirectApiCallback));
9042 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
9043 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
9044 // call the api function multiple times to ensure direct call stub creation.
9045 v8::Handle<Value> result = CompileRun(
9046 "var result = '';"
9047 "function f() {"
9048 " for (var i = 1; i <= 5; i++) {"
9049 " try { nativeobject.callback(); } catch (e) { result += e; }"
9050 " }"
9051 "}"
9052 "f(); result;");
9053 CHECK_EQ(v8_str("ggggg"), result);
9054}
9055
9056
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009057v8::Handle<v8::Value> DirectGetterCallback(Local<String> name,
9058 const v8::AccessorInfo& info) {
9059 if (++p_getter_count % 3 == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009060 HEAP->CollectAllGarbage(true);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009061 GenerateSomeGarbage();
9062 }
9063 return v8::Handle<v8::Value>();
9064}
9065
9066
9067THREADED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
9068 v8::HandleScope scope;
9069 LocalContext context;
9070 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
9071 obj->SetAccessor(v8_str("p1"), DirectGetterCallback);
9072 context->Global()->Set(v8_str("o1"), obj->NewInstance());
9073 p_getter_count = 0;
9074 CompileRun(
9075 "function f() {"
9076 " for (var i = 0; i < 30; i++) o1.p1;"
9077 "}"
9078 "f();");
9079 CHECK_EQ(30, p_getter_count);
9080}
9081
9082
9083v8::Handle<v8::Value> ThrowingDirectGetterCallback(
9084 Local<String> name, const v8::AccessorInfo& info) {
9085 return v8::ThrowException(v8_str("g"));
9086}
9087
9088
9089THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
9090 v8::HandleScope scope;
9091 LocalContext context;
9092 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
9093 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
9094 context->Global()->Set(v8_str("o1"), obj->NewInstance());
9095 v8::Handle<Value> result = CompileRun(
9096 "var result = '';"
9097 "for (var i = 0; i < 5; i++) {"
9098 " try { o1.p1; } catch (e) { result += e; }"
9099 "}"
9100 "result;");
9101 CHECK_EQ(v8_str("ggggg"), result);
9102}
9103
9104
ager@chromium.org5c838252010-02-19 08:53:10 +00009105THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
9106 int interceptor_call_count = 0;
9107 v8::HandleScope scope;
9108 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9109 v8::Handle<v8::FunctionTemplate> method_templ =
9110 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
9111 v8_str("method_data"),
9112 v8::Handle<v8::Signature>());
9113 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9114 proto_templ->Set(v8_str("method"), method_templ);
9115 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9116 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9117 NULL, NULL, NULL, NULL,
9118 v8::External::Wrap(&interceptor_call_count));
9119 LocalContext context;
9120 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9121 GenerateSomeGarbage();
9122 context->Global()->Set(v8_str("o"), fun->NewInstance());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009123 v8::Handle<Value> value(CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +00009124 "var result = 0;"
9125 "for (var i = 0; i < 100; i++) {"
9126 " result = o.method(41);"
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009127 "}"));
ager@chromium.org5c838252010-02-19 08:53:10 +00009128 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9129 CHECK_EQ(100, interceptor_call_count);
9130}
9131
9132THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
9133 int interceptor_call_count = 0;
9134 v8::HandleScope scope;
9135 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9136 v8::Handle<v8::FunctionTemplate> method_templ =
9137 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9138 v8_str("method_data"),
9139 v8::Signature::New(fun_templ));
9140 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9141 proto_templ->Set(v8_str("method"), method_templ);
9142 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9143 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9144 NULL, NULL, NULL, NULL,
9145 v8::External::Wrap(&interceptor_call_count));
9146 LocalContext context;
9147 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9148 GenerateSomeGarbage();
9149 context->Global()->Set(v8_str("o"), fun->NewInstance());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009150 v8::Handle<Value> value(CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +00009151 "o.foo = 17;"
9152 "var receiver = {};"
9153 "receiver.__proto__ = o;"
9154 "var result = 0;"
9155 "for (var i = 0; i < 100; i++) {"
9156 " result = receiver.method(41);"
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009157 "}"));
ager@chromium.org5c838252010-02-19 08:53:10 +00009158 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9159 CHECK_EQ(100, interceptor_call_count);
9160}
9161
9162THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
9163 int interceptor_call_count = 0;
9164 v8::HandleScope scope;
9165 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9166 v8::Handle<v8::FunctionTemplate> method_templ =
9167 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9168 v8_str("method_data"),
9169 v8::Signature::New(fun_templ));
9170 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9171 proto_templ->Set(v8_str("method"), method_templ);
9172 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9173 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9174 NULL, NULL, NULL, NULL,
9175 v8::External::Wrap(&interceptor_call_count));
9176 LocalContext context;
9177 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9178 GenerateSomeGarbage();
9179 context->Global()->Set(v8_str("o"), fun->NewInstance());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009180 v8::Handle<Value> value(CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +00009181 "o.foo = 17;"
9182 "var receiver = {};"
9183 "receiver.__proto__ = o;"
9184 "var result = 0;"
9185 "var saved_result = 0;"
9186 "for (var i = 0; i < 100; i++) {"
9187 " result = receiver.method(41);"
9188 " if (i == 50) {"
9189 " saved_result = result;"
9190 " receiver = {method: function(x) { return x - 1 }};"
9191 " }"
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009192 "}"));
ager@chromium.org5c838252010-02-19 08:53:10 +00009193 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
9194 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9195 CHECK_GE(interceptor_call_count, 50);
9196}
9197
9198THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
9199 int interceptor_call_count = 0;
9200 v8::HandleScope scope;
9201 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9202 v8::Handle<v8::FunctionTemplate> method_templ =
9203 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9204 v8_str("method_data"),
9205 v8::Signature::New(fun_templ));
9206 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9207 proto_templ->Set(v8_str("method"), method_templ);
9208 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9209 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9210 NULL, NULL, NULL, NULL,
9211 v8::External::Wrap(&interceptor_call_count));
9212 LocalContext context;
9213 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9214 GenerateSomeGarbage();
9215 context->Global()->Set(v8_str("o"), fun->NewInstance());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009216 v8::Handle<Value> value(CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +00009217 "o.foo = 17;"
9218 "var receiver = {};"
9219 "receiver.__proto__ = o;"
9220 "var result = 0;"
9221 "var saved_result = 0;"
9222 "for (var i = 0; i < 100; i++) {"
9223 " result = receiver.method(41);"
9224 " if (i == 50) {"
9225 " saved_result = result;"
9226 " o.method = function(x) { return x - 1 };"
9227 " }"
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009228 "}"));
ager@chromium.org5c838252010-02-19 08:53:10 +00009229 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
9230 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9231 CHECK_GE(interceptor_call_count, 50);
9232}
9233
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00009234THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
9235 int interceptor_call_count = 0;
9236 v8::HandleScope scope;
9237 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9238 v8::Handle<v8::FunctionTemplate> method_templ =
9239 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9240 v8_str("method_data"),
9241 v8::Signature::New(fun_templ));
9242 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9243 proto_templ->Set(v8_str("method"), method_templ);
9244 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9245 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9246 NULL, NULL, NULL, NULL,
9247 v8::External::Wrap(&interceptor_call_count));
9248 LocalContext context;
9249 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9250 GenerateSomeGarbage();
9251 context->Global()->Set(v8_str("o"), fun->NewInstance());
9252 v8::TryCatch try_catch;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009253 v8::Handle<Value> value(CompileRun(
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00009254 "o.foo = 17;"
9255 "var receiver = {};"
9256 "receiver.__proto__ = o;"
9257 "var result = 0;"
9258 "var saved_result = 0;"
9259 "for (var i = 0; i < 100; i++) {"
9260 " result = receiver.method(41);"
9261 " if (i == 50) {"
9262 " saved_result = result;"
9263 " receiver = 333;"
9264 " }"
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009265 "}"));
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00009266 CHECK(try_catch.HasCaught());
9267 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
9268 try_catch.Exception()->ToString());
9269 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9270 CHECK_GE(interceptor_call_count, 50);
9271}
9272
ager@chromium.org5c838252010-02-19 08:53:10 +00009273THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
9274 int interceptor_call_count = 0;
9275 v8::HandleScope scope;
9276 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9277 v8::Handle<v8::FunctionTemplate> method_templ =
9278 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9279 v8_str("method_data"),
9280 v8::Signature::New(fun_templ));
9281 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9282 proto_templ->Set(v8_str("method"), method_templ);
9283 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9284 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9285 NULL, NULL, NULL, NULL,
9286 v8::External::Wrap(&interceptor_call_count));
9287 LocalContext context;
9288 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9289 GenerateSomeGarbage();
9290 context->Global()->Set(v8_str("o"), fun->NewInstance());
9291 v8::TryCatch try_catch;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009292 v8::Handle<Value> value(CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +00009293 "o.foo = 17;"
9294 "var receiver = {};"
9295 "receiver.__proto__ = o;"
9296 "var result = 0;"
9297 "var saved_result = 0;"
9298 "for (var i = 0; i < 100; i++) {"
9299 " result = receiver.method(41);"
9300 " if (i == 50) {"
9301 " saved_result = result;"
9302 " receiver = {method: receiver.method};"
9303 " }"
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009304 "}"));
ager@chromium.org5c838252010-02-19 08:53:10 +00009305 CHECK(try_catch.HasCaught());
9306 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
9307 try_catch.Exception()->ToString());
9308 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9309 CHECK_GE(interceptor_call_count, 50);
9310}
9311
9312THREADED_TEST(CallICFastApi_TrivialSignature) {
9313 v8::HandleScope scope;
9314 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9315 v8::Handle<v8::FunctionTemplate> method_templ =
9316 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
9317 v8_str("method_data"),
9318 v8::Handle<v8::Signature>());
9319 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9320 proto_templ->Set(v8_str("method"), method_templ);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009321 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
ager@chromium.org5c838252010-02-19 08:53:10 +00009322 LocalContext context;
9323 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9324 GenerateSomeGarbage();
9325 context->Global()->Set(v8_str("o"), fun->NewInstance());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009326 v8::Handle<Value> value(CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +00009327 "var result = 0;"
9328 "for (var i = 0; i < 100; i++) {"
9329 " result = o.method(41);"
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009330 "}"));
ager@chromium.org5c838252010-02-19 08:53:10 +00009331
9332 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9333}
9334
9335THREADED_TEST(CallICFastApi_SimpleSignature) {
9336 v8::HandleScope scope;
9337 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9338 v8::Handle<v8::FunctionTemplate> method_templ =
9339 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9340 v8_str("method_data"),
9341 v8::Signature::New(fun_templ));
9342 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9343 proto_templ->Set(v8_str("method"), method_templ);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009344 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
ager@chromium.org5c838252010-02-19 08:53:10 +00009345 LocalContext context;
9346 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9347 GenerateSomeGarbage();
9348 context->Global()->Set(v8_str("o"), fun->NewInstance());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009349 v8::Handle<Value> value(CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +00009350 "o.foo = 17;"
9351 "var receiver = {};"
9352 "receiver.__proto__ = o;"
9353 "var result = 0;"
9354 "for (var i = 0; i < 100; i++) {"
9355 " result = receiver.method(41);"
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009356 "}"));
ager@chromium.org5c838252010-02-19 08:53:10 +00009357
9358 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9359}
9360
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00009361THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) {
ager@chromium.org5c838252010-02-19 08:53:10 +00009362 v8::HandleScope scope;
9363 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9364 v8::Handle<v8::FunctionTemplate> method_templ =
9365 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9366 v8_str("method_data"),
9367 v8::Signature::New(fun_templ));
9368 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9369 proto_templ->Set(v8_str("method"), method_templ);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009370 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
ager@chromium.org5c838252010-02-19 08:53:10 +00009371 LocalContext context;
9372 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9373 GenerateSomeGarbage();
9374 context->Global()->Set(v8_str("o"), fun->NewInstance());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009375 v8::Handle<Value> value(CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +00009376 "o.foo = 17;"
9377 "var receiver = {};"
9378 "receiver.__proto__ = o;"
9379 "var result = 0;"
9380 "var saved_result = 0;"
9381 "for (var i = 0; i < 100; i++) {"
9382 " result = receiver.method(41);"
9383 " if (i == 50) {"
9384 " saved_result = result;"
9385 " receiver = {method: function(x) { return x - 1 }};"
9386 " }"
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009387 "}"));
ager@chromium.org5c838252010-02-19 08:53:10 +00009388 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
9389 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9390}
9391
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00009392THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) {
9393 v8::HandleScope scope;
9394 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9395 v8::Handle<v8::FunctionTemplate> method_templ =
9396 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9397 v8_str("method_data"),
9398 v8::Signature::New(fun_templ));
9399 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9400 proto_templ->Set(v8_str("method"), method_templ);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009401 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00009402 LocalContext context;
9403 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9404 GenerateSomeGarbage();
9405 context->Global()->Set(v8_str("o"), fun->NewInstance());
9406 v8::TryCatch try_catch;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009407 v8::Handle<Value> value(CompileRun(
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00009408 "o.foo = 17;"
9409 "var receiver = {};"
9410 "receiver.__proto__ = o;"
9411 "var result = 0;"
9412 "var saved_result = 0;"
9413 "for (var i = 0; i < 100; i++) {"
9414 " result = receiver.method(41);"
9415 " if (i == 50) {"
9416 " saved_result = result;"
9417 " receiver = 333;"
9418 " }"
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009419 "}"));
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00009420 CHECK(try_catch.HasCaught());
9421 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
9422 try_catch.Exception()->ToString());
9423 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9424}
9425
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009426
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009427v8::Handle<Value> keyed_call_ic_function;
9428
9429static v8::Handle<Value> InterceptorKeyedCallICGetter(
9430 Local<String> name, const AccessorInfo& info) {
9431 ApiTestFuzzer::Fuzz();
9432 if (v8_str("x")->Equals(name)) {
9433 return keyed_call_ic_function;
9434 }
9435 return v8::Handle<Value>();
9436}
9437
9438
9439// Test the case when we stored cacheable lookup into
9440// a stub, but the function name changed (to another cacheable function).
9441THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
9442 v8::HandleScope scope;
9443 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9444 templ->SetNamedPropertyHandler(NoBlockGetterX);
9445 LocalContext context;
9446 context->Global()->Set(v8_str("o"), templ->NewInstance());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009447 v8::Handle<Value> value(CompileRun(
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009448 "proto = new Object();"
9449 "proto.y = function(x) { return x + 1; };"
9450 "proto.z = function(x) { return x - 1; };"
9451 "o.__proto__ = proto;"
9452 "var result = 0;"
9453 "var method = 'y';"
9454 "for (var i = 0; i < 10; i++) {"
9455 " if (i == 5) { method = 'z'; };"
9456 " result += o[method](41);"
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009457 "}"));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009458 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9459}
9460
9461
9462// Test the case when we stored cacheable lookup into
9463// a stub, but the function name changed (and the new function is present
9464// both before and after the interceptor in the prototype chain).
9465THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
9466 v8::HandleScope scope;
9467 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9468 templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
9469 LocalContext context;
9470 context->Global()->Set(v8_str("proto1"), templ->NewInstance());
9471 keyed_call_ic_function =
9472 v8_compile("function f(x) { return x - 1; }; f")->Run();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009473 v8::Handle<Value> value(CompileRun(
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009474 "o = new Object();"
9475 "proto2 = new Object();"
9476 "o.y = function(x) { return x + 1; };"
9477 "proto2.y = function(x) { return x + 2; };"
9478 "o.__proto__ = proto1;"
9479 "proto1.__proto__ = proto2;"
9480 "var result = 0;"
9481 "var method = 'x';"
9482 "for (var i = 0; i < 10; i++) {"
9483 " if (i == 5) { method = 'y'; };"
9484 " result += o[method](41);"
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009485 "}"));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009486 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9487}
9488
9489
9490// Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
9491// on the global object.
9492THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
9493 v8::HandleScope scope;
9494 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9495 templ->SetNamedPropertyHandler(NoBlockGetterX);
9496 LocalContext context;
9497 context->Global()->Set(v8_str("o"), templ->NewInstance());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009498 v8::Handle<Value> value(CompileRun(
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009499 "function inc(x) { return x + 1; };"
9500 "inc(1);"
9501 "function dec(x) { return x - 1; };"
9502 "dec(1);"
9503 "o.__proto__ = this;"
9504 "this.__proto__.x = inc;"
9505 "this.__proto__.y = dec;"
9506 "var result = 0;"
9507 "var method = 'x';"
9508 "for (var i = 0; i < 10; i++) {"
9509 " if (i == 5) { method = 'y'; };"
9510 " result += o[method](41);"
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009511 "}"));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009512 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9513}
9514
9515
9516// Test the case when actual function to call sits on global object.
9517THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
9518 v8::HandleScope scope;
9519 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9520 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9521 LocalContext context;
9522 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9523
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009524 v8::Handle<Value> value(CompileRun(
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009525 "function len(x) { return x.length; };"
9526 "o.__proto__ = this;"
9527 "var m = 'parseFloat';"
9528 "var result = 0;"
9529 "for (var i = 0; i < 10; i++) {"
9530 " if (i == 5) {"
9531 " m = 'len';"
9532 " saved_result = result;"
9533 " };"
9534 " result = o[m]('239');"
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009535 "}"));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009536 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
9537 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9538}
9539
9540// Test the map transition before the interceptor.
9541THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
9542 v8::HandleScope scope;
9543 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9544 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9545 LocalContext context;
9546 context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
9547
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009548 v8::Handle<Value> value(CompileRun(
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009549 "var o = new Object();"
9550 "o.__proto__ = proto;"
9551 "o.method = function(x) { return x + 1; };"
9552 "var m = 'method';"
9553 "var result = 0;"
9554 "for (var i = 0; i < 10; i++) {"
9555 " if (i == 5) { o.method = function(x) { return x - 1; }; };"
9556 " result += o[m](41);"
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009557 "}"));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009558 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9559}
9560
9561
9562// Test the map transition after the interceptor.
9563THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
9564 v8::HandleScope scope;
9565 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9566 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9567 LocalContext context;
9568 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9569
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009570 v8::Handle<Value> value(CompileRun(
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009571 "var proto = new Object();"
9572 "o.__proto__ = proto;"
9573 "proto.method = function(x) { return x + 1; };"
9574 "var m = 'method';"
9575 "var result = 0;"
9576 "for (var i = 0; i < 10; i++) {"
9577 " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
9578 " result += o[m](41);"
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009579 "}"));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009580 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9581}
9582
9583
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009584static int interceptor_call_count = 0;
9585
9586static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
9587 const AccessorInfo& info) {
9588 ApiTestFuzzer::Fuzz();
9589 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
9590 return call_ic_function2;
9591 }
9592 return v8::Handle<Value>();
9593}
9594
9595
9596// This test should hit load and call ICs for the interceptor case.
9597// Once in a while, the interceptor will reply that a property was not
9598// found in which case we should get a reference error.
9599THREADED_TEST(InterceptorICReferenceErrors) {
9600 v8::HandleScope scope;
9601 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9602 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
9603 LocalContext context(0, templ, v8::Handle<Value>());
9604 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
9605 v8::Handle<Value> value = CompileRun(
9606 "function f() {"
9607 " for (var i = 0; i < 1000; i++) {"
9608 " try { x; } catch(e) { return true; }"
9609 " }"
9610 " return false;"
9611 "};"
9612 "f();");
9613 CHECK_EQ(true, value->BooleanValue());
9614 interceptor_call_count = 0;
9615 value = CompileRun(
9616 "function g() {"
9617 " for (var i = 0; i < 1000; i++) {"
9618 " try { x(42); } catch(e) { return true; }"
9619 " }"
9620 " return false;"
9621 "};"
9622 "g();");
9623 CHECK_EQ(true, value->BooleanValue());
9624}
9625
9626
9627static int interceptor_ic_exception_get_count = 0;
9628
9629static v8::Handle<Value> InterceptorICExceptionGetter(
9630 Local<String> name,
9631 const AccessorInfo& info) {
9632 ApiTestFuzzer::Fuzz();
9633 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
9634 return call_ic_function3;
9635 }
9636 if (interceptor_ic_exception_get_count == 20) {
9637 return v8::ThrowException(v8_num(42));
9638 }
9639 // Do not handle get for properties other than x.
9640 return v8::Handle<Value>();
9641}
9642
9643// Test interceptor load/call IC where the interceptor throws an
9644// exception once in a while.
9645THREADED_TEST(InterceptorICGetterExceptions) {
9646 interceptor_ic_exception_get_count = 0;
9647 v8::HandleScope scope;
9648 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9649 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
9650 LocalContext context(0, templ, v8::Handle<Value>());
9651 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
9652 v8::Handle<Value> value = CompileRun(
9653 "function f() {"
9654 " for (var i = 0; i < 100; i++) {"
9655 " try { x; } catch(e) { return true; }"
9656 " }"
9657 " return false;"
9658 "};"
9659 "f();");
9660 CHECK_EQ(true, value->BooleanValue());
9661 interceptor_ic_exception_get_count = 0;
9662 value = CompileRun(
9663 "function f() {"
9664 " for (var i = 0; i < 100; i++) {"
9665 " try { x(42); } catch(e) { return true; }"
9666 " }"
9667 " return false;"
9668 "};"
9669 "f();");
9670 CHECK_EQ(true, value->BooleanValue());
9671}
9672
9673
9674static int interceptor_ic_exception_set_count = 0;
9675
9676static v8::Handle<Value> InterceptorICExceptionSetter(
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009677 Local<String> key, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009678 ApiTestFuzzer::Fuzz();
9679 if (++interceptor_ic_exception_set_count > 20) {
9680 return v8::ThrowException(v8_num(42));
9681 }
9682 // Do not actually handle setting.
9683 return v8::Handle<Value>();
9684}
9685
9686// Test interceptor store IC where the interceptor throws an exception
9687// once in a while.
9688THREADED_TEST(InterceptorICSetterExceptions) {
9689 interceptor_ic_exception_set_count = 0;
9690 v8::HandleScope scope;
9691 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9692 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
9693 LocalContext context(0, templ, v8::Handle<Value>());
9694 v8::Handle<Value> value = CompileRun(
9695 "function f() {"
9696 " for (var i = 0; i < 100; i++) {"
9697 " try { x = 42; } catch(e) { return true; }"
9698 " }"
9699 " return false;"
9700 "};"
9701 "f();");
9702 CHECK_EQ(true, value->BooleanValue());
9703}
9704
9705
9706// Test that we ignore null interceptors.
9707THREADED_TEST(NullNamedInterceptor) {
9708 v8::HandleScope scope;
9709 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9710 templ->SetNamedPropertyHandler(0);
9711 LocalContext context;
9712 templ->Set("x", v8_num(42));
9713 v8::Handle<v8::Object> obj = templ->NewInstance();
9714 context->Global()->Set(v8_str("obj"), obj);
9715 v8::Handle<Value> value = CompileRun("obj.x");
9716 CHECK(value->IsInt32());
9717 CHECK_EQ(42, value->Int32Value());
9718}
9719
9720
9721// Test that we ignore null interceptors.
9722THREADED_TEST(NullIndexedInterceptor) {
9723 v8::HandleScope scope;
9724 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9725 templ->SetIndexedPropertyHandler(0);
9726 LocalContext context;
9727 templ->Set("42", v8_num(42));
9728 v8::Handle<v8::Object> obj = templ->NewInstance();
9729 context->Global()->Set(v8_str("obj"), obj);
9730 v8::Handle<Value> value = CompileRun("obj[42]");
9731 CHECK(value->IsInt32());
9732 CHECK_EQ(42, value->Int32Value());
9733}
9734
9735
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009736THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
9737 v8::HandleScope scope;
9738 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9739 templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9740 LocalContext env;
9741 env->Global()->Set(v8_str("obj"),
9742 templ->GetFunction()->NewInstance());
9743 ExpectTrue("obj.x === 42");
9744 ExpectTrue("!obj.propertyIsEnumerable('x')");
9745}
9746
9747
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009748static Handle<Value> ThrowingGetter(Local<String> name,
9749 const AccessorInfo& info) {
9750 ApiTestFuzzer::Fuzz();
9751 ThrowException(Handle<Value>());
9752 return Undefined();
9753}
9754
9755
9756THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
9757 HandleScope scope;
9758 LocalContext context;
9759
9760 Local<FunctionTemplate> templ = FunctionTemplate::New();
9761 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
9762 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
9763
9764 Local<Object> instance = templ->GetFunction()->NewInstance();
9765
9766 Local<Object> another = Object::New();
9767 another->SetPrototype(instance);
9768
9769 Local<Object> with_js_getter = CompileRun(
9770 "o = {};\n"
9771 "o.__defineGetter__('f', function() { throw undefined; });\n"
9772 "o\n").As<Object>();
9773 CHECK(!with_js_getter.IsEmpty());
9774
9775 TryCatch try_catch;
9776
9777 Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
9778 CHECK(try_catch.HasCaught());
9779 try_catch.Reset();
9780 CHECK(result.IsEmpty());
9781
9782 result = another->GetRealNamedProperty(v8_str("f"));
9783 CHECK(try_catch.HasCaught());
9784 try_catch.Reset();
9785 CHECK(result.IsEmpty());
9786
9787 result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
9788 CHECK(try_catch.HasCaught());
9789 try_catch.Reset();
9790 CHECK(result.IsEmpty());
9791
9792 result = another->Get(v8_str("f"));
9793 CHECK(try_catch.HasCaught());
9794 try_catch.Reset();
9795 CHECK(result.IsEmpty());
9796
9797 result = with_js_getter->GetRealNamedProperty(v8_str("f"));
9798 CHECK(try_catch.HasCaught());
9799 try_catch.Reset();
9800 CHECK(result.IsEmpty());
9801
9802 result = with_js_getter->Get(v8_str("f"));
9803 CHECK(try_catch.HasCaught());
9804 try_catch.Reset();
9805 CHECK(result.IsEmpty());
9806}
9807
9808
9809static Handle<Value> ThrowingCallbackWithTryCatch(const Arguments& args) {
9810 TryCatch try_catch;
9811 // Verboseness is important: it triggers message delivery which can call into
9812 // external code.
9813 try_catch.SetVerbose(true);
9814 CompileRun("throw 'from JS';");
9815 CHECK(try_catch.HasCaught());
9816 CHECK(!i::Isolate::Current()->has_pending_exception());
9817 CHECK(!i::Isolate::Current()->has_scheduled_exception());
9818 return Undefined();
9819}
9820
9821
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009822static int call_depth;
9823
9824
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009825static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
9826 TryCatch try_catch;
9827}
9828
9829
9830static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009831 if (--call_depth) CompileRun("throw 'ThrowInJS';");
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009832}
9833
9834
9835static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009836 if (--call_depth) ThrowException(v8_str("ThrowViaApi"));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009837}
9838
9839
9840static void WebKitLike(Handle<Message> message, Handle<Value> data) {
9841 Handle<String> errorMessageString = message->Get();
9842 CHECK(!errorMessageString.IsEmpty());
9843 message->GetStackTrace();
9844 message->GetScriptResourceName();
9845}
9846
9847THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
9848 HandleScope scope;
9849 LocalContext context;
9850
9851 Local<Function> func =
9852 FunctionTemplate::New(ThrowingCallbackWithTryCatch)->GetFunction();
9853 context->Global()->Set(v8_str("func"), func);
9854
9855 MessageCallback callbacks[] =
9856 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
9857 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
9858 MessageCallback callback = callbacks[i];
9859 if (callback != NULL) {
9860 V8::AddMessageListener(callback);
9861 }
ricow@chromium.orgdcebac02011-04-20 09:44:50 +00009862 // Some small number to control number of times message handler should
9863 // throw an exception.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009864 call_depth = 5;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009865 ExpectFalse(
9866 "var thrown = false;\n"
9867 "try { func(); } catch(e) { thrown = true; }\n"
9868 "thrown\n");
9869 if (callback != NULL) {
9870 V8::RemoveMessageListeners(callback);
9871 }
9872 }
9873}
9874
9875
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009876static v8::Handle<Value> ParentGetter(Local<String> name,
9877 const AccessorInfo& info) {
9878 ApiTestFuzzer::Fuzz();
9879 return v8_num(1);
9880}
9881
9882
9883static v8::Handle<Value> ChildGetter(Local<String> name,
9884 const AccessorInfo& info) {
9885 ApiTestFuzzer::Fuzz();
9886 return v8_num(42);
9887}
9888
9889
9890THREADED_TEST(Overriding) {
9891 v8::HandleScope scope;
9892 LocalContext context;
9893
9894 // Parent template.
9895 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
9896 Local<ObjectTemplate> parent_instance_templ =
9897 parent_templ->InstanceTemplate();
9898 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
9899
9900 // Template that inherits from the parent template.
9901 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
9902 Local<ObjectTemplate> child_instance_templ =
9903 child_templ->InstanceTemplate();
9904 child_templ->Inherit(parent_templ);
9905 // Override 'f'. The child version of 'f' should get called for child
9906 // instances.
9907 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
9908 // Add 'g' twice. The 'g' added last should get called for instances.
9909 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
9910 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
9911
9912 // Add 'h' as an accessor to the proto template with ReadOnly attributes
9913 // so 'h' can be shadowed on the instance object.
9914 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
9915 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
9916 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
9917
9918 // Add 'i' as an accessor to the instance template with ReadOnly attributes
9919 // but the attribute does not have effect because it is duplicated with
9920 // NULL setter.
9921 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
9922 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
9923
9924
9925
9926 // Instantiate the child template.
9927 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
9928
9929 // Check that the child function overrides the parent one.
9930 context->Global()->Set(v8_str("o"), instance);
9931 Local<Value> value = v8_compile("o.f")->Run();
9932 // Check that the 'g' that was added last is hit.
9933 CHECK_EQ(42, value->Int32Value());
9934 value = v8_compile("o.g")->Run();
9935 CHECK_EQ(42, value->Int32Value());
9936
9937 // Check 'h' can be shadowed.
9938 value = v8_compile("o.h = 3; o.h")->Run();
9939 CHECK_EQ(3, value->Int32Value());
9940
9941 // Check 'i' is cannot be shadowed or changed.
9942 value = v8_compile("o.i = 3; o.i")->Run();
9943 CHECK_EQ(42, value->Int32Value());
9944}
9945
9946
9947static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
9948 ApiTestFuzzer::Fuzz();
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009949 return v8::Boolean::New(args.IsConstructCall());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009950}
9951
9952
9953THREADED_TEST(IsConstructCall) {
9954 v8::HandleScope scope;
9955
9956 // Function template with call handler.
9957 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9958 templ->SetCallHandler(IsConstructHandler);
9959
9960 LocalContext context;
9961
9962 context->Global()->Set(v8_str("f"), templ->GetFunction());
9963 Local<Value> value = v8_compile("f()")->Run();
9964 CHECK(!value->BooleanValue());
9965 value = v8_compile("new f()")->Run();
9966 CHECK(value->BooleanValue());
9967}
9968
9969
9970THREADED_TEST(ObjectProtoToString) {
9971 v8::HandleScope scope;
9972 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9973 templ->SetClassName(v8_str("MyClass"));
9974
9975 LocalContext context;
9976
9977 Local<String> customized_tostring = v8_str("customized toString");
9978
9979 // Replace Object.prototype.toString
9980 v8_compile("Object.prototype.toString = function() {"
9981 " return 'customized toString';"
9982 "}")->Run();
9983
9984 // Normal ToString call should call replaced Object.prototype.toString
9985 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
9986 Local<String> value = instance->ToString();
9987 CHECK(value->IsString() && value->Equals(customized_tostring));
9988
9989 // ObjectProtoToString should not call replace toString function.
9990 value = instance->ObjectProtoToString();
9991 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
9992
9993 // Check global
9994 value = context->Global()->ObjectProtoToString();
9995 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
9996
9997 // Check ordinary object
9998 Local<Value> object = v8_compile("new Object()")->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009999 value = object.As<v8::Object>()->ObjectProtoToString();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010000 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
10001}
10002
10003
ager@chromium.orgbeb25712010-11-29 08:02:25 +000010004THREADED_TEST(ObjectGetConstructorName) {
10005 v8::HandleScope scope;
10006 LocalContext context;
10007 v8_compile("function Parent() {};"
10008 "function Child() {};"
10009 "Child.prototype = new Parent();"
10010 "var outer = { inner: function() { } };"
10011 "var p = new Parent();"
10012 "var c = new Child();"
10013 "var x = new outer.inner();")->Run();
10014
10015 Local<v8::Value> p = context->Global()->Get(v8_str("p"));
10016 CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
10017 v8_str("Parent")));
10018
10019 Local<v8::Value> c = context->Global()->Get(v8_str("c"));
10020 CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
10021 v8_str("Child")));
10022
10023 Local<v8::Value> x = context->Global()->Get(v8_str("x"));
10024 CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
10025 v8_str("outer.inner")));
10026}
10027
10028
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010029bool ApiTestFuzzer::fuzzing_ = false;
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010030i::Semaphore* ApiTestFuzzer::all_tests_done_=
10031 i::OS::CreateSemaphore(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010032int ApiTestFuzzer::active_tests_;
10033int ApiTestFuzzer::tests_being_run_;
10034int ApiTestFuzzer::current_;
10035
10036
10037// We are in a callback and want to switch to another thread (if we
10038// are currently running the thread fuzzing test).
10039void ApiTestFuzzer::Fuzz() {
10040 if (!fuzzing_) return;
10041 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
10042 test->ContextSwitch();
10043}
10044
10045
10046// Let the next thread go. Since it is also waiting on the V8 lock it may
10047// not start immediately.
10048bool ApiTestFuzzer::NextThread() {
10049 int test_position = GetNextTestNumber();
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010050 const char* test_name = RegisterThreadedTest::nth(current_)->name();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010051 if (test_position == current_) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010052 if (kLogThreading)
10053 printf("Stay with %s\n", test_name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010054 return false;
10055 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010056 if (kLogThreading) {
10057 printf("Switch from %s to %s\n",
10058 test_name,
10059 RegisterThreadedTest::nth(test_position)->name());
10060 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010061 current_ = test_position;
10062 RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
10063 return true;
10064}
10065
10066
10067void ApiTestFuzzer::Run() {
10068 // When it is our turn...
10069 gate_->Wait();
10070 {
10071 // ... get the V8 lock and start running the test.
10072 v8::Locker locker;
10073 CallTest();
10074 }
10075 // This test finished.
10076 active_ = false;
10077 active_tests_--;
10078 // If it was the last then signal that fact.
10079 if (active_tests_ == 0) {
10080 all_tests_done_->Signal();
10081 } else {
10082 // Otherwise select a new test and start that.
10083 NextThread();
10084 }
10085}
10086
10087
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010088static unsigned linear_congruential_generator;
10089
10090
10091void ApiTestFuzzer::Setup(PartOfTest part) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000010092 linear_congruential_generator = i::FLAG_testing_prng_seed;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010093 fuzzing_ = true;
lrn@chromium.org1c092762011-05-09 09:42:16 +000010094 int count = RegisterThreadedTest::count();
10095 int start = count * part / (LAST_PART + 1);
10096 int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
10097 active_tests_ = tests_being_run_ = end - start + 1;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010098 for (int i = 0; i < tests_being_run_; i++) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010099 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010100 }
10101 for (int i = 0; i < active_tests_; i++) {
10102 RegisterThreadedTest::nth(i)->fuzzer_->Start();
10103 }
10104}
10105
10106
10107static void CallTestNumber(int test_number) {
10108 (RegisterThreadedTest::nth(test_number)->callback())();
10109}
10110
10111
10112void ApiTestFuzzer::RunAllTests() {
10113 // Set off the first test.
10114 current_ = -1;
10115 NextThread();
10116 // Wait till they are all done.
10117 all_tests_done_->Wait();
10118}
10119
10120
10121int ApiTestFuzzer::GetNextTestNumber() {
10122 int next_test;
10123 do {
10124 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
10125 linear_congruential_generator *= 1664525u;
10126 linear_congruential_generator += 1013904223u;
10127 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
10128 return next_test;
10129}
10130
10131
10132void ApiTestFuzzer::ContextSwitch() {
10133 // If the new thread is the same as the current thread there is nothing to do.
10134 if (NextThread()) {
10135 // Now it can start.
10136 v8::Unlocker unlocker;
10137 // Wait till someone starts us again.
10138 gate_->Wait();
10139 // And we're off.
10140 }
10141}
10142
10143
10144void ApiTestFuzzer::TearDown() {
10145 fuzzing_ = false;
ager@chromium.org41826e72009-03-30 13:30:57 +000010146 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
10147 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
10148 if (fuzzer != NULL) fuzzer->Join();
10149 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010150}
10151
10152
10153// Lets not be needlessly self-referential.
10154TEST(Threading) {
10155 ApiTestFuzzer::Setup(ApiTestFuzzer::FIRST_PART);
10156 ApiTestFuzzer::RunAllTests();
10157 ApiTestFuzzer::TearDown();
10158}
10159
10160TEST(Threading2) {
10161 ApiTestFuzzer::Setup(ApiTestFuzzer::SECOND_PART);
10162 ApiTestFuzzer::RunAllTests();
10163 ApiTestFuzzer::TearDown();
10164}
10165
lrn@chromium.org1c092762011-05-09 09:42:16 +000010166TEST(Threading3) {
10167 ApiTestFuzzer::Setup(ApiTestFuzzer::THIRD_PART);
10168 ApiTestFuzzer::RunAllTests();
10169 ApiTestFuzzer::TearDown();
10170}
10171
10172TEST(Threading4) {
10173 ApiTestFuzzer::Setup(ApiTestFuzzer::FOURTH_PART);
10174 ApiTestFuzzer::RunAllTests();
10175 ApiTestFuzzer::TearDown();
10176}
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010177
10178void ApiTestFuzzer::CallTest() {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010179 if (kLogThreading)
10180 printf("Start test %d\n", test_number_);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010181 CallTestNumber(test_number_);
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010182 if (kLogThreading)
10183 printf("End test %d\n", test_number_);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010184}
10185
10186
10187static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010188 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010189 ApiTestFuzzer::Fuzz();
10190 v8::Unlocker unlocker;
10191 const char* code = "throw 7;";
10192 {
10193 v8::Locker nested_locker;
10194 v8::HandleScope scope;
10195 v8::Handle<Value> exception;
10196 { v8::TryCatch try_catch;
10197 v8::Handle<Value> value = CompileRun(code);
10198 CHECK(value.IsEmpty());
10199 CHECK(try_catch.HasCaught());
10200 // Make sure to wrap the exception in a new handle because
10201 // the handle returned from the TryCatch is destroyed
10202 // when the TryCatch is destroyed.
10203 exception = Local<Value>::New(try_catch.Exception());
10204 }
10205 return v8::ThrowException(exception);
10206 }
10207}
10208
10209
10210static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010211 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010212 ApiTestFuzzer::Fuzz();
10213 v8::Unlocker unlocker;
10214 const char* code = "throw 7;";
10215 {
10216 v8::Locker nested_locker;
10217 v8::HandleScope scope;
10218 v8::Handle<Value> value = CompileRun(code);
10219 CHECK(value.IsEmpty());
10220 return v8_str("foo");
10221 }
10222}
10223
10224
10225// These are locking tests that don't need to be run again
10226// as part of the locking aggregation tests.
10227TEST(NestedLockers) {
10228 v8::Locker locker;
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010229 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010230 v8::HandleScope scope;
10231 LocalContext env;
10232 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
10233 Local<Function> fun = fun_templ->GetFunction();
10234 env->Global()->Set(v8_str("throw_in_js"), fun);
10235 Local<Script> script = v8_compile("(function () {"
10236 " try {"
10237 " throw_in_js();"
10238 " return 42;"
10239 " } catch (e) {"
10240 " return e * 13;"
10241 " }"
10242 "})();");
10243 CHECK_EQ(91, script->Run()->Int32Value());
10244}
10245
10246
10247// These are locking tests that don't need to be run again
10248// as part of the locking aggregation tests.
10249TEST(NestedLockersNoTryCatch) {
10250 v8::Locker locker;
10251 v8::HandleScope scope;
10252 LocalContext env;
10253 Local<v8::FunctionTemplate> fun_templ =
10254 v8::FunctionTemplate::New(ThrowInJSNoCatch);
10255 Local<Function> fun = fun_templ->GetFunction();
10256 env->Global()->Set(v8_str("throw_in_js"), fun);
10257 Local<Script> script = v8_compile("(function () {"
10258 " try {"
10259 " throw_in_js();"
10260 " return 42;"
10261 " } catch (e) {"
10262 " return e * 13;"
10263 " }"
10264 "})();");
10265 CHECK_EQ(91, script->Run()->Int32Value());
10266}
10267
10268
10269THREADED_TEST(RecursiveLocking) {
10270 v8::Locker locker;
10271 {
10272 v8::Locker locker2;
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010273 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010274 }
10275}
10276
10277
10278static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
10279 ApiTestFuzzer::Fuzz();
10280 v8::Unlocker unlocker;
10281 return v8::Undefined();
10282}
10283
10284
10285THREADED_TEST(LockUnlockLock) {
10286 {
10287 v8::Locker locker;
10288 v8::HandleScope scope;
10289 LocalContext env;
10290 Local<v8::FunctionTemplate> fun_templ =
10291 v8::FunctionTemplate::New(UnlockForAMoment);
10292 Local<Function> fun = fun_templ->GetFunction();
10293 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
10294 Local<Script> script = v8_compile("(function () {"
10295 " unlock_for_a_moment();"
10296 " return 42;"
10297 "})();");
10298 CHECK_EQ(42, script->Run()->Int32Value());
10299 }
10300 {
10301 v8::Locker locker;
10302 v8::HandleScope scope;
10303 LocalContext env;
10304 Local<v8::FunctionTemplate> fun_templ =
10305 v8::FunctionTemplate::New(UnlockForAMoment);
10306 Local<Function> fun = fun_templ->GetFunction();
10307 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
10308 Local<Script> script = v8_compile("(function () {"
10309 " unlock_for_a_moment();"
10310 " return 42;"
10311 "})();");
10312 CHECK_EQ(42, script->Run()->Int32Value());
10313 }
10314}
10315
10316
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010317static int GetGlobalObjectsCount() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010318 i::Isolate::Current()->heap()->EnsureHeapIsIterable();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010319 int count = 0;
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010320 i::HeapIterator it;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010321 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
10322 if (object->IsJSGlobalObject()) count++;
10323 return count;
10324}
10325
10326
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000010327static void CheckSurvivingGlobalObjectsCount(int expected) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000010328 // We need to collect all garbage twice to be sure that everything
10329 // has been collected. This is because inline caches are cleared in
10330 // the first garbage collection but some of the maps have already
10331 // been marked at that point. Therefore some of the maps are not
10332 // collected until the second garbage collection.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010333 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
10334 HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010335 int count = GetGlobalObjectsCount();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010336#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010337 if (count != expected) HEAP->TracePathToGlobal();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010338#endif
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000010339 CHECK_EQ(expected, count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010340}
10341
10342
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010343TEST(DontLeakGlobalObjects) {
10344 // Regression test for issues 1139850 and 1174891.
10345
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000010346 v8::V8::Initialize();
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010347
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010348 for (int i = 0; i < 5; i++) {
10349 { v8::HandleScope scope;
10350 LocalContext context;
10351 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000010352 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010353
10354 { v8::HandleScope scope;
10355 LocalContext context;
10356 v8_compile("Date")->Run();
10357 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000010358 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010359
10360 { v8::HandleScope scope;
10361 LocalContext context;
10362 v8_compile("/aaa/")->Run();
10363 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000010364 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010365
10366 { v8::HandleScope scope;
10367 const char* extension_list[] = { "v8/gc" };
10368 v8::ExtensionConfiguration extensions(1, extension_list);
10369 LocalContext context(&extensions);
10370 v8_compile("gc();")->Run();
10371 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000010372 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010373 }
10374}
10375
10376
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000010377v8::Persistent<v8::Object> some_object;
10378v8::Persistent<v8::Object> bad_handle;
10379
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +000010380void NewPersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) {
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000010381 v8::HandleScope scope;
10382 bad_handle = v8::Persistent<v8::Object>::New(some_object);
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +000010383 handle.Dispose();
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000010384}
10385
10386
10387THREADED_TEST(NewPersistentHandleFromWeakCallback) {
10388 LocalContext context;
10389
10390 v8::Persistent<v8::Object> handle1, handle2;
10391 {
10392 v8::HandleScope scope;
10393 some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
10394 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
10395 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
10396 }
10397 // Note: order is implementation dependent alas: currently
10398 // global handle nodes are processed by PostGarbageCollectionProcessing
10399 // in reverse allocation order, so if second allocated handle is deleted,
10400 // weak callback of the first handle would be able to 'reallocate' it.
10401 handle1.MakeWeak(NULL, NewPersistentHandleCallback);
10402 handle2.Dispose();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010403 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000010404}
10405
10406
10407v8::Persistent<v8::Object> to_be_disposed;
10408
10409void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
10410 to_be_disposed.Dispose();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010411 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +000010412 handle.Dispose();
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000010413}
10414
10415
10416THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
10417 LocalContext context;
10418
10419 v8::Persistent<v8::Object> handle1, handle2;
10420 {
10421 v8::HandleScope scope;
10422 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
10423 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
10424 }
10425 handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
10426 to_be_disposed = handle2;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010427 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000010428}
10429
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010430void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
10431 handle.Dispose();
10432}
10433
10434void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
10435 v8::HandleScope scope;
10436 v8::Persistent<v8::Object>::New(v8::Object::New());
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +000010437 handle.Dispose();
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010438}
10439
10440
10441THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
10442 LocalContext context;
10443
10444 v8::Persistent<v8::Object> handle1, handle2, handle3;
10445 {
10446 v8::HandleScope scope;
10447 handle3 = v8::Persistent<v8::Object>::New(v8::Object::New());
10448 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
10449 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
10450 }
10451 handle2.MakeWeak(NULL, DisposingCallback);
10452 handle3.MakeWeak(NULL, HandleCreatingCallback);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010453 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010454}
10455
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000010456
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010457THREADED_TEST(CheckForCrossContextObjectLiterals) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000010458 v8::V8::Initialize();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010459
10460 const int nof = 2;
10461 const char* sources[nof] = {
10462 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
10463 "Object()"
10464 };
10465
10466 for (int i = 0; i < nof; i++) {
10467 const char* source = sources[i];
10468 { v8::HandleScope scope;
10469 LocalContext context;
10470 CompileRun(source);
10471 }
10472 { v8::HandleScope scope;
10473 LocalContext context;
10474 CompileRun(source);
10475 }
10476 }
10477}
10478
10479
10480static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
10481 v8::HandleScope inner;
10482 env->Enter();
10483 v8::Handle<Value> three = v8_num(3);
10484 v8::Handle<Value> value = inner.Close(three);
10485 env->Exit();
10486 return value;
10487}
10488
10489
10490THREADED_TEST(NestedHandleScopeAndContexts) {
10491 v8::HandleScope outer;
10492 v8::Persistent<Context> env = Context::New();
10493 env->Enter();
10494 v8::Handle<Value> value = NestedScope(env);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010495 v8::Handle<String> str(value->ToString());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010496 env->Exit();
10497 env.Dispose();
10498}
10499
10500
10501THREADED_TEST(ExternalAllocatedMemory) {
10502 v8::HandleScope outer;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010503 v8::Persistent<Context> env(Context::New());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010504 const int kSize = 1024*1024;
10505 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
10506 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
10507}
10508
10509
10510THREADED_TEST(DisposeEnteredContext) {
10511 v8::HandleScope scope;
10512 LocalContext outer;
10513 { v8::Persistent<v8::Context> inner = v8::Context::New();
10514 inner->Enter();
10515 inner.Dispose();
10516 inner.Clear();
10517 inner->Exit();
10518 }
10519}
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010520
10521
10522// Regression test for issue 54, object templates with internal fields
10523// but no accessors or interceptors did not get their internal field
10524// count set on instances.
10525THREADED_TEST(Regress54) {
10526 v8::HandleScope outer;
10527 LocalContext context;
10528 static v8::Persistent<v8::ObjectTemplate> templ;
10529 if (templ.IsEmpty()) {
10530 v8::HandleScope inner;
10531 v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
10532 local->SetInternalFieldCount(1);
10533 templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
10534 }
10535 v8::Handle<v8::Object> result = templ->NewInstance();
10536 CHECK_EQ(1, result->InternalFieldCount());
10537}
10538
10539
10540// If part of the threaded tests, this test makes ThreadingTest fail
10541// on mac.
10542TEST(CatchStackOverflow) {
10543 v8::HandleScope scope;
10544 LocalContext context;
10545 v8::TryCatch try_catch;
10546 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
10547 "function f() {"
10548 " return f();"
10549 "}"
10550 ""
10551 "f();"));
10552 v8::Handle<v8::Value> result = script->Run();
10553 CHECK(result.IsEmpty());
10554}
10555
10556
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000010557static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
10558 const char* resource_name,
10559 int line_offset) {
10560 v8::HandleScope scope;
10561 v8::TryCatch try_catch;
10562 v8::Handle<v8::Value> result = script->Run();
10563 CHECK(result.IsEmpty());
10564 CHECK(try_catch.HasCaught());
10565 v8::Handle<v8::Message> message = try_catch.Message();
10566 CHECK(!message.IsEmpty());
10567 CHECK_EQ(10 + line_offset, message->GetLineNumber());
10568 CHECK_EQ(91, message->GetStartPosition());
10569 CHECK_EQ(92, message->GetEndPosition());
10570 CHECK_EQ(2, message->GetStartColumn());
10571 CHECK_EQ(3, message->GetEndColumn());
10572 v8::String::AsciiValue line(message->GetSourceLine());
10573 CHECK_EQ(" throw 'nirk';", *line);
10574 v8::String::AsciiValue name(message->GetScriptResourceName());
10575 CHECK_EQ(resource_name, *name);
10576}
10577
10578
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010579THREADED_TEST(TryCatchSourceInfo) {
10580 v8::HandleScope scope;
10581 LocalContext context;
10582 v8::Handle<v8::String> source = v8::String::New(
10583 "function Foo() {\n"
10584 " return Bar();\n"
10585 "}\n"
10586 "\n"
10587 "function Bar() {\n"
10588 " return Baz();\n"
10589 "}\n"
10590 "\n"
10591 "function Baz() {\n"
10592 " throw 'nirk';\n"
10593 "}\n"
10594 "\n"
10595 "Foo();\n");
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000010596
10597 const char* resource_name;
10598 v8::Handle<v8::Script> script;
10599 resource_name = "test.js";
10600 script = v8::Script::Compile(source, v8::String::New(resource_name));
10601 CheckTryCatchSourceInfo(script, resource_name, 0);
10602
10603 resource_name = "test1.js";
10604 v8::ScriptOrigin origin1(v8::String::New(resource_name));
10605 script = v8::Script::Compile(source, &origin1);
10606 CheckTryCatchSourceInfo(script, resource_name, 0);
10607
10608 resource_name = "test2.js";
10609 v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
10610 script = v8::Script::Compile(source, &origin2);
10611 CheckTryCatchSourceInfo(script, resource_name, 7);
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010612}
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000010613
10614
10615THREADED_TEST(CompilationCache) {
10616 v8::HandleScope scope;
10617 LocalContext context;
10618 v8::Handle<v8::String> source0 = v8::String::New("1234");
10619 v8::Handle<v8::String> source1 = v8::String::New("1234");
10620 v8::Handle<v8::Script> script0 =
10621 v8::Script::Compile(source0, v8::String::New("test.js"));
10622 v8::Handle<v8::Script> script1 =
10623 v8::Script::Compile(source1, v8::String::New("test.js"));
10624 v8::Handle<v8::Script> script2 =
10625 v8::Script::Compile(source0); // different origin
10626 CHECK_EQ(1234, script0->Run()->Int32Value());
10627 CHECK_EQ(1234, script1->Run()->Int32Value());
10628 CHECK_EQ(1234, script2->Run()->Int32Value());
10629}
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000010630
10631
10632static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
10633 ApiTestFuzzer::Fuzz();
10634 return v8_num(42);
10635}
10636
10637
10638THREADED_TEST(CallbackFunctionName) {
10639 v8::HandleScope scope;
10640 LocalContext context;
10641 Local<ObjectTemplate> t = ObjectTemplate::New();
10642 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
10643 context->Global()->Set(v8_str("obj"), t->NewInstance());
10644 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
10645 CHECK(value->IsString());
10646 v8::String::AsciiValue name(value);
10647 CHECK_EQ("asdf", *name);
10648}
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010649
10650
10651THREADED_TEST(DateAccess) {
10652 v8::HandleScope scope;
10653 LocalContext context;
10654 v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
10655 CHECK(date->IsDate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010656 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010657}
10658
10659
10660void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010661 v8::Handle<v8::Object> obj = val.As<v8::Object>();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010662 v8::Handle<v8::Array> props = obj->GetPropertyNames();
10663 CHECK_EQ(elmc, props->Length());
10664 for (int i = 0; i < elmc; i++) {
10665 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
10666 CHECK_EQ(elmv[i], *elm);
10667 }
10668}
10669
10670
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010671void CheckOwnProperties(v8::Handle<v8::Value> val,
10672 int elmc,
10673 const char* elmv[]) {
10674 v8::Handle<v8::Object> obj = val.As<v8::Object>();
10675 v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
10676 CHECK_EQ(elmc, props->Length());
10677 for (int i = 0; i < elmc; i++) {
10678 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
10679 CHECK_EQ(elmv[i], *elm);
10680 }
10681}
10682
10683
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010684THREADED_TEST(PropertyEnumeration) {
10685 v8::HandleScope scope;
10686 LocalContext context;
10687 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
10688 "var result = [];"
10689 "result[0] = {};"
10690 "result[1] = {a: 1, b: 2};"
10691 "result[2] = [1, 2, 3];"
10692 "var proto = {x: 1, y: 2, z: 3};"
10693 "var x = { __proto__: proto, w: 0, z: 1 };"
10694 "result[3] = x;"
10695 "result;"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010696 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010697 CHECK_EQ(4, elms->Length());
10698 int elmc0 = 0;
10699 const char** elmv0 = NULL;
10700 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010701 CheckOwnProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010702 int elmc1 = 2;
10703 const char* elmv1[] = {"a", "b"};
10704 CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010705 CheckOwnProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010706 int elmc2 = 3;
10707 const char* elmv2[] = {"0", "1", "2"};
10708 CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010709 CheckOwnProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010710 int elmc3 = 4;
10711 const char* elmv3[] = {"w", "z", "x", "y"};
10712 CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010713 int elmc4 = 2;
10714 const char* elmv4[] = {"w", "z"};
10715 CheckOwnProperties(elms->Get(v8::Integer::New(3)), elmc4, elmv4);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010716}
ager@chromium.org870a0b62008-11-04 11:43:05 +000010717
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010718THREADED_TEST(PropertyEnumeration2) {
10719 v8::HandleScope scope;
10720 LocalContext context;
10721 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
10722 "var result = [];"
10723 "result[0] = {};"
10724 "result[1] = {a: 1, b: 2};"
10725 "result[2] = [1, 2, 3];"
10726 "var proto = {x: 1, y: 2, z: 3};"
10727 "var x = { __proto__: proto, w: 0, z: 1 };"
10728 "result[3] = x;"
10729 "result;"))->Run();
10730 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
10731 CHECK_EQ(4, elms->Length());
10732 int elmc0 = 0;
10733 const char** elmv0 = NULL;
10734 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
10735
10736 v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(0));
10737 v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
10738 CHECK_EQ(0, props->Length());
10739 for (uint32_t i = 0; i < props->Length(); i++) {
10740 printf("p[%d]\n", i);
10741 }
10742}
ager@chromium.org870a0b62008-11-04 11:43:05 +000010743
ager@chromium.org870a0b62008-11-04 11:43:05 +000010744static bool NamedSetAccessBlocker(Local<v8::Object> obj,
10745 Local<Value> name,
10746 v8::AccessType type,
10747 Local<Value> data) {
10748 return type != v8::ACCESS_SET;
10749}
10750
10751
10752static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
10753 uint32_t key,
10754 v8::AccessType type,
10755 Local<Value> data) {
10756 return type != v8::ACCESS_SET;
10757}
10758
10759
10760THREADED_TEST(DisableAccessChecksWhileConfiguring) {
10761 v8::HandleScope scope;
10762 LocalContext context;
10763 Local<ObjectTemplate> templ = ObjectTemplate::New();
10764 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
10765 IndexedSetAccessBlocker);
10766 templ->Set(v8_str("x"), v8::True());
10767 Local<v8::Object> instance = templ->NewInstance();
10768 context->Global()->Set(v8_str("obj"), instance);
10769 Local<Value> value = CompileRun("obj.x");
10770 CHECK(value->BooleanValue());
10771}
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010772
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010773
ager@chromium.org32912102009-01-16 10:38:43 +000010774static bool NamedGetAccessBlocker(Local<v8::Object> obj,
10775 Local<Value> name,
10776 v8::AccessType type,
10777 Local<Value> data) {
10778 return false;
10779}
10780
10781
10782static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
10783 uint32_t key,
10784 v8::AccessType type,
10785 Local<Value> data) {
10786 return false;
10787}
10788
10789
10790
10791THREADED_TEST(AccessChecksReenabledCorrectly) {
10792 v8::HandleScope scope;
10793 LocalContext context;
10794 Local<ObjectTemplate> templ = ObjectTemplate::New();
10795 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
10796 IndexedGetAccessBlocker);
10797 templ->Set(v8_str("a"), v8_str("a"));
10798 // Add more than 8 (see kMaxFastProperties) properties
10799 // so that the constructor will force copying map.
10800 // Cannot sprintf, gcc complains unsafety.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010801 char buf[4];
ager@chromium.org32912102009-01-16 10:38:43 +000010802 for (char i = '0'; i <= '9' ; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010803 buf[0] = i;
ager@chromium.org32912102009-01-16 10:38:43 +000010804 for (char j = '0'; j <= '9'; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010805 buf[1] = j;
ager@chromium.org32912102009-01-16 10:38:43 +000010806 for (char k = '0'; k <= '9'; k++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010807 buf[2] = k;
10808 buf[3] = 0;
ager@chromium.org32912102009-01-16 10:38:43 +000010809 templ->Set(v8_str(buf), v8::Number::New(k));
10810 }
10811 }
10812 }
10813
10814 Local<v8::Object> instance_1 = templ->NewInstance();
10815 context->Global()->Set(v8_str("obj_1"), instance_1);
10816
10817 Local<Value> value_1 = CompileRun("obj_1.a");
10818 CHECK(value_1->IsUndefined());
10819
10820 Local<v8::Object> instance_2 = templ->NewInstance();
10821 context->Global()->Set(v8_str("obj_2"), instance_2);
10822
10823 Local<Value> value_2 = CompileRun("obj_2.a");
10824 CHECK(value_2->IsUndefined());
10825}
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010826
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010827
ager@chromium.org8bb60582008-12-11 12:02:20 +000010828// This tests that access check information remains on the global
10829// object template when creating contexts.
10830THREADED_TEST(AccessControlRepeatedContextCreation) {
10831 v8::HandleScope handle_scope;
10832 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
10833 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
10834 IndexedSetAccessBlocker);
10835 i::Handle<i::ObjectTemplateInfo> internal_template =
10836 v8::Utils::OpenHandle(*global_template);
10837 CHECK(!internal_template->constructor()->IsUndefined());
10838 i::Handle<i::FunctionTemplateInfo> constructor(
10839 i::FunctionTemplateInfo::cast(internal_template->constructor()));
10840 CHECK(!constructor->access_check_info()->IsUndefined());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010841 v8::Persistent<Context> context0(Context::New(NULL, global_template));
ager@chromium.org8bb60582008-12-11 12:02:20 +000010842 CHECK(!constructor->access_check_info()->IsUndefined());
10843}
10844
10845
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010846THREADED_TEST(TurnOnAccessCheck) {
10847 v8::HandleScope handle_scope;
10848
10849 // Create an environment with access check to the global object disabled by
10850 // default.
10851 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
10852 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
10853 IndexedGetAccessBlocker,
10854 v8::Handle<v8::Value>(),
10855 false);
10856 v8::Persistent<Context> context = Context::New(NULL, global_template);
10857 Context::Scope context_scope(context);
10858
10859 // Set up a property and a number of functions.
10860 context->Global()->Set(v8_str("a"), v8_num(1));
10861 CompileRun("function f1() {return a;}"
10862 "function f2() {return a;}"
10863 "function g1() {return h();}"
10864 "function g2() {return h();}"
10865 "function h() {return 1;}");
10866 Local<Function> f1 =
10867 Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
10868 Local<Function> f2 =
10869 Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
10870 Local<Function> g1 =
10871 Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
10872 Local<Function> g2 =
10873 Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
10874 Local<Function> h =
10875 Local<Function>::Cast(context->Global()->Get(v8_str("h")));
10876
10877 // Get the global object.
10878 v8::Handle<v8::Object> global = context->Global();
10879
10880 // Call f1 one time and f2 a number of times. This will ensure that f1 still
10881 // uses the runtime system to retreive property a whereas f2 uses global load
10882 // inline cache.
10883 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
10884 for (int i = 0; i < 4; i++) {
10885 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
10886 }
10887
10888 // Same for g1 and g2.
10889 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
10890 for (int i = 0; i < 4; i++) {
10891 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
10892 }
10893
10894 // Detach the global and turn on access check.
10895 context->DetachGlobal();
10896 context->Global()->TurnOnAccessCheck();
10897
10898 // Failing access check to property get results in undefined.
10899 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
10900 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
10901
10902 // Failing access check to function call results in exception.
10903 CHECK(g1->Call(global, 0, NULL).IsEmpty());
10904 CHECK(g2->Call(global, 0, NULL).IsEmpty());
10905
10906 // No failing access check when just returning a constant.
10907 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
10908}
10909
10910
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010911v8::Handle<v8::String> a;
10912v8::Handle<v8::String> h;
10913
10914static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
10915 Local<Value> name,
10916 v8::AccessType type,
10917 Local<Value> data) {
10918 return !(name->Equals(a) || name->Equals(h));
10919}
10920
10921
10922THREADED_TEST(TurnOnAccessCheckAndRecompile) {
10923 v8::HandleScope handle_scope;
10924
10925 // Create an environment with access check to the global object disabled by
10926 // default. When the registered access checker will block access to properties
10927 // a and h
10928 a = v8_str("a");
10929 h = v8_str("h");
10930 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
10931 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
10932 IndexedGetAccessBlocker,
10933 v8::Handle<v8::Value>(),
10934 false);
10935 v8::Persistent<Context> context = Context::New(NULL, global_template);
10936 Context::Scope context_scope(context);
10937
10938 // Set up a property and a number of functions.
10939 context->Global()->Set(v8_str("a"), v8_num(1));
10940 static const char* source = "function f1() {return a;}"
10941 "function f2() {return a;}"
10942 "function g1() {return h();}"
10943 "function g2() {return h();}"
10944 "function h() {return 1;}";
10945
10946 CompileRun(source);
10947 Local<Function> f1;
10948 Local<Function> f2;
10949 Local<Function> g1;
10950 Local<Function> g2;
10951 Local<Function> h;
10952 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
10953 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
10954 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
10955 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
10956 h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
10957
10958 // Get the global object.
10959 v8::Handle<v8::Object> global = context->Global();
10960
10961 // Call f1 one time and f2 a number of times. This will ensure that f1 still
10962 // uses the runtime system to retreive property a whereas f2 uses global load
10963 // inline cache.
10964 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
10965 for (int i = 0; i < 4; i++) {
10966 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
10967 }
10968
10969 // Same for g1 and g2.
10970 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
10971 for (int i = 0; i < 4; i++) {
10972 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
10973 }
10974
10975 // Detach the global and turn on access check now blocking access to property
10976 // a and function h.
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 // Now compile the source again. And get the newly compiled functions, except
10992 // for h for which access is blocked.
10993 CompileRun(source);
10994 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
10995 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
10996 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
10997 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
10998 CHECK(context->Global()->Get(v8_str("h"))->IsUndefined());
10999
11000 // Failing access check to property get results in undefined.
11001 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
11002 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
11003
11004 // Failing access check to function call results in exception.
11005 CHECK(g1->Call(global, 0, NULL).IsEmpty());
11006 CHECK(g2->Call(global, 0, NULL).IsEmpty());
11007}
11008
11009
ager@chromium.orga74f0da2008-12-03 16:05:52 +000011010// This test verifies that pre-compilation (aka preparsing) can be called
11011// without initializing the whole VM. Thus we cannot run this test in a
11012// multi-threaded setup.
11013TEST(PreCompile) {
11014 // TODO(155): This test would break without the initialization of V8. This is
11015 // a workaround for now to make this test not fail.
11016 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011017 const char* script = "function foo(a) { return a+1; }";
11018 v8::ScriptData* sd =
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011019 v8::ScriptData::PreCompile(script, i::StrLength(script));
ager@chromium.orga74f0da2008-12-03 16:05:52 +000011020 CHECK_NE(sd->Length(), 0);
11021 CHECK_NE(sd->Data(), NULL);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000011022 CHECK(!sd->HasError());
11023 delete sd;
11024}
11025
11026
11027TEST(PreCompileWithError) {
11028 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011029 const char* script = "function foo(a) { return 1 * * 2; }";
11030 v8::ScriptData* sd =
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000011031 v8::ScriptData::PreCompile(script, i::StrLength(script));
11032 CHECK(sd->HasError());
11033 delete sd;
11034}
11035
11036
11037TEST(Regress31661) {
11038 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011039 const char* script = " The Definintive Guide";
11040 v8::ScriptData* sd =
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000011041 v8::ScriptData::PreCompile(script, i::StrLength(script));
11042 CHECK(sd->HasError());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011043 delete sd;
ager@chromium.orga74f0da2008-12-03 16:05:52 +000011044}
11045
11046
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011047// Tests that ScriptData can be serialized and deserialized.
11048TEST(PreCompileSerialization) {
11049 v8::V8::Initialize();
11050 const char* script = "function foo(a) { return a+1; }";
11051 v8::ScriptData* sd =
11052 v8::ScriptData::PreCompile(script, i::StrLength(script));
11053
11054 // Serialize.
11055 int serialized_data_length = sd->Length();
11056 char* serialized_data = i::NewArray<char>(serialized_data_length);
11057 memcpy(serialized_data, sd->Data(), serialized_data_length);
11058
11059 // Deserialize.
11060 v8::ScriptData* deserialized_sd =
11061 v8::ScriptData::New(serialized_data, serialized_data_length);
11062
11063 // Verify that the original is the same as the deserialized.
11064 CHECK_EQ(sd->Length(), deserialized_sd->Length());
11065 CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
11066 CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
11067
11068 delete sd;
11069 delete deserialized_sd;
11070}
11071
11072
11073// Attempts to deserialize bad data.
11074TEST(PreCompileDeserializationError) {
11075 v8::V8::Initialize();
11076 const char* data = "DONT CARE";
11077 int invalid_size = 3;
11078 v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
11079
11080 CHECK_EQ(0, sd->Length());
11081
11082 delete sd;
11083}
11084
11085
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000011086// Attempts to deserialize bad data.
11087TEST(PreCompileInvalidPreparseDataError) {
11088 v8::V8::Initialize();
11089 v8::HandleScope scope;
11090 LocalContext context;
11091
11092 const char* script = "function foo(){ return 5;}\n"
11093 "function bar(){ return 6 + 7;} foo();";
11094 v8::ScriptData* sd =
11095 v8::ScriptData::PreCompile(script, i::StrLength(script));
11096 CHECK(!sd->HasError());
11097 // ScriptDataImpl private implementation details
ager@chromium.orgbeb25712010-11-29 08:02:25 +000011098 const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
ager@chromium.org5b2fbee2010-09-08 06:38:15 +000011099 const int kFunctionEntrySize = i::FunctionEntry::kSize;
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000011100 const int kFunctionEntryStartOffset = 0;
11101 const int kFunctionEntryEndOffset = 1;
11102 unsigned* sd_data =
11103 reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000011104
11105 // Overwrite function bar's end position with 0.
11106 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
11107 v8::TryCatch try_catch;
11108
11109 Local<String> source = String::New(script);
11110 Local<Script> compiled_script = Script::New(source, NULL, sd);
11111 CHECK(try_catch.HasCaught());
11112 String::AsciiValue exception_value(try_catch.Message()->Get());
11113 CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
11114 *exception_value);
11115
11116 try_catch.Reset();
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000011117
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000011118 // Overwrite function bar's start position with 200. The function entry
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000011119 // will not be found when searching for it by position and we should fall
11120 // back on eager compilation.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +000011121 sd = v8::ScriptData::PreCompile(script, i::StrLength(script));
11122 sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000011123 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
11124 200;
11125 compiled_script = Script::New(source, NULL, sd);
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000011126 CHECK(!try_catch.HasCaught());
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000011127
11128 delete sd;
11129}
11130
11131
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000011132// Verifies that the Handle<String> and const char* versions of the API produce
11133// the same results (at least for one trivial case).
11134TEST(PreCompileAPIVariationsAreSame) {
11135 v8::V8::Initialize();
11136 v8::HandleScope scope;
11137
11138 const char* cstring = "function foo(a) { return a+1; }";
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011139
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000011140 v8::ScriptData* sd_from_cstring =
11141 v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
11142
11143 TestAsciiResource* resource = new TestAsciiResource(cstring);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011144 v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile(
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000011145 v8::String::NewExternal(resource));
11146
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011147 v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile(
11148 v8::String::New(cstring));
11149
11150 CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000011151 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011152 sd_from_external_string->Data(),
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000011153 sd_from_cstring->Length()));
11154
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011155 CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length());
11156 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
11157 sd_from_string->Data(),
11158 sd_from_cstring->Length()));
11159
11160
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000011161 delete sd_from_cstring;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011162 delete sd_from_external_string;
11163 delete sd_from_string;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000011164}
11165
11166
ager@chromium.orga74f0da2008-12-03 16:05:52 +000011167// This tests that we do not allow dictionary load/call inline caches
11168// to use functions that have not yet been compiled. The potential
11169// problem of loading a function that has not yet been compiled can
11170// arise because we share code between contexts via the compilation
11171// cache.
11172THREADED_TEST(DictionaryICLoadedFunction) {
11173 v8::HandleScope scope;
11174 // Test LoadIC.
11175 for (int i = 0; i < 2; i++) {
11176 LocalContext context;
11177 context->Global()->Set(v8_str("tmp"), v8::True());
11178 context->Global()->Delete(v8_str("tmp"));
11179 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
11180 }
11181 // Test CallIC.
11182 for (int i = 0; i < 2; i++) {
11183 LocalContext context;
11184 context->Global()->Set(v8_str("tmp"), v8::True());
11185 context->Global()->Delete(v8_str("tmp"));
11186 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
11187 }
11188}
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011189
11190
11191// Test that cross-context new calls use the context of the callee to
11192// create the new JavaScript object.
11193THREADED_TEST(CrossContextNew) {
11194 v8::HandleScope scope;
11195 v8::Persistent<Context> context0 = Context::New();
11196 v8::Persistent<Context> context1 = Context::New();
11197
11198 // Allow cross-domain access.
11199 Local<String> token = v8_str("<security token>");
11200 context0->SetSecurityToken(token);
11201 context1->SetSecurityToken(token);
11202
11203 // Set an 'x' property on the Object prototype and define a
11204 // constructor function in context0.
11205 context0->Enter();
11206 CompileRun("Object.prototype.x = 42; function C() {};");
11207 context0->Exit();
11208
11209 // Call the constructor function from context0 and check that the
11210 // result has the 'x' property.
11211 context1->Enter();
11212 context1->Global()->Set(v8_str("other"), context0->Global());
11213 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
11214 CHECK(value->IsInt32());
11215 CHECK_EQ(42, value->Int32Value());
11216 context1->Exit();
11217
11218 // Dispose the contexts to allow them to be garbage collected.
11219 context0.Dispose();
11220 context1.Dispose();
11221}
ager@chromium.org381abbb2009-02-25 13:23:22 +000011222
11223
11224class RegExpInterruptTest {
11225 public:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011226 RegExpInterruptTest() : block_(NULL) {}
11227 ~RegExpInterruptTest() { delete block_; }
ager@chromium.org381abbb2009-02-25 13:23:22 +000011228 void RunTest() {
11229 block_ = i::OS::CreateSemaphore(0);
11230 gc_count_ = 0;
11231 gc_during_regexp_ = 0;
11232 regexp_success_ = false;
11233 gc_success_ = false;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011234 GCThread gc_thread(this);
ager@chromium.org381abbb2009-02-25 13:23:22 +000011235 gc_thread.Start();
11236 v8::Locker::StartPreemption(1);
11237
11238 LongRunningRegExp();
11239 {
11240 v8::Unlocker unlock;
11241 gc_thread.Join();
11242 }
11243 v8::Locker::StopPreemption();
11244 CHECK(regexp_success_);
11245 CHECK(gc_success_);
11246 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000011247
ager@chromium.org381abbb2009-02-25 13:23:22 +000011248 private:
11249 // Number of garbage collections required.
11250 static const int kRequiredGCs = 5;
11251
11252 class GCThread : public i::Thread {
11253 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011254 explicit GCThread(RegExpInterruptTest* test)
11255 : Thread("GCThread"), test_(test) {}
ager@chromium.org381abbb2009-02-25 13:23:22 +000011256 virtual void Run() {
11257 test_->CollectGarbage();
11258 }
11259 private:
11260 RegExpInterruptTest* test_;
11261 };
11262
11263 void CollectGarbage() {
11264 block_->Wait();
11265 while (gc_during_regexp_ < kRequiredGCs) {
11266 {
11267 v8::Locker lock;
11268 // TODO(lrn): Perhaps create some garbage before collecting.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011269 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org381abbb2009-02-25 13:23:22 +000011270 gc_count_++;
11271 }
11272 i::OS::Sleep(1);
11273 }
11274 gc_success_ = true;
11275 }
11276
11277 void LongRunningRegExp() {
11278 block_->Signal(); // Enable garbage collection thread on next preemption.
11279 int rounds = 0;
11280 while (gc_during_regexp_ < kRequiredGCs) {
11281 int gc_before = gc_count_;
11282 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011283 // Match 15-30 "a"'s against 14 and a "b".
ager@chromium.org381abbb2009-02-25 13:23:22 +000011284 const char* c_source =
11285 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
11286 ".exec('aaaaaaaaaaaaaaab') === null";
11287 Local<String> source = String::New(c_source);
11288 Local<Script> script = Script::Compile(source);
11289 Local<Value> result = script->Run();
11290 if (!result->BooleanValue()) {
11291 gc_during_regexp_ = kRequiredGCs; // Allow gc thread to exit.
11292 return;
11293 }
11294 }
11295 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011296 // Match 15-30 "a"'s against 15 and a "b".
ager@chromium.org381abbb2009-02-25 13:23:22 +000011297 const char* c_source =
11298 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
11299 ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
11300 Local<String> source = String::New(c_source);
11301 Local<Script> script = Script::Compile(source);
11302 Local<Value> result = script->Run();
11303 if (!result->BooleanValue()) {
11304 gc_during_regexp_ = kRequiredGCs;
11305 return;
11306 }
11307 }
11308 int gc_after = gc_count_;
11309 gc_during_regexp_ += gc_after - gc_before;
11310 rounds++;
11311 i::OS::Sleep(1);
11312 }
11313 regexp_success_ = true;
11314 }
11315
11316 i::Semaphore* block_;
11317 int gc_count_;
11318 int gc_during_regexp_;
11319 bool regexp_success_;
11320 bool gc_success_;
11321};
11322
11323
11324// Test that a regular expression execution can be interrupted and
11325// survive a garbage collection.
11326TEST(RegExpInterruption) {
11327 v8::Locker lock;
11328 v8::V8::Initialize();
11329 v8::HandleScope scope;
11330 Local<Context> local_env;
11331 {
11332 LocalContext env;
11333 local_env = env.local();
11334 }
11335
11336 // Local context should still be live.
11337 CHECK(!local_env.IsEmpty());
11338 local_env->Enter();
11339
11340 // Should complete without problems.
11341 RegExpInterruptTest().RunTest();
11342
11343 local_env->Exit();
11344}
ager@chromium.org3b45ab52009-03-19 22:21:34 +000011345
11346
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011347class ApplyInterruptTest {
11348 public:
11349 ApplyInterruptTest() : block_(NULL) {}
11350 ~ApplyInterruptTest() { delete block_; }
11351 void RunTest() {
11352 block_ = i::OS::CreateSemaphore(0);
11353 gc_count_ = 0;
11354 gc_during_apply_ = 0;
11355 apply_success_ = false;
11356 gc_success_ = false;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011357 GCThread gc_thread(this);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011358 gc_thread.Start();
11359 v8::Locker::StartPreemption(1);
11360
11361 LongRunningApply();
11362 {
11363 v8::Unlocker unlock;
11364 gc_thread.Join();
11365 }
11366 v8::Locker::StopPreemption();
11367 CHECK(apply_success_);
11368 CHECK(gc_success_);
11369 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000011370
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011371 private:
11372 // Number of garbage collections required.
11373 static const int kRequiredGCs = 2;
11374
11375 class GCThread : public i::Thread {
11376 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011377 explicit GCThread(ApplyInterruptTest* test)
11378 : Thread("GCThread"), test_(test) {}
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011379 virtual void Run() {
11380 test_->CollectGarbage();
11381 }
11382 private:
11383 ApplyInterruptTest* test_;
11384 };
11385
11386 void CollectGarbage() {
11387 block_->Wait();
11388 while (gc_during_apply_ < kRequiredGCs) {
11389 {
11390 v8::Locker lock;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011391 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011392 gc_count_++;
11393 }
11394 i::OS::Sleep(1);
11395 }
11396 gc_success_ = true;
11397 }
11398
11399 void LongRunningApply() {
11400 block_->Signal();
11401 int rounds = 0;
11402 while (gc_during_apply_ < kRequiredGCs) {
11403 int gc_before = gc_count_;
11404 {
11405 const char* c_source =
11406 "function do_very_little(bar) {"
11407 " this.foo = bar;"
11408 "}"
11409 "for (var i = 0; i < 100000; i++) {"
11410 " do_very_little.apply(this, ['bar']);"
11411 "}";
11412 Local<String> source = String::New(c_source);
11413 Local<Script> script = Script::Compile(source);
11414 Local<Value> result = script->Run();
ager@chromium.org3a37e9b2009-04-27 09:26:21 +000011415 // Check that no exception was thrown.
11416 CHECK(!result.IsEmpty());
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011417 }
11418 int gc_after = gc_count_;
11419 gc_during_apply_ += gc_after - gc_before;
11420 rounds++;
11421 }
11422 apply_success_ = true;
11423 }
11424
11425 i::Semaphore* block_;
11426 int gc_count_;
11427 int gc_during_apply_;
11428 bool apply_success_;
11429 bool gc_success_;
11430};
11431
11432
11433// Test that nothing bad happens if we get a preemption just when we were
11434// about to do an apply().
11435TEST(ApplyInterruption) {
11436 v8::Locker lock;
11437 v8::V8::Initialize();
11438 v8::HandleScope scope;
11439 Local<Context> local_env;
11440 {
11441 LocalContext env;
11442 local_env = env.local();
11443 }
11444
11445 // Local context should still be live.
11446 CHECK(!local_env.IsEmpty());
11447 local_env->Enter();
11448
11449 // Should complete without problems.
11450 ApplyInterruptTest().RunTest();
11451
11452 local_env->Exit();
11453}
11454
11455
ager@chromium.org3b45ab52009-03-19 22:21:34 +000011456// Verify that we can clone an object
11457TEST(ObjectClone) {
11458 v8::HandleScope scope;
11459 LocalContext env;
11460
11461 const char* sample =
11462 "var rv = {};" \
11463 "rv.alpha = 'hello';" \
11464 "rv.beta = 123;" \
11465 "rv;";
11466
11467 // Create an object, verify basics.
11468 Local<Value> val = CompileRun(sample);
11469 CHECK(val->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011470 Local<v8::Object> obj = val.As<v8::Object>();
ager@chromium.org3b45ab52009-03-19 22:21:34 +000011471 obj->Set(v8_str("gamma"), v8_str("cloneme"));
11472
11473 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
11474 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
11475 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
11476
11477 // Clone it.
11478 Local<v8::Object> clone = obj->Clone();
11479 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
11480 CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
11481 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
11482
11483 // Set a property on the clone, verify each object.
11484 clone->Set(v8_str("beta"), v8::Integer::New(456));
11485 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
11486 CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
11487}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011488
11489
ager@chromium.org5ec48922009-05-05 07:25:34 +000011490class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
11491 public:
11492 explicit AsciiVectorResource(i::Vector<const char> vector)
11493 : data_(vector) {}
11494 virtual ~AsciiVectorResource() {}
11495 virtual size_t length() const { return data_.length(); }
11496 virtual const char* data() const { return data_.start(); }
11497 private:
11498 i::Vector<const char> data_;
11499};
11500
11501
11502class UC16VectorResource : public v8::String::ExternalStringResource {
11503 public:
11504 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
11505 : data_(vector) {}
11506 virtual ~UC16VectorResource() {}
11507 virtual size_t length() const { return data_.length(); }
11508 virtual const i::uc16* data() const { return data_.start(); }
11509 private:
11510 i::Vector<const i::uc16> data_;
11511};
11512
11513
11514static void MorphAString(i::String* string,
11515 AsciiVectorResource* ascii_resource,
11516 UC16VectorResource* uc16_resource) {
11517 CHECK(i::StringShape(string).IsExternal());
11518 if (string->IsAsciiRepresentation()) {
11519 // Check old map is not symbol or long.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011520 CHECK(string->map() == HEAP->external_ascii_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000011521 // Morph external string to be TwoByte string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011522 string->set_map(HEAP->external_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000011523 i::ExternalTwoByteString* morphed =
11524 i::ExternalTwoByteString::cast(string);
11525 morphed->set_resource(uc16_resource);
11526 } else {
11527 // Check old map is not symbol or long.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011528 CHECK(string->map() == HEAP->external_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000011529 // Morph external string to be ASCII string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011530 string->set_map(HEAP->external_ascii_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000011531 i::ExternalAsciiString* morphed =
11532 i::ExternalAsciiString::cast(string);
11533 morphed->set_resource(ascii_resource);
11534 }
11535}
11536
11537
11538// Test that we can still flatten a string if the components it is built up
11539// from have been turned into 16 bit strings in the mean time.
11540THREADED_TEST(MorphCompositeStringTest) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011541 char utf_buffer[129];
ager@chromium.org5ec48922009-05-05 07:25:34 +000011542 const char* c_string = "Now is the time for all good men"
11543 " to come to the aid of the party";
11544 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
11545 {
11546 v8::HandleScope scope;
11547 LocalContext env;
11548 AsciiVectorResource ascii_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011549 i::Vector<const char>(c_string, i::StrLength(c_string)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000011550 UC16VectorResource uc16_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011551 i::Vector<const uint16_t>(two_byte_string,
11552 i::StrLength(c_string)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000011553
11554 Local<String> lhs(v8::Utils::ToLocal(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011555 FACTORY->NewExternalStringFromAscii(&ascii_resource)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000011556 Local<String> rhs(v8::Utils::ToLocal(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011557 FACTORY->NewExternalStringFromAscii(&ascii_resource)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000011558
11559 env->Global()->Set(v8_str("lhs"), lhs);
11560 env->Global()->Set(v8_str("rhs"), rhs);
11561
11562 CompileRun(
11563 "var cons = lhs + rhs;"
11564 "var slice = lhs.substring(1, lhs.length - 1);"
11565 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
11566
11567 MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
11568 MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
11569
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011570 // This should UTF-8 without flattening, since everything is ASCII.
11571 Handle<String> cons = v8_compile("cons")->Run().As<String>();
11572 CHECK_EQ(128, cons->Utf8Length());
11573 int nchars = -1;
11574 CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
11575 CHECK_EQ(128, nchars);
11576 CHECK_EQ(0, strcmp(
11577 utf_buffer,
11578 "Now is the time for all good men to come to the aid of the party"
11579 "Now is the time for all good men to come to the aid of the party"));
11580
ager@chromium.org5ec48922009-05-05 07:25:34 +000011581 // Now do some stuff to make sure the strings are flattened, etc.
11582 CompileRun(
11583 "/[^a-z]/.test(cons);"
11584 "/[^a-z]/.test(slice);"
11585 "/[^a-z]/.test(slice_on_cons);");
11586 const char* expected_cons =
11587 "Now is the time for all good men to come to the aid of the party"
11588 "Now is the time for all good men to come to the aid of the party";
11589 const char* expected_slice =
11590 "ow is the time for all good men to come to the aid of the part";
11591 const char* expected_slice_on_cons =
11592 "ow is the time for all good men to come to the aid of the party"
11593 "Now is the time for all good men to come to the aid of the part";
11594 CHECK_EQ(String::New(expected_cons),
11595 env->Global()->Get(v8_str("cons")));
11596 CHECK_EQ(String::New(expected_slice),
11597 env->Global()->Get(v8_str("slice")));
11598 CHECK_EQ(String::New(expected_slice_on_cons),
11599 env->Global()->Get(v8_str("slice_on_cons")));
11600 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011601 i::DeleteArray(two_byte_string);
ager@chromium.org5ec48922009-05-05 07:25:34 +000011602}
11603
11604
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011605TEST(CompileExternalTwoByteSource) {
11606 v8::HandleScope scope;
11607 LocalContext context;
11608
11609 // This is a very short list of sources, which currently is to check for a
11610 // regression caused by r2703.
11611 const char* ascii_sources[] = {
11612 "0.5",
11613 "-0.5", // This mainly testes PushBack in the Scanner.
11614 "--0.5", // This mainly testes PushBack in the Scanner.
11615 NULL
11616 };
11617
11618 // Compile the sources as external two byte strings.
11619 for (int i = 0; ascii_sources[i] != NULL; i++) {
11620 uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
11621 UC16VectorResource uc16_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011622 i::Vector<const uint16_t>(two_byte_string,
11623 i::StrLength(ascii_sources[i])));
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011624 v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
11625 v8::Script::Compile(source);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011626 i::DeleteArray(two_byte_string);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011627 }
11628}
11629
11630
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011631class RegExpStringModificationTest {
11632 public:
11633 RegExpStringModificationTest()
11634 : block_(i::OS::CreateSemaphore(0)),
11635 morphs_(0),
11636 morphs_during_regexp_(0),
11637 ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
11638 uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
11639 ~RegExpStringModificationTest() { delete block_; }
11640 void RunTest() {
11641 regexp_success_ = false;
11642 morph_success_ = false;
11643
11644 // Initialize the contents of two_byte_content_ to be a uc16 representation
11645 // of "aaaaaaaaaaaaaab".
11646 for (int i = 0; i < 14; i++) {
11647 two_byte_content_[i] = 'a';
11648 }
11649 two_byte_content_[14] = 'b';
11650
11651 // Create the input string for the regexp - the one we are going to change
11652 // properties of.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011653 input_ = FACTORY->NewExternalStringFromAscii(&ascii_resource_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011654
11655 // Inject the input as a global variable.
11656 i::Handle<i::String> input_name =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011657 FACTORY->NewStringFromAscii(i::Vector<const char>("input", 5));
11658 i::Isolate::Current()->global_context()->global()->SetProperty(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011659 *input_name,
11660 *input_,
11661 NONE,
11662 i::kNonStrictMode)->ToObjectChecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011663
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011664 MorphThread morph_thread(this);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011665 morph_thread.Start();
11666 v8::Locker::StartPreemption(1);
11667 LongRunningRegExp();
11668 {
11669 v8::Unlocker unlock;
11670 morph_thread.Join();
11671 }
11672 v8::Locker::StopPreemption();
11673 CHECK(regexp_success_);
11674 CHECK(morph_success_);
11675 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011676
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000011677 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011678 // Number of string modifications required.
11679 static const int kRequiredModifications = 5;
11680 static const int kMaxModifications = 100;
11681
11682 class MorphThread : public i::Thread {
11683 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011684 explicit MorphThread(RegExpStringModificationTest* test)
11685 : Thread("MorphThread"), test_(test) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011686 virtual void Run() {
11687 test_->MorphString();
11688 }
11689 private:
11690 RegExpStringModificationTest* test_;
11691 };
11692
11693 void MorphString() {
11694 block_->Wait();
11695 while (morphs_during_regexp_ < kRequiredModifications &&
11696 morphs_ < kMaxModifications) {
11697 {
11698 v8::Locker lock;
11699 // Swap string between ascii and two-byte representation.
11700 i::String* string = *input_;
ager@chromium.org5ec48922009-05-05 07:25:34 +000011701 MorphAString(string, &ascii_resource_, &uc16_resource_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011702 morphs_++;
11703 }
11704 i::OS::Sleep(1);
11705 }
11706 morph_success_ = true;
11707 }
11708
11709 void LongRunningRegExp() {
11710 block_->Signal(); // Enable morphing thread on next preemption.
11711 while (morphs_during_regexp_ < kRequiredModifications &&
11712 morphs_ < kMaxModifications) {
11713 int morphs_before = morphs_;
11714 {
erik.corry@gmail.com145eff52010-08-23 11:36:18 +000011715 v8::HandleScope scope;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011716 // Match 15-30 "a"'s against 14 and a "b".
11717 const char* c_source =
11718 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
11719 ".exec(input) === null";
11720 Local<String> source = String::New(c_source);
11721 Local<Script> script = Script::Compile(source);
11722 Local<Value> result = script->Run();
11723 CHECK(result->IsTrue());
11724 }
11725 int morphs_after = morphs_;
11726 morphs_during_regexp_ += morphs_after - morphs_before;
11727 }
11728 regexp_success_ = true;
11729 }
11730
11731 i::uc16 two_byte_content_[15];
11732 i::Semaphore* block_;
11733 int morphs_;
11734 int morphs_during_regexp_;
11735 bool regexp_success_;
11736 bool morph_success_;
11737 i::Handle<i::String> input_;
11738 AsciiVectorResource ascii_resource_;
11739 UC16VectorResource uc16_resource_;
11740};
11741
11742
11743// Test that a regular expression execution can be interrupted and
11744// the string changed without failing.
11745TEST(RegExpStringModification) {
11746 v8::Locker lock;
11747 v8::V8::Initialize();
11748 v8::HandleScope scope;
11749 Local<Context> local_env;
11750 {
11751 LocalContext env;
11752 local_env = env.local();
11753 }
11754
11755 // Local context should still be live.
11756 CHECK(!local_env.IsEmpty());
11757 local_env->Enter();
11758
11759 // Should complete without problems.
11760 RegExpStringModificationTest().RunTest();
11761
11762 local_env->Exit();
11763}
11764
11765
11766// Test that we can set a property on the global object even if there
11767// is a read-only property in the prototype chain.
11768TEST(ReadOnlyPropertyInGlobalProto) {
11769 v8::HandleScope scope;
11770 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11771 LocalContext context(0, templ);
11772 v8::Handle<v8::Object> global = context->Global();
11773 v8::Handle<v8::Object> global_proto =
11774 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
11775 global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
11776 global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
11777 // Check without 'eval' or 'with'.
11778 v8::Handle<v8::Value> res =
11779 CompileRun("function f() { x = 42; return x; }; f()");
11780 // Check with 'eval'.
11781 res = CompileRun("function f() { eval('1'); y = 42; return y; }; f()");
11782 CHECK_EQ(v8::Integer::New(42), res);
11783 // Check with 'with'.
11784 res = CompileRun("function f() { with (this) { y = 42 }; return y; }; f()");
11785 CHECK_EQ(v8::Integer::New(42), res);
11786}
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011787
11788static int force_set_set_count = 0;
11789static int force_set_get_count = 0;
11790bool pass_on_get = false;
11791
11792static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
11793 const v8::AccessorInfo& info) {
11794 force_set_get_count++;
11795 if (pass_on_get) {
11796 return v8::Handle<v8::Value>();
11797 } else {
11798 return v8::Int32::New(3);
11799 }
11800}
11801
11802static void ForceSetSetter(v8::Local<v8::String> name,
11803 v8::Local<v8::Value> value,
11804 const v8::AccessorInfo& info) {
11805 force_set_set_count++;
11806}
11807
11808static v8::Handle<v8::Value> ForceSetInterceptSetter(
11809 v8::Local<v8::String> name,
11810 v8::Local<v8::Value> value,
11811 const v8::AccessorInfo& info) {
11812 force_set_set_count++;
11813 return v8::Undefined();
11814}
11815
11816TEST(ForceSet) {
11817 force_set_get_count = 0;
11818 force_set_set_count = 0;
11819 pass_on_get = false;
11820
11821 v8::HandleScope scope;
11822 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11823 v8::Handle<v8::String> access_property = v8::String::New("a");
11824 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
11825 LocalContext context(NULL, templ);
11826 v8::Handle<v8::Object> global = context->Global();
11827
11828 // Ordinary properties
11829 v8::Handle<v8::String> simple_property = v8::String::New("p");
11830 global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
11831 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11832 // This should fail because the property is read-only
11833 global->Set(simple_property, v8::Int32::New(5));
11834 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11835 // This should succeed even though the property is read-only
11836 global->ForceSet(simple_property, v8::Int32::New(6));
11837 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
11838
11839 // Accessors
11840 CHECK_EQ(0, force_set_set_count);
11841 CHECK_EQ(0, force_set_get_count);
11842 CHECK_EQ(3, global->Get(access_property)->Int32Value());
11843 // CHECK_EQ the property shouldn't override it, just call the setter
11844 // which in this case does nothing.
11845 global->Set(access_property, v8::Int32::New(7));
11846 CHECK_EQ(3, global->Get(access_property)->Int32Value());
11847 CHECK_EQ(1, force_set_set_count);
11848 CHECK_EQ(2, force_set_get_count);
11849 // Forcing the property to be set should override the accessor without
11850 // calling it
11851 global->ForceSet(access_property, v8::Int32::New(8));
11852 CHECK_EQ(8, global->Get(access_property)->Int32Value());
11853 CHECK_EQ(1, force_set_set_count);
11854 CHECK_EQ(2, force_set_get_count);
11855}
11856
11857TEST(ForceSetWithInterceptor) {
11858 force_set_get_count = 0;
11859 force_set_set_count = 0;
11860 pass_on_get = false;
11861
11862 v8::HandleScope scope;
11863 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11864 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
11865 LocalContext context(NULL, templ);
11866 v8::Handle<v8::Object> global = context->Global();
11867
11868 v8::Handle<v8::String> some_property = v8::String::New("a");
11869 CHECK_EQ(0, force_set_set_count);
11870 CHECK_EQ(0, force_set_get_count);
11871 CHECK_EQ(3, global->Get(some_property)->Int32Value());
11872 // Setting the property shouldn't override it, just call the setter
11873 // which in this case does nothing.
11874 global->Set(some_property, v8::Int32::New(7));
11875 CHECK_EQ(3, global->Get(some_property)->Int32Value());
11876 CHECK_EQ(1, force_set_set_count);
11877 CHECK_EQ(2, force_set_get_count);
11878 // Getting the property when the interceptor returns an empty handle
11879 // should yield undefined, since the property isn't present on the
11880 // object itself yet.
11881 pass_on_get = true;
11882 CHECK(global->Get(some_property)->IsUndefined());
11883 CHECK_EQ(1, force_set_set_count);
11884 CHECK_EQ(3, force_set_get_count);
11885 // Forcing the property to be set should cause the value to be
11886 // set locally without calling the interceptor.
11887 global->ForceSet(some_property, v8::Int32::New(8));
11888 CHECK_EQ(8, global->Get(some_property)->Int32Value());
11889 CHECK_EQ(1, force_set_set_count);
11890 CHECK_EQ(4, force_set_get_count);
11891 // Reenabling the interceptor should cause it to take precedence over
11892 // the property
11893 pass_on_get = false;
11894 CHECK_EQ(3, global->Get(some_property)->Int32Value());
11895 CHECK_EQ(1, force_set_set_count);
11896 CHECK_EQ(5, force_set_get_count);
11897 // The interceptor should also work for other properties
11898 CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
11899 CHECK_EQ(1, force_set_set_count);
11900 CHECK_EQ(6, force_set_get_count);
11901}
ager@chromium.org1bf0cd02009-05-20 11:34:19 +000011902
11903
ager@chromium.orge2902be2009-06-08 12:21:35 +000011904THREADED_TEST(ForceDelete) {
11905 v8::HandleScope scope;
11906 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
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::DontDelete);
11913 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11914 // This should fail because the property is dont-delete.
11915 CHECK(!global->Delete(simple_property));
11916 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11917 // This should succeed even though the property is dont-delete.
11918 CHECK(global->ForceDelete(simple_property));
11919 CHECK(global->Get(simple_property)->IsUndefined());
11920}
11921
11922
11923static int force_delete_interceptor_count = 0;
11924static bool pass_on_delete = false;
11925
11926
11927static v8::Handle<v8::Boolean> ForceDeleteDeleter(
11928 v8::Local<v8::String> name,
11929 const v8::AccessorInfo& info) {
11930 force_delete_interceptor_count++;
11931 if (pass_on_delete) {
11932 return v8::Handle<v8::Boolean>();
11933 } else {
11934 return v8::True();
11935 }
11936}
11937
11938
11939THREADED_TEST(ForceDeleteWithInterceptor) {
11940 force_delete_interceptor_count = 0;
11941 pass_on_delete = false;
11942
11943 v8::HandleScope scope;
11944 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11945 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
11946 LocalContext context(NULL, templ);
11947 v8::Handle<v8::Object> global = context->Global();
11948
11949 v8::Handle<v8::String> some_property = v8::String::New("a");
11950 global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
11951
11952 // Deleting a property should get intercepted and nothing should
11953 // happen.
11954 CHECK_EQ(0, force_delete_interceptor_count);
11955 CHECK(global->Delete(some_property));
11956 CHECK_EQ(1, force_delete_interceptor_count);
11957 CHECK_EQ(42, global->Get(some_property)->Int32Value());
11958 // Deleting the property when the interceptor returns an empty
11959 // handle should not delete the property since it is DontDelete.
11960 pass_on_delete = true;
11961 CHECK(!global->Delete(some_property));
11962 CHECK_EQ(2, force_delete_interceptor_count);
11963 CHECK_EQ(42, global->Get(some_property)->Int32Value());
11964 // Forcing the property to be deleted should delete the value
11965 // without calling the interceptor.
11966 CHECK(global->ForceDelete(some_property));
11967 CHECK(global->Get(some_property)->IsUndefined());
11968 CHECK_EQ(2, force_delete_interceptor_count);
11969}
11970
11971
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000011972// Make sure that forcing a delete invalidates any IC stubs, so we
11973// don't read the hole value.
11974THREADED_TEST(ForceDeleteIC) {
11975 v8::HandleScope scope;
11976 LocalContext context;
11977 // Create a DontDelete variable on the global object.
11978 CompileRun("this.__proto__ = { foo: 'horse' };"
11979 "var foo = 'fish';"
11980 "function f() { return foo.length; }");
11981 // Initialize the IC for foo in f.
11982 CompileRun("for (var i = 0; i < 4; i++) f();");
11983 // Make sure the value of foo is correct before the deletion.
11984 CHECK_EQ(4, CompileRun("f()")->Int32Value());
11985 // Force the deletion of foo.
11986 CHECK(context->Global()->ForceDelete(v8_str("foo")));
11987 // Make sure the value for foo is read from the prototype, and that
11988 // we don't get in trouble with reading the deleted cell value
11989 // sentinel.
11990 CHECK_EQ(5, CompileRun("f()")->Int32Value());
11991}
11992
11993
ager@chromium.org1bf0cd02009-05-20 11:34:19 +000011994v8::Persistent<Context> calling_context0;
11995v8::Persistent<Context> calling_context1;
11996v8::Persistent<Context> calling_context2;
11997
11998
11999// Check that the call to the callback is initiated in
12000// calling_context2, the directly calling context is calling_context1
12001// and the callback itself is in calling_context0.
12002static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
12003 ApiTestFuzzer::Fuzz();
12004 CHECK(Context::GetCurrent() == calling_context0);
12005 CHECK(Context::GetCalling() == calling_context1);
12006 CHECK(Context::GetEntered() == calling_context2);
12007 return v8::Integer::New(42);
12008}
12009
12010
12011THREADED_TEST(GetCallingContext) {
12012 v8::HandleScope scope;
12013
12014 calling_context0 = Context::New();
12015 calling_context1 = Context::New();
12016 calling_context2 = Context::New();
12017
12018 // Allow cross-domain access.
12019 Local<String> token = v8_str("<security token>");
12020 calling_context0->SetSecurityToken(token);
12021 calling_context1->SetSecurityToken(token);
12022 calling_context2->SetSecurityToken(token);
12023
12024 // Create an object with a C++ callback in context0.
12025 calling_context0->Enter();
12026 Local<v8::FunctionTemplate> callback_templ =
12027 v8::FunctionTemplate::New(GetCallingContextCallback);
12028 calling_context0->Global()->Set(v8_str("callback"),
12029 callback_templ->GetFunction());
12030 calling_context0->Exit();
12031
12032 // Expose context0 in context1 and setup a function that calls the
12033 // callback function.
12034 calling_context1->Enter();
12035 calling_context1->Global()->Set(v8_str("context0"),
12036 calling_context0->Global());
12037 CompileRun("function f() { context0.callback() }");
12038 calling_context1->Exit();
12039
12040 // Expose context1 in context2 and call the callback function in
12041 // context0 indirectly through f in context1.
12042 calling_context2->Enter();
12043 calling_context2->Global()->Set(v8_str("context1"),
12044 calling_context1->Global());
12045 CompileRun("context1.f()");
12046 calling_context2->Exit();
12047
12048 // Dispose the contexts to allow them to be garbage collected.
12049 calling_context0.Dispose();
12050 calling_context1.Dispose();
12051 calling_context2.Dispose();
12052 calling_context0.Clear();
12053 calling_context1.Clear();
12054 calling_context2.Clear();
12055}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012056
12057
12058// Check that a variable declaration with no explicit initialization
12059// value does not shadow an existing property in the prototype chain.
12060//
12061// This is consistent with Firefox and Safari.
12062//
12063// See http://crbug.com/12548.
12064THREADED_TEST(InitGlobalVarInProtoChain) {
12065 v8::HandleScope scope;
12066 LocalContext context;
12067 // Introduce a variable in the prototype chain.
12068 CompileRun("__proto__.x = 42");
12069 v8::Handle<v8::Value> result = CompileRun("var x; x");
12070 CHECK(!result->IsUndefined());
12071 CHECK_EQ(42, result->Int32Value());
12072}
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000012073
12074
12075// Regression test for issue 398.
12076// If a function is added to an object, creating a constant function
12077// field, and the result is cloned, replacing the constant function on the
12078// original should not affect the clone.
12079// See http://code.google.com/p/v8/issues/detail?id=398
12080THREADED_TEST(ReplaceConstantFunction) {
12081 v8::HandleScope scope;
12082 LocalContext context;
12083 v8::Handle<v8::Object> obj = v8::Object::New();
12084 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
12085 v8::Handle<v8::String> foo_string = v8::String::New("foo");
12086 obj->Set(foo_string, func_templ->GetFunction());
12087 v8::Handle<v8::Object> obj_clone = obj->Clone();
12088 obj_clone->Set(foo_string, v8::String::New("Hello"));
12089 CHECK(!obj->Get(foo_string)->IsUndefined());
12090}
kasperl@chromium.orge959c182009-07-27 08:59:04 +000012091
12092
12093// Regression test for http://crbug.com/16276.
12094THREADED_TEST(Regress16276) {
12095 v8::HandleScope scope;
12096 LocalContext context;
12097 // Force the IC in f to be a dictionary load IC.
12098 CompileRun("function f(obj) { return obj.x; }\n"
12099 "var obj = { x: { foo: 42 }, y: 87 };\n"
12100 "var x = obj.x;\n"
12101 "delete obj.y;\n"
12102 "for (var i = 0; i < 5; i++) f(obj);");
12103 // Detach the global object to make 'this' refer directly to the
12104 // global object (not the proxy), and make sure that the dictionary
12105 // load IC doesn't mess up loading directly from the global object.
12106 context->DetachGlobal();
12107 CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
12108}
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012109
12110
12111THREADED_TEST(PixelArray) {
12112 v8::HandleScope scope;
12113 LocalContext context;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000012114 const int kElementCount = 260;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012115 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012116 i::Handle<i::ExternalPixelArray> pixels =
12117 i::Handle<i::ExternalPixelArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012118 FACTORY->NewExternalArray(kElementCount,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012119 v8::kExternalPixelArray,
12120 pixel_data));
12121 // Force GC to trigger verification.
12122 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012123 for (int i = 0; i < kElementCount; i++) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000012124 pixels->set(i, i % 256);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012125 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012126 // Force GC to trigger verification.
12127 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012128 for (int i = 0; i < kElementCount; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012129 CHECK_EQ(i % 256, pixels->get_scalar(i));
ager@chromium.orgc4c92722009-11-18 14:12:51 +000012130 CHECK_EQ(i % 256, pixel_data[i]);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012131 }
12132
12133 v8::Handle<v8::Object> obj = v8::Object::New();
12134 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
12135 // Set the elements to be the pixels.
12136 // jsobj->set_elements(*pixels);
12137 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012138 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012139 obj->Set(v8_str("field"), v8::Int32::New(1503));
12140 context->Global()->Set(v8_str("pixels"), obj);
12141 v8::Handle<v8::Value> result = CompileRun("pixels.field");
12142 CHECK_EQ(1503, result->Int32Value());
12143 result = CompileRun("pixels[1]");
12144 CHECK_EQ(1, result->Int32Value());
sgjesse@chromium.org9eceac12009-09-30 07:18:41 +000012145
12146 result = CompileRun("var sum = 0;"
12147 "for (var i = 0; i < 8; i++) {"
12148 " sum += pixels[i] = pixels[i] = -i;"
12149 "}"
12150 "sum;");
12151 CHECK_EQ(-28, result->Int32Value());
12152
12153 result = CompileRun("var sum = 0;"
12154 "for (var i = 0; i < 8; i++) {"
12155 " sum += pixels[i] = pixels[i] = 0;"
12156 "}"
12157 "sum;");
12158 CHECK_EQ(0, result->Int32Value());
12159
12160 result = CompileRun("var sum = 0;"
12161 "for (var i = 0; i < 8; i++) {"
12162 " sum += pixels[i] = pixels[i] = 255;"
12163 "}"
12164 "sum;");
12165 CHECK_EQ(8 * 255, result->Int32Value());
12166
12167 result = CompileRun("var sum = 0;"
12168 "for (var i = 0; i < 8; i++) {"
12169 " sum += pixels[i] = pixels[i] = 256 + i;"
12170 "}"
12171 "sum;");
12172 CHECK_EQ(2076, result->Int32Value());
12173
12174 result = CompileRun("var sum = 0;"
12175 "for (var i = 0; i < 8; i++) {"
12176 " sum += pixels[i] = pixels[i] = i;"
12177 "}"
12178 "sum;");
12179 CHECK_EQ(28, result->Int32Value());
12180
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012181 result = CompileRun("var sum = 0;"
12182 "for (var i = 0; i < 8; i++) {"
12183 " sum += pixels[i];"
12184 "}"
12185 "sum;");
12186 CHECK_EQ(28, result->Int32Value());
12187
12188 i::Handle<i::Smi> value(i::Smi::FromInt(2));
jkummerow@chromium.org486075a2011-09-07 12:44:28 +000012189 i::Handle<i::Object> no_failure;
12190 no_failure = i::SetElement(jsobj, 1, value, i::kNonStrictMode);
12191 ASSERT(!no_failure.is_null());
12192 i::USE(no_failure);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012193 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012194 *value.location() = i::Smi::FromInt(256);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +000012195 no_failure = i::SetElement(jsobj, 1, value, i::kNonStrictMode);
12196 ASSERT(!no_failure.is_null());
12197 i::USE(no_failure);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012198 CHECK_EQ(255,
12199 i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012200 *value.location() = i::Smi::FromInt(-1);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +000012201 no_failure = i::SetElement(jsobj, 1, value, i::kNonStrictMode);
12202 ASSERT(!no_failure.is_null());
12203 i::USE(no_failure);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012204 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012205
12206 result = CompileRun("for (var i = 0; i < 8; i++) {"
12207 " pixels[i] = (i * 65) - 109;"
12208 "}"
12209 "pixels[1] + pixels[6];");
12210 CHECK_EQ(255, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012211 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
12212 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
12213 CHECK_EQ(21,
12214 i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
12215 CHECK_EQ(86,
12216 i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
12217 CHECK_EQ(151,
12218 i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
12219 CHECK_EQ(216,
12220 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
12221 CHECK_EQ(255,
12222 i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
12223 CHECK_EQ(255,
12224 i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012225 result = CompileRun("var sum = 0;"
12226 "for (var i = 0; i < 8; i++) {"
12227 " sum += pixels[i];"
12228 "}"
12229 "sum;");
12230 CHECK_EQ(984, result->Int32Value());
12231
12232 result = CompileRun("for (var i = 0; i < 8; i++) {"
12233 " pixels[i] = (i * 1.1);"
12234 "}"
12235 "pixels[1] + pixels[6];");
12236 CHECK_EQ(8, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012237 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
12238 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
12239 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
12240 CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
12241 CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
12242 CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
12243 CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
12244 CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012245
12246 result = CompileRun("for (var i = 0; i < 8; i++) {"
12247 " pixels[7] = undefined;"
12248 "}"
12249 "pixels[7];");
12250 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012251 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012252
12253 result = CompileRun("for (var i = 0; i < 8; i++) {"
12254 " pixels[6] = '2.3';"
12255 "}"
12256 "pixels[6];");
12257 CHECK_EQ(2, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012258 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012259
12260 result = CompileRun("for (var i = 0; i < 8; i++) {"
12261 " pixels[5] = NaN;"
12262 "}"
12263 "pixels[5];");
12264 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012265 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012266
12267 result = CompileRun("for (var i = 0; i < 8; i++) {"
12268 " pixels[8] = Infinity;"
12269 "}"
12270 "pixels[8];");
12271 CHECK_EQ(255, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012272 CHECK_EQ(255,
12273 i::Smi::cast(jsobj->GetElement(8)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012274
12275 result = CompileRun("for (var i = 0; i < 8; i++) {"
12276 " pixels[9] = -Infinity;"
12277 "}"
12278 "pixels[9];");
12279 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012280 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012281
12282 result = CompileRun("pixels[3] = 33;"
12283 "delete pixels[3];"
12284 "pixels[3];");
12285 CHECK_EQ(33, result->Int32Value());
12286
12287 result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
12288 "pixels[2] = 12; pixels[3] = 13;"
12289 "pixels.__defineGetter__('2',"
12290 "function() { return 120; });"
12291 "pixels[2];");
12292 CHECK_EQ(12, result->Int32Value());
12293
12294 result = CompileRun("var js_array = new Array(40);"
12295 "js_array[0] = 77;"
12296 "js_array;");
12297 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
12298
12299 result = CompileRun("pixels[1] = 23;"
12300 "pixels.__proto__ = [];"
12301 "js_array.__proto__ = pixels;"
12302 "js_array.concat(pixels);");
12303 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
12304 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
12305
sgjesse@chromium.org9eceac12009-09-30 07:18:41 +000012306 result = CompileRun("pixels[1] = 23;");
12307 CHECK_EQ(23, result->Int32Value());
12308
ager@chromium.orgc4c92722009-11-18 14:12:51 +000012309 // Test for index greater than 255. Regression test for:
12310 // http://code.google.com/p/chromium/issues/detail?id=26337.
12311 result = CompileRun("pixels[256] = 255;");
12312 CHECK_EQ(255, result->Int32Value());
12313 result = CompileRun("var i = 0;"
12314 "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
12315 "i");
12316 CHECK_EQ(255, result->Int32Value());
12317
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012318 // Make sure that pixel array ICs recognize when a non-pixel array
12319 // is passed to it.
12320 result = CompileRun("function pa_load(p) {"
12321 " var sum = 0;"
12322 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
12323 " return sum;"
12324 "}"
12325 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12326 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
12327 "just_ints = new Object();"
12328 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12329 "for (var i = 0; i < 10; ++i) {"
12330 " result = pa_load(just_ints);"
12331 "}"
12332 "result");
12333 CHECK_EQ(32640, result->Int32Value());
12334
12335 // Make sure that pixel array ICs recognize out-of-bound accesses.
12336 result = CompileRun("function pa_load(p, start) {"
12337 " var sum = 0;"
12338 " for (var j = start; j < 256; j++) { sum += p[j]; }"
12339 " return sum;"
12340 "}"
12341 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12342 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
12343 "for (var i = 0; i < 10; ++i) {"
12344 " result = pa_load(pixels,-10);"
12345 "}"
12346 "result");
12347 CHECK_EQ(0, result->Int32Value());
12348
12349 // Make sure that generic ICs properly handles a pixel array.
12350 result = CompileRun("function pa_load(p) {"
12351 " var sum = 0;"
12352 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
12353 " return sum;"
12354 "}"
12355 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12356 "just_ints = new Object();"
12357 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12358 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
12359 "for (var i = 0; i < 10; ++i) {"
12360 " result = pa_load(pixels);"
12361 "}"
12362 "result");
12363 CHECK_EQ(32640, result->Int32Value());
12364
12365 // Make sure that generic load ICs recognize out-of-bound accesses in
12366 // pixel arrays.
12367 result = CompileRun("function pa_load(p, start) {"
12368 " var sum = 0;"
12369 " for (var j = start; j < 256; j++) { sum += p[j]; }"
12370 " return sum;"
12371 "}"
12372 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12373 "just_ints = new Object();"
12374 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12375 "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
12376 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
12377 "for (var i = 0; i < 10; ++i) {"
12378 " result = pa_load(pixels,-10);"
12379 "}"
12380 "result");
12381 CHECK_EQ(0, result->Int32Value());
12382
12383 // Make sure that generic ICs properly handles other types than pixel
12384 // arrays (that the inlined fast pixel array test leaves the right information
12385 // in the right registers).
12386 result = CompileRun("function pa_load(p) {"
12387 " var sum = 0;"
12388 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
12389 " return sum;"
12390 "}"
12391 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12392 "just_ints = new Object();"
12393 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12394 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
12395 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
12396 "sparse_array = new Object();"
12397 "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
12398 "sparse_array[1000000] = 3;"
12399 "for (var i = 0; i < 10; ++i) {"
12400 " result = pa_load(sparse_array);"
12401 "}"
12402 "result");
12403 CHECK_EQ(32640, result->Int32Value());
12404
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +000012405 // Make sure that pixel array store ICs clamp values correctly.
12406 result = CompileRun("function pa_store(p) {"
12407 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
12408 "}"
12409 "pa_store(pixels);"
12410 "var sum = 0;"
12411 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
12412 "sum");
12413 CHECK_EQ(48896, result->Int32Value());
12414
12415 // Make sure that pixel array stores correctly handle accesses outside
12416 // of the pixel array..
12417 result = CompileRun("function pa_store(p,start) {"
12418 " for (var j = 0; j < 256; j++) {"
12419 " p[j+start] = j * 2;"
12420 " }"
12421 "}"
12422 "pa_store(pixels,0);"
12423 "pa_store(pixels,-128);"
12424 "var sum = 0;"
12425 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
12426 "sum");
12427 CHECK_EQ(65280, result->Int32Value());
12428
12429 // Make sure that the generic store stub correctly handle accesses outside
12430 // of the pixel array..
12431 result = CompileRun("function pa_store(p,start) {"
12432 " for (var j = 0; j < 256; j++) {"
12433 " p[j+start] = j * 2;"
12434 " }"
12435 "}"
12436 "pa_store(pixels,0);"
12437 "just_ints = new Object();"
12438 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12439 "pa_store(just_ints, 0);"
12440 "pa_store(pixels,-128);"
12441 "var sum = 0;"
12442 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
12443 "sum");
12444 CHECK_EQ(65280, result->Int32Value());
12445
12446 // Make sure that the generic keyed store stub clamps pixel array values
12447 // correctly.
12448 result = CompileRun("function pa_store(p) {"
12449 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
12450 "}"
12451 "pa_store(pixels);"
12452 "just_ints = new Object();"
12453 "pa_store(just_ints);"
12454 "pa_store(pixels);"
12455 "var sum = 0;"
12456 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
12457 "sum");
12458 CHECK_EQ(48896, result->Int32Value());
12459
12460 // Make sure that pixel array loads are optimized by crankshaft.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000012461 result = CompileRun("function pa_load(p) {"
12462 " var sum = 0;"
12463 " for (var i=0; i<256; ++i) {"
12464 " sum += p[i];"
12465 " }"
12466 " return sum; "
12467 "}"
12468 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012469 "for (var i = 0; i < 5000; ++i) {"
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000012470 " result = pa_load(pixels);"
12471 "}"
12472 "result");
12473 CHECK_EQ(32640, result->Int32Value());
12474
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000012475 // Make sure that pixel array stores are optimized by crankshaft.
12476 result = CompileRun("function pa_init(p) {"
12477 "for (var i = 0; i < 256; ++i) { p[i] = i; }"
12478 "}"
12479 "function pa_load(p) {"
12480 " var sum = 0;"
12481 " for (var i=0; i<256; ++i) {"
12482 " sum += p[i];"
12483 " }"
12484 " return sum; "
12485 "}"
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012486 "for (var i = 0; i < 5000; ++i) {"
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000012487 " pa_init(pixels);"
12488 "}"
12489 "result = pa_load(pixels);"
12490 "result");
12491 CHECK_EQ(32640, result->Int32Value());
12492
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012493 free(pixel_data);
12494}
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000012495
ager@chromium.org96c75b52009-08-26 09:13:16 +000012496
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000012497THREADED_TEST(PixelArrayInfo) {
12498 v8::HandleScope scope;
12499 LocalContext context;
12500 for (int size = 0; size < 100; size += 10) {
12501 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
12502 v8::Handle<v8::Object> obj = v8::Object::New();
12503 obj->SetIndexedPropertiesToPixelData(pixel_data, size);
12504 CHECK(obj->HasIndexedPropertiesInPixelData());
12505 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
12506 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
12507 free(pixel_data);
12508 }
12509}
12510
12511
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000012512static v8::Handle<Value> NotHandledIndexedPropertyGetter(
12513 uint32_t index,
12514 const AccessorInfo& info) {
12515 ApiTestFuzzer::Fuzz();
12516 return v8::Handle<Value>();
12517}
12518
12519
12520static v8::Handle<Value> NotHandledIndexedPropertySetter(
12521 uint32_t index,
12522 Local<Value> value,
12523 const AccessorInfo& info) {
12524 ApiTestFuzzer::Fuzz();
12525 return v8::Handle<Value>();
12526}
12527
12528
12529THREADED_TEST(PixelArrayWithInterceptor) {
12530 v8::HandleScope scope;
12531 LocalContext context;
12532 const int kElementCount = 260;
12533 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012534 i::Handle<i::ExternalPixelArray> pixels =
12535 i::Handle<i::ExternalPixelArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012536 FACTORY->NewExternalArray(kElementCount,
12537 v8::kExternalPixelArray,
12538 pixel_data));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000012539 for (int i = 0; i < kElementCount; i++) {
12540 pixels->set(i, i % 256);
12541 }
12542 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12543 templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
12544 NotHandledIndexedPropertySetter);
12545 v8::Handle<v8::Object> obj = templ->NewInstance();
12546 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
12547 context->Global()->Set(v8_str("pixels"), obj);
12548 v8::Handle<v8::Value> result = CompileRun("pixels[1]");
12549 CHECK_EQ(1, result->Int32Value());
12550 result = CompileRun("var sum = 0;"
12551 "for (var i = 0; i < 8; i++) {"
12552 " sum += pixels[i] = pixels[i] = -i;"
12553 "}"
12554 "sum;");
12555 CHECK_EQ(-28, result->Int32Value());
12556 result = CompileRun("pixels.hasOwnProperty('1')");
12557 CHECK(result->BooleanValue());
12558 free(pixel_data);
12559}
12560
12561
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000012562static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
12563 switch (array_type) {
12564 case v8::kExternalByteArray:
12565 case v8::kExternalUnsignedByteArray:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012566 case v8::kExternalPixelArray:
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000012567 return 1;
12568 break;
12569 case v8::kExternalShortArray:
12570 case v8::kExternalUnsignedShortArray:
12571 return 2;
12572 break;
12573 case v8::kExternalIntArray:
12574 case v8::kExternalUnsignedIntArray:
12575 case v8::kExternalFloatArray:
12576 return 4;
12577 break;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000012578 case v8::kExternalDoubleArray:
12579 return 8;
12580 break;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000012581 default:
12582 UNREACHABLE();
12583 return -1;
12584 }
12585 UNREACHABLE();
12586 return -1;
12587}
12588
12589
ager@chromium.org3811b432009-10-28 14:53:37 +000012590template <class ExternalArrayClass, class ElementType>
12591static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
12592 int64_t low,
12593 int64_t high) {
12594 v8::HandleScope scope;
12595 LocalContext context;
12596 const int kElementCount = 40;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000012597 int element_size = ExternalArrayElementSize(array_type);
ager@chromium.org3811b432009-10-28 14:53:37 +000012598 ElementType* array_data =
12599 static_cast<ElementType*>(malloc(kElementCount * element_size));
12600 i::Handle<ExternalArrayClass> array =
12601 i::Handle<ExternalArrayClass>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012602 FACTORY->NewExternalArray(kElementCount, array_type, array_data));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012603 // Force GC to trigger verification.
12604 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3811b432009-10-28 14:53:37 +000012605 for (int i = 0; i < kElementCount; i++) {
12606 array->set(i, static_cast<ElementType>(i));
12607 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012608 // Force GC to trigger verification.
12609 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3811b432009-10-28 14:53:37 +000012610 for (int i = 0; i < kElementCount; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012611 CHECK_EQ(static_cast<int64_t>(i),
12612 static_cast<int64_t>(array->get_scalar(i)));
ager@chromium.org3811b432009-10-28 14:53:37 +000012613 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
12614 }
12615
12616 v8::Handle<v8::Object> obj = v8::Object::New();
12617 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
12618 // Set the elements to be the external array.
12619 obj->SetIndexedPropertiesToExternalArrayData(array_data,
12620 array_type,
12621 kElementCount);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012622 CHECK_EQ(
12623 1, static_cast<int>(jsobj->GetElement(1)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000012624 obj->Set(v8_str("field"), v8::Int32::New(1503));
12625 context->Global()->Set(v8_str("ext_array"), obj);
12626 v8::Handle<v8::Value> result = CompileRun("ext_array.field");
12627 CHECK_EQ(1503, result->Int32Value());
12628 result = CompileRun("ext_array[1]");
12629 CHECK_EQ(1, result->Int32Value());
12630
12631 // Check pass through of assigned smis
12632 result = CompileRun("var sum = 0;"
12633 "for (var i = 0; i < 8; i++) {"
12634 " sum += ext_array[i] = ext_array[i] = -i;"
12635 "}"
12636 "sum;");
12637 CHECK_EQ(-28, result->Int32Value());
12638
12639 // Check assigned smis
12640 result = CompileRun("for (var i = 0; i < 8; i++) {"
12641 " ext_array[i] = i;"
12642 "}"
12643 "var sum = 0;"
12644 "for (var i = 0; i < 8; i++) {"
12645 " sum += ext_array[i];"
12646 "}"
12647 "sum;");
12648 CHECK_EQ(28, result->Int32Value());
12649
12650 // Check assigned smis in reverse order
12651 result = CompileRun("for (var i = 8; --i >= 0; ) {"
12652 " ext_array[i] = i;"
12653 "}"
12654 "var sum = 0;"
12655 "for (var i = 0; i < 8; i++) {"
12656 " sum += ext_array[i];"
12657 "}"
12658 "sum;");
12659 CHECK_EQ(28, result->Int32Value());
12660
12661 // Check pass through of assigned HeapNumbers
12662 result = CompileRun("var sum = 0;"
12663 "for (var i = 0; i < 16; i+=2) {"
12664 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
12665 "}"
12666 "sum;");
12667 CHECK_EQ(-28, result->Int32Value());
12668
12669 // Check assigned HeapNumbers
12670 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
12671 " ext_array[i] = (i * 0.5);"
12672 "}"
12673 "var sum = 0;"
12674 "for (var i = 0; i < 16; i+=2) {"
12675 " sum += ext_array[i];"
12676 "}"
12677 "sum;");
12678 CHECK_EQ(28, result->Int32Value());
12679
12680 // Check assigned HeapNumbers in reverse order
12681 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
12682 " ext_array[i] = (i * 0.5);"
12683 "}"
12684 "var sum = 0;"
12685 "for (var i = 0; i < 16; i+=2) {"
12686 " sum += ext_array[i];"
12687 "}"
12688 "sum;");
12689 CHECK_EQ(28, result->Int32Value());
12690
12691 i::ScopedVector<char> test_buf(1024);
12692
12693 // Check legal boundary conditions.
12694 // The repeated loads and stores ensure the ICs are exercised.
12695 const char* boundary_program =
12696 "var res = 0;"
12697 "for (var i = 0; i < 16; i++) {"
12698 " ext_array[i] = %lld;"
12699 " if (i > 8) {"
12700 " res = ext_array[i];"
12701 " }"
12702 "}"
12703 "res;";
12704 i::OS::SNPrintF(test_buf,
12705 boundary_program,
12706 low);
12707 result = CompileRun(test_buf.start());
12708 CHECK_EQ(low, result->IntegerValue());
12709
12710 i::OS::SNPrintF(test_buf,
12711 boundary_program,
12712 high);
12713 result = CompileRun(test_buf.start());
12714 CHECK_EQ(high, result->IntegerValue());
12715
12716 // Check misprediction of type in IC.
12717 result = CompileRun("var tmp_array = ext_array;"
12718 "var sum = 0;"
12719 "for (var i = 0; i < 8; i++) {"
12720 " tmp_array[i] = i;"
12721 " sum += tmp_array[i];"
12722 " if (i == 4) {"
12723 " tmp_array = {};"
12724 " }"
12725 "}"
12726 "sum;");
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012727 // Force GC to trigger verification.
12728 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3811b432009-10-28 14:53:37 +000012729 CHECK_EQ(28, result->Int32Value());
12730
12731 // Make sure out-of-range loads do not throw.
12732 i::OS::SNPrintF(test_buf,
12733 "var caught_exception = false;"
12734 "try {"
12735 " ext_array[%d];"
12736 "} catch (e) {"
12737 " caught_exception = true;"
12738 "}"
12739 "caught_exception;",
12740 kElementCount);
12741 result = CompileRun(test_buf.start());
12742 CHECK_EQ(false, result->BooleanValue());
12743
12744 // Make sure out-of-range stores do not throw.
12745 i::OS::SNPrintF(test_buf,
12746 "var caught_exception = false;"
12747 "try {"
12748 " ext_array[%d] = 1;"
12749 "} catch (e) {"
12750 " caught_exception = true;"
12751 "}"
12752 "caught_exception;",
12753 kElementCount);
12754 result = CompileRun(test_buf.start());
12755 CHECK_EQ(false, result->BooleanValue());
12756
12757 // Check other boundary conditions, values and operations.
12758 result = CompileRun("for (var i = 0; i < 8; i++) {"
12759 " ext_array[7] = undefined;"
12760 "}"
12761 "ext_array[7];");
12762 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012763 CHECK_EQ(
12764 0, static_cast<int>(jsobj->GetElement(7)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000012765
12766 result = CompileRun("for (var i = 0; i < 8; i++) {"
12767 " ext_array[6] = '2.3';"
12768 "}"
12769 "ext_array[6];");
12770 CHECK_EQ(2, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012771 CHECK_EQ(
12772 2, static_cast<int>(jsobj->GetElement(6)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000012773
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000012774 if (array_type != v8::kExternalFloatArray &&
12775 array_type != v8::kExternalDoubleArray) {
ager@chromium.org3811b432009-10-28 14:53:37 +000012776 // Though the specification doesn't state it, be explicit about
12777 // converting NaNs and +/-Infinity to zero.
12778 result = CompileRun("for (var i = 0; i < 8; i++) {"
12779 " ext_array[i] = 5;"
12780 "}"
12781 "for (var i = 0; i < 8; i++) {"
12782 " ext_array[i] = NaN;"
12783 "}"
12784 "ext_array[5];");
12785 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012786 CHECK_EQ(0,
12787 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
ager@chromium.org3811b432009-10-28 14:53:37 +000012788
12789 result = CompileRun("for (var i = 0; i < 8; i++) {"
12790 " ext_array[i] = 5;"
12791 "}"
12792 "for (var i = 0; i < 8; i++) {"
12793 " ext_array[i] = Infinity;"
12794 "}"
12795 "ext_array[5];");
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012796 int expected_value =
12797 (array_type == v8::kExternalPixelArray) ? 255 : 0;
12798 CHECK_EQ(expected_value, result->Int32Value());
12799 CHECK_EQ(expected_value,
lrn@chromium.org303ada72010-10-27 09:33:13 +000012800 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
ager@chromium.org3811b432009-10-28 14:53:37 +000012801
12802 result = CompileRun("for (var i = 0; i < 8; i++) {"
12803 " ext_array[i] = 5;"
12804 "}"
12805 "for (var i = 0; i < 8; i++) {"
12806 " ext_array[i] = -Infinity;"
12807 "}"
12808 "ext_array[5];");
12809 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012810 CHECK_EQ(0,
12811 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000012812
12813 // Check truncation behavior of integral arrays.
12814 const char* unsigned_data =
12815 "var source_data = [0.6, 10.6];"
12816 "var expected_results = [0, 10];";
12817 const char* signed_data =
12818 "var source_data = [0.6, 10.6, -0.6, -10.6];"
12819 "var expected_results = [0, 10, 0, -10];";
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012820 const char* pixel_data =
12821 "var source_data = [0.6, 10.6];"
12822 "var expected_results = [1, 11];";
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000012823 bool is_unsigned =
12824 (array_type == v8::kExternalUnsignedByteArray ||
12825 array_type == v8::kExternalUnsignedShortArray ||
12826 array_type == v8::kExternalUnsignedIntArray);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012827 bool is_pixel_data = array_type == v8::kExternalPixelArray;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000012828
12829 i::OS::SNPrintF(test_buf,
12830 "%s"
12831 "var all_passed = true;"
12832 "for (var i = 0; i < source_data.length; i++) {"
12833 " for (var j = 0; j < 8; j++) {"
12834 " ext_array[j] = source_data[i];"
12835 " }"
12836 " all_passed = all_passed &&"
12837 " (ext_array[5] == expected_results[i]);"
12838 "}"
12839 "all_passed;",
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012840 (is_unsigned ?
12841 unsigned_data :
12842 (is_pixel_data ? pixel_data : signed_data)));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000012843 result = CompileRun(test_buf.start());
12844 CHECK_EQ(true, result->BooleanValue());
ager@chromium.org3811b432009-10-28 14:53:37 +000012845 }
12846
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000012847 for (int i = 0; i < kElementCount; i++) {
12848 array->set(i, static_cast<ElementType>(i));
12849 }
12850 // Test complex assignments
12851 result = CompileRun("function ee_op_test_complex_func(sum) {"
12852 " for (var i = 0; i < 40; ++i) {"
12853 " sum += (ext_array[i] += 1);"
12854 " sum += (ext_array[i] -= 1);"
12855 " } "
12856 " return sum;"
12857 "}"
12858 "sum=0;"
12859 "for (var i=0;i<10000;++i) {"
12860 " sum=ee_op_test_complex_func(sum);"
12861 "}"
12862 "sum;");
12863 CHECK_EQ(16000000, result->Int32Value());
12864
12865 // Test count operations
12866 result = CompileRun("function ee_op_test_count_func(sum) {"
12867 " for (var i = 0; i < 40; ++i) {"
12868 " sum += (++ext_array[i]);"
12869 " sum += (--ext_array[i]);"
12870 " } "
12871 " return sum;"
12872 "}"
12873 "sum=0;"
12874 "for (var i=0;i<10000;++i) {"
12875 " sum=ee_op_test_count_func(sum);"
12876 "}"
12877 "sum;");
12878 CHECK_EQ(16000000, result->Int32Value());
12879
ager@chromium.org3811b432009-10-28 14:53:37 +000012880 result = CompileRun("ext_array[3] = 33;"
12881 "delete ext_array[3];"
12882 "ext_array[3];");
12883 CHECK_EQ(33, result->Int32Value());
12884
12885 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
12886 "ext_array[2] = 12; ext_array[3] = 13;"
12887 "ext_array.__defineGetter__('2',"
12888 "function() { return 120; });"
12889 "ext_array[2];");
12890 CHECK_EQ(12, result->Int32Value());
12891
12892 result = CompileRun("var js_array = new Array(40);"
12893 "js_array[0] = 77;"
12894 "js_array;");
12895 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
12896
12897 result = CompileRun("ext_array[1] = 23;"
12898 "ext_array.__proto__ = [];"
12899 "js_array.__proto__ = ext_array;"
12900 "js_array.concat(ext_array);");
12901 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
12902 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
12903
12904 result = CompileRun("ext_array[1] = 23;");
12905 CHECK_EQ(23, result->Int32Value());
12906
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012907 // Test more complex manipulations which cause eax to contain values
12908 // that won't be completely overwritten by loads from the arrays.
12909 // This catches bugs in the instructions used for the KeyedLoadIC
12910 // for byte and word types.
12911 {
12912 const int kXSize = 300;
12913 const int kYSize = 300;
12914 const int kLargeElementCount = kXSize * kYSize * 4;
12915 ElementType* large_array_data =
12916 static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012917 i::Handle<ExternalArrayClass> large_array(
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012918 i::Handle<ExternalArrayClass>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012919 FACTORY->NewExternalArray(kLargeElementCount,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012920 array_type,
12921 array_data)));
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012922 v8::Handle<v8::Object> large_obj = v8::Object::New();
12923 // Set the elements to be the external array.
12924 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
12925 array_type,
12926 kLargeElementCount);
12927 context->Global()->Set(v8_str("large_array"), large_obj);
12928 // Initialize contents of a few rows.
12929 for (int x = 0; x < 300; x++) {
12930 int row = 0;
12931 int offset = row * 300 * 4;
12932 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
12933 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
12934 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
12935 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
12936 row = 150;
12937 offset = row * 300 * 4;
12938 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
12939 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
12940 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
12941 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
12942 row = 298;
12943 offset = row * 300 * 4;
12944 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
12945 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
12946 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
12947 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
12948 }
12949 // The goal of the code below is to make "offset" large enough
12950 // that the computation of the index (which goes into eax) has
12951 // high bits set which will not be overwritten by a byte or short
12952 // load.
12953 result = CompileRun("var failed = false;"
12954 "var offset = 0;"
12955 "for (var i = 0; i < 300; i++) {"
12956 " if (large_array[4 * i] != 127 ||"
12957 " large_array[4 * i + 1] != 0 ||"
12958 " large_array[4 * i + 2] != 0 ||"
12959 " large_array[4 * i + 3] != 127) {"
12960 " failed = true;"
12961 " }"
12962 "}"
12963 "offset = 150 * 300 * 4;"
12964 "for (var i = 0; i < 300; i++) {"
12965 " if (large_array[offset + 4 * i] != 127 ||"
12966 " large_array[offset + 4 * i + 1] != 0 ||"
12967 " large_array[offset + 4 * i + 2] != 0 ||"
12968 " large_array[offset + 4 * i + 3] != 127) {"
12969 " failed = true;"
12970 " }"
12971 "}"
12972 "offset = 298 * 300 * 4;"
12973 "for (var i = 0; i < 300; i++) {"
12974 " if (large_array[offset + 4 * i] != 127 ||"
12975 " large_array[offset + 4 * i + 1] != 0 ||"
12976 " large_array[offset + 4 * i + 2] != 0 ||"
12977 " large_array[offset + 4 * i + 3] != 127) {"
12978 " failed = true;"
12979 " }"
12980 "}"
12981 "!failed;");
12982 CHECK_EQ(true, result->BooleanValue());
12983 free(large_array_data);
12984 }
12985
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012986 // The "" property descriptor is overloaded to store information about
12987 // the external array. Ensure that setting and accessing the "" property
12988 // works (it should overwrite the information cached about the external
12989 // array in the DescriptorArray) in various situations.
12990 result = CompileRun("ext_array[''] = 23; ext_array['']");
12991 CHECK_EQ(23, result->Int32Value());
12992
12993 // Property "" set after the external array is associated with the object.
12994 {
12995 v8::Handle<v8::Object> obj2 = v8::Object::New();
12996 obj2->Set(v8_str("ee_test_field"), v8::Int32::New(256));
12997 obj2->Set(v8_str(""), v8::Int32::New(1503));
12998 // Set the elements to be the external array.
12999 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
13000 array_type,
13001 kElementCount);
13002 context->Global()->Set(v8_str("ext_array"), obj2);
13003 result = CompileRun("ext_array['']");
13004 CHECK_EQ(1503, result->Int32Value());
13005 }
13006
13007 // Property "" set after the external array is associated with the object.
13008 {
13009 v8::Handle<v8::Object> obj2 = v8::Object::New();
13010 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
13011 // Set the elements to be the external array.
13012 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
13013 array_type,
13014 kElementCount);
13015 obj2->Set(v8_str(""), v8::Int32::New(1503));
13016 context->Global()->Set(v8_str("ext_array"), obj2);
13017 result = CompileRun("ext_array['']");
13018 CHECK_EQ(1503, result->Int32Value());
13019 }
13020
13021 // Should reuse the map from previous test.
13022 {
13023 v8::Handle<v8::Object> obj2 = v8::Object::New();
13024 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
13025 // Set the elements to be the external array. Should re-use the map
13026 // from previous test.
13027 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
13028 array_type,
13029 kElementCount);
13030 context->Global()->Set(v8_str("ext_array"), obj2);
13031 result = CompileRun("ext_array['']");
13032 }
13033
13034 // Property "" is a constant function that shouldn't not be interfered with
13035 // when an external array is set.
13036 {
13037 v8::Handle<v8::Object> obj2 = v8::Object::New();
13038 // Start
13039 obj2->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
13040
13041 // Add a constant function to an object.
13042 context->Global()->Set(v8_str("ext_array"), obj2);
13043 result = CompileRun("ext_array[''] = function() {return 1503;};"
13044 "ext_array['']();");
13045
13046 // Add an external array transition to the same map that
13047 // has the constant transition.
13048 v8::Handle<v8::Object> obj3 = v8::Object::New();
13049 obj3->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
13050 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
13051 array_type,
13052 kElementCount);
13053 context->Global()->Set(v8_str("ext_array"), obj3);
13054 }
13055
13056 // If a external array transition is in the map, it should get clobbered
13057 // by a constant function.
13058 {
13059 // Add an external array transition.
13060 v8::Handle<v8::Object> obj3 = v8::Object::New();
13061 obj3->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
13062 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
13063 array_type,
13064 kElementCount);
13065
13066 // Add a constant function to the same map that just got an external array
13067 // transition.
13068 v8::Handle<v8::Object> obj2 = v8::Object::New();
13069 obj2->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
13070 context->Global()->Set(v8_str("ext_array"), obj2);
13071 result = CompileRun("ext_array[''] = function() {return 1503;};"
13072 "ext_array['']();");
13073 }
13074
ager@chromium.org3811b432009-10-28 14:53:37 +000013075 free(array_data);
13076}
13077
13078
13079THREADED_TEST(ExternalByteArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000013080 ExternalArrayTestHelper<i::ExternalByteArray, int8_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000013081 v8::kExternalByteArray,
13082 -128,
13083 127);
13084}
13085
13086
13087THREADED_TEST(ExternalUnsignedByteArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000013088 ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000013089 v8::kExternalUnsignedByteArray,
13090 0,
13091 255);
13092}
13093
13094
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000013095THREADED_TEST(ExternalPixelArray) {
13096 ExternalArrayTestHelper<i::ExternalPixelArray, uint8_t>(
13097 v8::kExternalPixelArray,
13098 0,
13099 255);
13100}
13101
13102
ager@chromium.org3811b432009-10-28 14:53:37 +000013103THREADED_TEST(ExternalShortArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000013104 ExternalArrayTestHelper<i::ExternalShortArray, int16_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000013105 v8::kExternalShortArray,
13106 -32768,
13107 32767);
13108}
13109
13110
13111THREADED_TEST(ExternalUnsignedShortArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000013112 ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000013113 v8::kExternalUnsignedShortArray,
13114 0,
13115 65535);
13116}
13117
13118
13119THREADED_TEST(ExternalIntArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000013120 ExternalArrayTestHelper<i::ExternalIntArray, int32_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000013121 v8::kExternalIntArray,
13122 INT_MIN, // -2147483648
13123 INT_MAX); // 2147483647
13124}
13125
13126
13127THREADED_TEST(ExternalUnsignedIntArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000013128 ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000013129 v8::kExternalUnsignedIntArray,
13130 0,
13131 UINT_MAX); // 4294967295
13132}
13133
13134
13135THREADED_TEST(ExternalFloatArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000013136 ExternalArrayTestHelper<i::ExternalFloatArray, float>(
ager@chromium.org3811b432009-10-28 14:53:37 +000013137 v8::kExternalFloatArray,
13138 -500,
13139 500);
13140}
13141
13142
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000013143THREADED_TEST(ExternalDoubleArray) {
13144 ExternalArrayTestHelper<i::ExternalDoubleArray, double>(
13145 v8::kExternalDoubleArray,
13146 -500,
13147 500);
13148}
13149
13150
ager@chromium.org3811b432009-10-28 14:53:37 +000013151THREADED_TEST(ExternalArrays) {
13152 TestExternalByteArray();
13153 TestExternalUnsignedByteArray();
13154 TestExternalShortArray();
13155 TestExternalUnsignedShortArray();
13156 TestExternalIntArray();
13157 TestExternalUnsignedIntArray();
13158 TestExternalFloatArray();
13159}
13160
13161
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000013162void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
13163 v8::HandleScope scope;
13164 LocalContext context;
13165 for (int size = 0; size < 100; size += 10) {
13166 int element_size = ExternalArrayElementSize(array_type);
13167 void* external_data = malloc(size * element_size);
13168 v8::Handle<v8::Object> obj = v8::Object::New();
13169 obj->SetIndexedPropertiesToExternalArrayData(
13170 external_data, array_type, size);
13171 CHECK(obj->HasIndexedPropertiesInExternalArrayData());
13172 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
13173 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
13174 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
13175 free(external_data);
13176 }
13177}
13178
13179
13180THREADED_TEST(ExternalArrayInfo) {
13181 ExternalArrayInfoTestHelper(v8::kExternalByteArray);
13182 ExternalArrayInfoTestHelper(v8::kExternalUnsignedByteArray);
13183 ExternalArrayInfoTestHelper(v8::kExternalShortArray);
13184 ExternalArrayInfoTestHelper(v8::kExternalUnsignedShortArray);
13185 ExternalArrayInfoTestHelper(v8::kExternalIntArray);
13186 ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray);
13187 ExternalArrayInfoTestHelper(v8::kExternalFloatArray);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000013188 ExternalArrayInfoTestHelper(v8::kExternalDoubleArray);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000013189 ExternalArrayInfoTestHelper(v8::kExternalPixelArray);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000013190}
13191
13192
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000013193THREADED_TEST(ScriptContextDependence) {
13194 v8::HandleScope scope;
13195 LocalContext c1;
13196 const char *source = "foo";
13197 v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
13198 v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
13199 c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
13200 CHECK_EQ(dep->Run()->Int32Value(), 100);
13201 CHECK_EQ(indep->Run()->Int32Value(), 100);
13202 LocalContext c2;
13203 c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
13204 CHECK_EQ(dep->Run()->Int32Value(), 100);
13205 CHECK_EQ(indep->Run()->Int32Value(), 101);
13206}
13207
ager@chromium.org96c75b52009-08-26 09:13:16 +000013208
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000013209THREADED_TEST(StackTrace) {
13210 v8::HandleScope scope;
13211 LocalContext context;
13212 v8::TryCatch try_catch;
13213 const char *source = "function foo() { FAIL.FAIL; }; foo();";
13214 v8::Handle<v8::String> src = v8::String::New(source);
13215 v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
13216 v8::Script::New(src, origin)->Run();
13217 CHECK(try_catch.HasCaught());
13218 v8::String::Utf8Value stack(try_catch.StackTrace());
13219 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
13220}
ager@chromium.org96c75b52009-08-26 09:13:16 +000013221
13222
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013223// Checks that a StackFrame has certain expected values.
13224void checkStackFrame(const char* expected_script_name,
13225 const char* expected_func_name, int expected_line_number,
13226 int expected_column, bool is_eval, bool is_constructor,
13227 v8::Handle<v8::StackFrame> frame) {
13228 v8::HandleScope scope;
13229 v8::String::Utf8Value func_name(frame->GetFunctionName());
13230 v8::String::Utf8Value script_name(frame->GetScriptName());
13231 if (*script_name == NULL) {
13232 // The situation where there is no associated script, like for evals.
13233 CHECK(expected_script_name == NULL);
13234 } else {
13235 CHECK(strstr(*script_name, expected_script_name) != NULL);
13236 }
13237 CHECK(strstr(*func_name, expected_func_name) != NULL);
13238 CHECK_EQ(expected_line_number, frame->GetLineNumber());
13239 CHECK_EQ(expected_column, frame->GetColumn());
13240 CHECK_EQ(is_eval, frame->IsEval());
13241 CHECK_EQ(is_constructor, frame->IsConstructor());
13242}
13243
13244
13245v8::Handle<Value> AnalyzeStackInNativeCode(const v8::Arguments& args) {
13246 v8::HandleScope scope;
13247 const char* origin = "capture-stack-trace-test";
13248 const int kOverviewTest = 1;
13249 const int kDetailedTest = 2;
13250
13251 ASSERT(args.Length() == 1);
13252
13253 int testGroup = args[0]->Int32Value();
13254 if (testGroup == kOverviewTest) {
13255 v8::Handle<v8::StackTrace> stackTrace =
13256 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
13257 CHECK_EQ(4, stackTrace->GetFrameCount());
13258 checkStackFrame(origin, "bar", 2, 10, false, false,
13259 stackTrace->GetFrame(0));
13260 checkStackFrame(origin, "foo", 6, 3, false, false,
13261 stackTrace->GetFrame(1));
whesse@chromium.org030d38e2011-07-13 13:23:34 +000013262 // This is the source string inside the eval which has the call to foo.
13263 checkStackFrame(NULL, "", 1, 5, false, false,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013264 stackTrace->GetFrame(2));
whesse@chromium.org030d38e2011-07-13 13:23:34 +000013265 // The last frame is an anonymous function which has the initial eval call.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013266 checkStackFrame(origin, "", 8, 7, false, false,
13267 stackTrace->GetFrame(3));
13268
13269 CHECK(stackTrace->AsArray()->IsArray());
13270 } else if (testGroup == kDetailedTest) {
13271 v8::Handle<v8::StackTrace> stackTrace =
13272 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
13273 CHECK_EQ(4, stackTrace->GetFrameCount());
13274 checkStackFrame(origin, "bat", 4, 22, false, false,
13275 stackTrace->GetFrame(0));
13276 checkStackFrame(origin, "baz", 8, 3, false, true,
13277 stackTrace->GetFrame(1));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000013278#ifdef ENABLE_DEBUGGER_SUPPORT
13279 bool is_eval = true;
13280#else // ENABLE_DEBUGGER_SUPPORT
13281 bool is_eval = false;
13282#endif // ENABLE_DEBUGGER_SUPPORT
13283
whesse@chromium.org030d38e2011-07-13 13:23:34 +000013284 // This is the source string inside the eval which has the call to baz.
13285 checkStackFrame(NULL, "", 1, 5, is_eval, false,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013286 stackTrace->GetFrame(2));
whesse@chromium.org030d38e2011-07-13 13:23:34 +000013287 // The last frame is an anonymous function which has the initial eval call.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013288 checkStackFrame(origin, "", 10, 1, false, false,
13289 stackTrace->GetFrame(3));
13290
13291 CHECK(stackTrace->AsArray()->IsArray());
13292 }
13293 return v8::Undefined();
13294}
13295
13296
13297// Tests the C++ StackTrace API.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013298// TODO(3074796): Reenable this as a THREADED_TEST once it passes.
13299// THREADED_TEST(CaptureStackTrace) {
13300TEST(CaptureStackTrace) {
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013301 v8::HandleScope scope;
13302 v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
13303 Local<ObjectTemplate> templ = ObjectTemplate::New();
13304 templ->Set(v8_str("AnalyzeStackInNativeCode"),
13305 v8::FunctionTemplate::New(AnalyzeStackInNativeCode));
13306 LocalContext context(0, templ);
13307
13308 // Test getting OVERVIEW information. Should ignore information that is not
13309 // script name, function name, line number, and column offset.
13310 const char *overview_source =
13311 "function bar() {\n"
13312 " var y; AnalyzeStackInNativeCode(1);\n"
13313 "}\n"
13314 "function foo() {\n"
13315 "\n"
13316 " bar();\n"
13317 "}\n"
13318 "var x;eval('new foo();');";
13319 v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000013320 v8::Handle<Value> overview_result(
13321 v8::Script::New(overview_src, origin)->Run());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013322 ASSERT(!overview_result.IsEmpty());
13323 ASSERT(overview_result->IsObject());
13324
13325 // Test getting DETAILED information.
13326 const char *detailed_source =
13327 "function bat() {AnalyzeStackInNativeCode(2);\n"
13328 "}\n"
13329 "\n"
13330 "function baz() {\n"
13331 " bat();\n"
13332 "}\n"
13333 "eval('new baz();');";
13334 v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
13335 // Make the script using a non-zero line and column offset.
13336 v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
13337 v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
13338 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
13339 v8::Handle<v8::Script> detailed_script(
13340 v8::Script::New(detailed_src, &detailed_origin));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000013341 v8::Handle<Value> detailed_result(detailed_script->Run());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013342 ASSERT(!detailed_result.IsEmpty());
13343 ASSERT(detailed_result->IsObject());
13344}
13345
13346
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000013347static void StackTraceForUncaughtExceptionListener(
13348 v8::Handle<v8::Message> message,
13349 v8::Handle<Value>) {
13350 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
13351 CHECK_EQ(2, stack_trace->GetFrameCount());
13352 checkStackFrame("origin", "foo", 2, 3, false, false,
13353 stack_trace->GetFrame(0));
13354 checkStackFrame("origin", "bar", 5, 3, false, false,
13355 stack_trace->GetFrame(1));
13356}
13357
13358TEST(CaptureStackTraceForUncaughtException) {
13359 report_count = 0;
13360 v8::HandleScope scope;
13361 LocalContext env;
13362 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
13363 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
13364
13365 Script::Compile(v8_str("function foo() {\n"
13366 " throw 1;\n"
13367 "};\n"
13368 "function bar() {\n"
13369 " foo();\n"
13370 "};"),
13371 v8_str("origin"))->Run();
13372 v8::Local<v8::Object> global = env->Global();
13373 Local<Value> trouble = global->Get(v8_str("bar"));
13374 CHECK(trouble->IsFunction());
13375 Function::Cast(*trouble)->Call(global, 0, NULL);
13376 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
13377 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
13378}
13379
13380
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000013381TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
13382 v8::HandleScope scope;
13383 LocalContext env;
13384 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
13385 1024,
13386 v8::StackTrace::kDetailed);
13387
13388 CompileRun(
13389 "var setters = ['column', 'lineNumber', 'scriptName',\n"
13390 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
13391 " 'isConstructor'];\n"
13392 "for (var i = 0; i < setters.length; i++) {\n"
13393 " var prop = setters[i];\n"
13394 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
13395 "}\n");
13396 CompileRun("throw 'exception';");
13397 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
13398}
13399
13400
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000013401v8::Handle<Value> AnalyzeStackOfEvalWithSourceURL(const v8::Arguments& args) {
13402 v8::HandleScope scope;
13403 v8::Handle<v8::StackTrace> stackTrace =
13404 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
13405 CHECK_EQ(5, stackTrace->GetFrameCount());
13406 v8::Handle<v8::String> url = v8_str("eval_url");
13407 for (int i = 0; i < 3; i++) {
13408 v8::Handle<v8::String> name =
13409 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
13410 CHECK(!name.IsEmpty());
13411 CHECK_EQ(url, name);
13412 }
13413 return v8::Undefined();
13414}
13415
13416
13417TEST(SourceURLInStackTrace) {
13418 v8::HandleScope scope;
13419 Local<ObjectTemplate> templ = ObjectTemplate::New();
13420 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
13421 v8::FunctionTemplate::New(AnalyzeStackOfEvalWithSourceURL));
13422 LocalContext context(0, templ);
13423
13424 const char *source =
13425 "function outer() {\n"
13426 "function bar() {\n"
13427 " AnalyzeStackOfEvalWithSourceURL();\n"
13428 "}\n"
13429 "function foo() {\n"
13430 "\n"
13431 " bar();\n"
13432 "}\n"
13433 "foo();\n"
13434 "}\n"
13435 "eval('(' + outer +')()//@ sourceURL=eval_url');";
13436 CHECK(CompileRun(source)->IsUndefined());
13437}
13438
13439
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000013440// Test that idle notification can be handled and eventually returns true.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000013441// This just checks the contract of the IdleNotification() function,
13442// and does not verify that it does reasonable work.
ager@chromium.org96c75b52009-08-26 09:13:16 +000013443THREADED_TEST(IdleNotification) {
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +000013444 v8::HandleScope scope;
13445 LocalContext env;
13446 CompileRun("function binom(n, m) {"
13447 " var C = [[1]];"
13448 " for (var i = 1; i <= n; ++i) {"
13449 " C[i] = [1];"
13450 " for (var j = 1; j < i; ++j) {"
13451 " C[i][j] = C[i-1][j-1] + C[i-1][j];"
13452 " }"
13453 " C[i][i] = 1;"
13454 " }"
13455 " return C[n][m];"
13456 "};"
13457 "binom(1000, 500)");
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000013458 bool rv = false;
13459 for (int i = 0; i < 100; i++) {
13460 rv = v8::V8::IdleNotification();
13461 if (rv)
13462 break;
13463 }
13464 CHECK(rv == true);
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +000013465}
13466
13467// Test that idle notification can be handled and eventually returns true.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000013468// This just checks the contract of the IdleNotification() function,
13469// and does not verify that it does reasonable work.
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +000013470THREADED_TEST(IdleNotificationWithHint) {
13471 v8::HandleScope scope;
13472 LocalContext env;
13473 CompileRun("function binom(n, m) {"
13474 " var C = [[1]];"
13475 " for (var i = 1; i <= n; ++i) {"
13476 " C[i] = [1];"
13477 " for (var j = 1; j < i; ++j) {"
13478 " C[i][j] = C[i-1][j-1] + C[i-1][j];"
13479 " }"
13480 " C[i][i] = 1;"
13481 " }"
13482 " return C[n][m];"
13483 "};"
13484 "binom(1000, 500)");
13485 bool rv = false;
13486 intptr_t old_size = HEAP->SizeOfObjects();
13487 bool no_idle_work = v8::V8::IdleNotification(10);
13488 for (int i = 0; i < 200; i++) {
13489 rv = v8::V8::IdleNotification(10);
13490 if (rv)
13491 break;
13492 }
13493 CHECK(rv == true);
13494 intptr_t new_size = HEAP->SizeOfObjects();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000013495 CHECK(no_idle_work || new_size < old_size);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000013496}
13497
13498
13499static uint32_t* stack_limit;
13500
13501static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013502 stack_limit = reinterpret_cast<uint32_t*>(
13503 i::Isolate::Current()->stack_guard()->real_climit());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000013504 return v8::Undefined();
13505}
13506
13507
13508// Uses the address of a local variable to determine the stack top now.
13509// Given a size, returns an address that is that far from the current
13510// top of stack.
13511static uint32_t* ComputeStackLimit(uint32_t size) {
13512 uint32_t* answer = &size - (size / sizeof(size));
13513 // If the size is very large and the stack is very near the bottom of
13514 // memory then the calculation above may wrap around and give an address
13515 // that is above the (downwards-growing) stack. In that case we return
13516 // a very low address.
13517 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
13518 return answer;
13519}
13520
13521
13522TEST(SetResourceConstraints) {
13523 static const int K = 1024;
13524 uint32_t* set_limit = ComputeStackLimit(128 * K);
13525
13526 // Set stack limit.
13527 v8::ResourceConstraints constraints;
13528 constraints.set_stack_limit(set_limit);
13529 CHECK(v8::SetResourceConstraints(&constraints));
13530
13531 // Execute a script.
13532 v8::HandleScope scope;
13533 LocalContext env;
13534 Local<v8::FunctionTemplate> fun_templ =
13535 v8::FunctionTemplate::New(GetStackLimitCallback);
13536 Local<Function> fun = fun_templ->GetFunction();
13537 env->Global()->Set(v8_str("get_stack_limit"), fun);
13538 CompileRun("get_stack_limit();");
13539
13540 CHECK(stack_limit == set_limit);
13541}
13542
13543
13544TEST(SetResourceConstraintsInThread) {
13545 uint32_t* set_limit;
13546 {
13547 v8::Locker locker;
13548 static const int K = 1024;
13549 set_limit = ComputeStackLimit(128 * K);
13550
13551 // Set stack limit.
13552 v8::ResourceConstraints constraints;
13553 constraints.set_stack_limit(set_limit);
13554 CHECK(v8::SetResourceConstraints(&constraints));
13555
13556 // Execute a script.
13557 v8::HandleScope scope;
13558 LocalContext env;
13559 Local<v8::FunctionTemplate> fun_templ =
13560 v8::FunctionTemplate::New(GetStackLimitCallback);
13561 Local<Function> fun = fun_templ->GetFunction();
13562 env->Global()->Set(v8_str("get_stack_limit"), fun);
13563 CompileRun("get_stack_limit();");
13564
13565 CHECK(stack_limit == set_limit);
13566 }
13567 {
13568 v8::Locker locker;
13569 CHECK(stack_limit == set_limit);
13570 }
ager@chromium.org96c75b52009-08-26 09:13:16 +000013571}
ager@chromium.org3811b432009-10-28 14:53:37 +000013572
13573
13574THREADED_TEST(GetHeapStatistics) {
13575 v8::HandleScope scope;
13576 LocalContext c1;
13577 v8::HeapStatistics heap_statistics;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000013578 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
13579 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
ager@chromium.org3811b432009-10-28 14:53:37 +000013580 v8::V8::GetHeapStatistics(&heap_statistics);
ager@chromium.orgc4c92722009-11-18 14:12:51 +000013581 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
13582 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
ager@chromium.org3811b432009-10-28 14:53:37 +000013583}
13584
13585
13586static double DoubleFromBits(uint64_t value) {
13587 double target;
ager@chromium.org3811b432009-10-28 14:53:37 +000013588 memcpy(&target, &value, sizeof(target));
ager@chromium.org3811b432009-10-28 14:53:37 +000013589 return target;
13590}
13591
13592
13593static uint64_t DoubleToBits(double value) {
13594 uint64_t target;
ager@chromium.org3811b432009-10-28 14:53:37 +000013595 memcpy(&target, &value, sizeof(target));
ager@chromium.org3811b432009-10-28 14:53:37 +000013596 return target;
13597}
13598
13599
13600static double DoubleToDateTime(double input) {
13601 double date_limit = 864e13;
13602 if (IsNaN(input) || input < -date_limit || input > date_limit) {
13603 return i::OS::nan_value();
13604 }
13605 return (input < 0) ? -(floor(-input)) : floor(input);
13606}
13607
13608// We don't have a consistent way to write 64-bit constants syntactically, so we
13609// split them into two 32-bit constants and combine them programmatically.
13610static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
13611 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
13612}
13613
13614
13615THREADED_TEST(QuietSignalingNaNs) {
13616 v8::HandleScope scope;
13617 LocalContext context;
13618 v8::TryCatch try_catch;
13619
13620 // Special double values.
13621 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
13622 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
13623 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
13624 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
13625 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
13626 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
13627 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
13628
13629 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
13630 // on either side of the epoch.
13631 double date_limit = 864e13;
13632
13633 double test_values[] = {
13634 snan,
13635 qnan,
13636 infinity,
13637 max_normal,
13638 date_limit + 1,
13639 date_limit,
13640 min_normal,
13641 max_denormal,
13642 min_denormal,
13643 0,
13644 -0,
13645 -min_denormal,
13646 -max_denormal,
13647 -min_normal,
13648 -date_limit,
13649 -date_limit - 1,
13650 -max_normal,
13651 -infinity,
13652 -qnan,
13653 -snan
13654 };
13655 int num_test_values = 20;
13656
13657 for (int i = 0; i < num_test_values; i++) {
13658 double test_value = test_values[i];
13659
13660 // Check that Number::New preserves non-NaNs and quiets SNaNs.
13661 v8::Handle<v8::Value> number = v8::Number::New(test_value);
13662 double stored_number = number->NumberValue();
13663 if (!IsNaN(test_value)) {
13664 CHECK_EQ(test_value, stored_number);
13665 } else {
13666 uint64_t stored_bits = DoubleToBits(stored_number);
13667 // Check if quiet nan (bits 51..62 all set).
danno@chromium.orgc612e022011-11-10 11:38:15 +000013668#if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
13669 // Most significant fraction bit for quiet nan is set to 0
13670 // on MIPS architecture. Allowed by IEEE-754.
13671 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
13672#else
ager@chromium.org3811b432009-10-28 14:53:37 +000013673 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
danno@chromium.orgc612e022011-11-10 11:38:15 +000013674#endif
ager@chromium.org3811b432009-10-28 14:53:37 +000013675 }
13676
13677 // Check that Date::New preserves non-NaNs in the date range and
13678 // quiets SNaNs.
13679 v8::Handle<v8::Value> date = v8::Date::New(test_value);
13680 double expected_stored_date = DoubleToDateTime(test_value);
13681 double stored_date = date->NumberValue();
13682 if (!IsNaN(expected_stored_date)) {
13683 CHECK_EQ(expected_stored_date, stored_date);
13684 } else {
13685 uint64_t stored_bits = DoubleToBits(stored_date);
13686 // Check if quiet nan (bits 51..62 all set).
danno@chromium.orgc612e022011-11-10 11:38:15 +000013687#if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
13688 // Most significant fraction bit for quiet nan is set to 0
13689 // on MIPS architecture. Allowed by IEEE-754.
13690 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
13691#else
ager@chromium.org3811b432009-10-28 14:53:37 +000013692 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
danno@chromium.orgc612e022011-11-10 11:38:15 +000013693#endif
ager@chromium.org3811b432009-10-28 14:53:37 +000013694 }
13695 }
13696}
christian.plesner.hansen@gmail.comb9ce6372009-11-03 11:38:18 +000013697
13698
13699static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
13700 v8::HandleScope scope;
13701 v8::TryCatch tc;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000013702 v8::Handle<v8::String> str(args[0]->ToString());
christian.plesner.hansen@gmail.comb9ce6372009-11-03 11:38:18 +000013703 if (tc.HasCaught())
13704 return tc.ReThrow();
13705 return v8::Undefined();
13706}
13707
13708
13709// Test that an exception can be propagated down through a spaghetti
13710// stack using ReThrow.
13711THREADED_TEST(SpaghettiStackReThrow) {
13712 v8::HandleScope scope;
13713 LocalContext context;
13714 context->Global()->Set(
13715 v8::String::New("s"),
13716 v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
13717 v8::TryCatch try_catch;
13718 CompileRun(
13719 "var i = 0;"
13720 "var o = {"
13721 " toString: function () {"
13722 " if (i == 10) {"
13723 " throw 'Hey!';"
13724 " } else {"
13725 " i++;"
13726 " return s(o);"
13727 " }"
13728 " }"
13729 "};"
13730 "s(o);");
13731 CHECK(try_catch.HasCaught());
13732 v8::String::Utf8Value value(try_catch.Exception());
13733 CHECK_EQ(0, strcmp(*value, "Hey!"));
13734}
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013735
13736
sgjesse@chromium.org98180592009-12-02 08:17:28 +000013737TEST(Regress528) {
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013738 v8::V8::Initialize();
13739
13740 v8::HandleScope scope;
13741 v8::Persistent<Context> context;
ager@chromium.org60121232009-12-03 11:25:37 +000013742 v8::Persistent<Context> other_context;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013743 int gc_count;
13744
ager@chromium.org60121232009-12-03 11:25:37 +000013745 // Create a context used to keep the code from aging in the compilation
13746 // cache.
13747 other_context = Context::New();
13748
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013749 // Context-dependent context data creates reference from the compilation
13750 // cache to the global object.
ager@chromium.org60121232009-12-03 11:25:37 +000013751 const char* source_simple = "1";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013752 context = Context::New();
13753 {
13754 v8::HandleScope scope;
13755
13756 context->Enter();
13757 Local<v8::String> obj = v8::String::New("");
13758 context->SetData(obj);
ager@chromium.org60121232009-12-03 11:25:37 +000013759 CompileRun(source_simple);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013760 context->Exit();
13761 }
13762 context.Dispose();
13763 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000013764 other_context->Enter();
13765 CompileRun(source_simple);
13766 other_context->Exit();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013767 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org60121232009-12-03 11:25:37 +000013768 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013769 }
ager@chromium.org60121232009-12-03 11:25:37 +000013770 CHECK_GE(2, gc_count);
13771 CHECK_EQ(1, GetGlobalObjectsCount());
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013772
13773 // Eval in a function creates reference from the compilation cache to the
13774 // global object.
ager@chromium.org60121232009-12-03 11:25:37 +000013775 const char* source_eval = "function f(){eval('1')}; f()";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013776 context = Context::New();
13777 {
13778 v8::HandleScope scope;
13779
13780 context->Enter();
ager@chromium.org60121232009-12-03 11:25:37 +000013781 CompileRun(source_eval);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013782 context->Exit();
13783 }
13784 context.Dispose();
13785 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000013786 other_context->Enter();
13787 CompileRun(source_eval);
13788 other_context->Exit();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013789 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org60121232009-12-03 11:25:37 +000013790 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013791 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013792 CHECK_GE(2, gc_count);
sgjesse@chromium.org98180592009-12-02 08:17:28 +000013793 CHECK_EQ(1, GetGlobalObjectsCount());
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013794
13795 // Looking up the line number for an exception creates reference from the
13796 // compilation cache to the global object.
ager@chromium.org60121232009-12-03 11:25:37 +000013797 const char* source_exception = "function f(){throw 1;} f()";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013798 context = Context::New();
13799 {
13800 v8::HandleScope scope;
13801
13802 context->Enter();
13803 v8::TryCatch try_catch;
ager@chromium.org60121232009-12-03 11:25:37 +000013804 CompileRun(source_exception);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013805 CHECK(try_catch.HasCaught());
13806 v8::Handle<v8::Message> message = try_catch.Message();
13807 CHECK(!message.IsEmpty());
13808 CHECK_EQ(1, message->GetLineNumber());
13809 context->Exit();
13810 }
13811 context.Dispose();
13812 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000013813 other_context->Enter();
13814 CompileRun(source_exception);
13815 other_context->Exit();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013816 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org60121232009-12-03 11:25:37 +000013817 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013818 }
ager@chromium.org60121232009-12-03 11:25:37 +000013819 CHECK_GE(2, gc_count);
13820 CHECK_EQ(1, GetGlobalObjectsCount());
13821
13822 other_context.Dispose();
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013823}
ager@chromium.org5c838252010-02-19 08:53:10 +000013824
13825
13826THREADED_TEST(ScriptOrigin) {
13827 v8::HandleScope scope;
13828 LocalContext env;
13829 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
13830 v8::Handle<v8::String> script = v8::String::New(
13831 "function f() {}\n\nfunction g() {}");
13832 v8::Script::Compile(script, &origin)->Run();
13833 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
13834 env->Global()->Get(v8::String::New("f")));
13835 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
13836 env->Global()->Get(v8::String::New("g")));
13837
13838 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
13839 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
13840 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
13841
13842 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
13843 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
13844 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
13845}
13846
13847
13848THREADED_TEST(ScriptLineNumber) {
13849 v8::HandleScope scope;
13850 LocalContext env;
13851 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
13852 v8::Handle<v8::String> script = v8::String::New(
13853 "function f() {}\n\nfunction g() {}");
13854 v8::Script::Compile(script, &origin)->Run();
13855 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
13856 env->Global()->Get(v8::String::New("f")));
13857 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
13858 env->Global()->Get(v8::String::New("g")));
13859 CHECK_EQ(0, f->GetScriptLineNumber());
13860 CHECK_EQ(2, g->GetScriptLineNumber());
13861}
13862
13863
danno@chromium.orgc612e022011-11-10 11:38:15 +000013864THREADED_TEST(ScriptColumnNumber) {
13865 v8::HandleScope scope;
13866 LocalContext env;
13867 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"),
13868 v8::Integer::New(3), v8::Integer::New(2));
13869 v8::Handle<v8::String> script = v8::String::New(
13870 "function foo() {}\n\n function bar() {}");
13871 v8::Script::Compile(script, &origin)->Run();
13872 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
13873 env->Global()->Get(v8::String::New("foo")));
13874 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
13875 env->Global()->Get(v8::String::New("bar")));
13876 CHECK_EQ(14, foo->GetScriptColumnNumber());
13877 CHECK_EQ(17, bar->GetScriptColumnNumber());
13878}
13879
13880
13881THREADED_TEST(FunctionGetScriptId) {
13882 v8::HandleScope scope;
13883 LocalContext env;
13884 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"),
13885 v8::Integer::New(3), v8::Integer::New(2));
13886 v8::Handle<v8::String> scriptSource = v8::String::New(
13887 "function foo() {}\n\n function bar() {}");
13888 v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
13889 script->Run();
13890 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
13891 env->Global()->Get(v8::String::New("foo")));
13892 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
13893 env->Global()->Get(v8::String::New("bar")));
13894 CHECK_EQ(script->Id(), foo->GetScriptId());
13895 CHECK_EQ(script->Id(), bar->GetScriptId());
13896}
13897
13898
ager@chromium.org5c838252010-02-19 08:53:10 +000013899static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
13900 const AccessorInfo& info) {
13901 return v8_num(42);
13902}
13903
13904
13905static void SetterWhichSetsYOnThisTo23(Local<String> name,
13906 Local<Value> value,
13907 const AccessorInfo& info) {
13908 info.This()->Set(v8_str("y"), v8_num(23));
13909}
13910
13911
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013912TEST(SetterOnConstructorPrototype) {
ager@chromium.org5c838252010-02-19 08:53:10 +000013913 v8::HandleScope scope;
13914 Local<ObjectTemplate> templ = ObjectTemplate::New();
13915 templ->SetAccessor(v8_str("x"),
13916 GetterWhichReturns42,
13917 SetterWhichSetsYOnThisTo23);
13918 LocalContext context;
13919 context->Global()->Set(v8_str("P"), templ->NewInstance());
13920 CompileRun("function C1() {"
13921 " this.x = 23;"
13922 "};"
13923 "C1.prototype = P;"
13924 "function C2() {"
13925 " this.x = 23"
13926 "};"
13927 "C2.prototype = { };"
13928 "C2.prototype.__proto__ = P;");
13929
13930 v8::Local<v8::Script> script;
13931 script = v8::Script::Compile(v8_str("new C1();"));
13932 for (int i = 0; i < 10; i++) {
13933 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13934 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
13935 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
13936 }
13937
13938 script = v8::Script::Compile(v8_str("new C2();"));
13939 for (int i = 0; i < 10; i++) {
13940 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
13941 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
13942 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
13943 }
13944}
13945
13946
13947static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
13948 Local<String> name, const AccessorInfo& info) {
13949 return v8_num(42);
13950}
13951
13952
13953static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
13954 Local<String> name, Local<Value> value, const AccessorInfo& info) {
13955 if (name->Equals(v8_str("x"))) {
13956 info.This()->Set(v8_str("y"), v8_num(23));
13957 }
13958 return v8::Handle<Value>();
13959}
13960
13961
13962THREADED_TEST(InterceptorOnConstructorPrototype) {
13963 v8::HandleScope scope;
13964 Local<ObjectTemplate> templ = ObjectTemplate::New();
13965 templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
13966 NamedPropertySetterWhichSetsYOnThisTo23);
13967 LocalContext context;
13968 context->Global()->Set(v8_str("P"), templ->NewInstance());
13969 CompileRun("function C1() {"
13970 " this.x = 23;"
13971 "};"
13972 "C1.prototype = P;"
13973 "function C2() {"
13974 " this.x = 23"
13975 "};"
13976 "C2.prototype = { };"
13977 "C2.prototype.__proto__ = P;");
13978
13979 v8::Local<v8::Script> script;
13980 script = v8::Script::Compile(v8_str("new C1();"));
13981 for (int i = 0; i < 10; i++) {
13982 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13983 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
13984 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
13985 }
13986
13987 script = v8::Script::Compile(v8_str("new C2();"));
13988 for (int i = 0; i < 10; i++) {
13989 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
13990 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
13991 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
13992 }
13993}
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013994
13995
13996TEST(Bug618) {
13997 const char* source = "function C1() {"
13998 " this.x = 23;"
13999 "};"
14000 "C1.prototype = P;";
14001
14002 v8::HandleScope scope;
14003 LocalContext context;
14004 v8::Local<v8::Script> script;
14005
14006 // Use a simple object as prototype.
14007 v8::Local<v8::Object> prototype = v8::Object::New();
14008 prototype->Set(v8_str("y"), v8_num(42));
14009 context->Global()->Set(v8_str("P"), prototype);
14010
14011 // This compile will add the code to the compilation cache.
14012 CompileRun(source);
14013
14014 script = v8::Script::Compile(v8_str("new C1();"));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000014015 // Allow enough iterations for the inobject slack tracking logic
14016 // to finalize instance size and install the fast construct stub.
14017 for (int i = 0; i < 256; i++) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000014018 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
14019 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
14020 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
14021 }
14022
14023 // Use an API object with accessors as prototype.
14024 Local<ObjectTemplate> templ = ObjectTemplate::New();
14025 templ->SetAccessor(v8_str("x"),
14026 GetterWhichReturns42,
14027 SetterWhichSetsYOnThisTo23);
14028 context->Global()->Set(v8_str("P"), templ->NewInstance());
14029
14030 // This compile will get the code from the compilation cache.
14031 CompileRun(source);
14032
14033 script = v8::Script::Compile(v8_str("new C1();"));
14034 for (int i = 0; i < 10; i++) {
14035 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
14036 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
14037 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
14038 }
14039}
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000014040
14041int prologue_call_count = 0;
14042int epilogue_call_count = 0;
14043int prologue_call_count_second = 0;
14044int epilogue_call_count_second = 0;
14045
14046void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
14047 ++prologue_call_count;
14048}
14049
14050void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
14051 ++epilogue_call_count;
14052}
14053
14054void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
14055 ++prologue_call_count_second;
14056}
14057
14058void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
14059 ++epilogue_call_count_second;
14060}
14061
14062TEST(GCCallbacks) {
14063 LocalContext context;
14064
14065 v8::V8::AddGCPrologueCallback(PrologueCallback);
14066 v8::V8::AddGCEpilogueCallback(EpilogueCallback);
14067 CHECK_EQ(0, prologue_call_count);
14068 CHECK_EQ(0, epilogue_call_count);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000014069 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000014070 CHECK_EQ(1, prologue_call_count);
14071 CHECK_EQ(1, epilogue_call_count);
14072 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
14073 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000014074 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000014075 CHECK_EQ(2, prologue_call_count);
14076 CHECK_EQ(2, epilogue_call_count);
14077 CHECK_EQ(1, prologue_call_count_second);
14078 CHECK_EQ(1, epilogue_call_count_second);
14079 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
14080 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000014081 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000014082 CHECK_EQ(2, prologue_call_count);
14083 CHECK_EQ(2, epilogue_call_count);
14084 CHECK_EQ(2, prologue_call_count_second);
14085 CHECK_EQ(2, epilogue_call_count_second);
14086 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
14087 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000014088 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000014089 CHECK_EQ(2, prologue_call_count);
14090 CHECK_EQ(2, epilogue_call_count);
14091 CHECK_EQ(2, prologue_call_count_second);
14092 CHECK_EQ(2, epilogue_call_count_second);
14093}
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014094
14095
14096THREADED_TEST(AddToJSFunctionResultCache) {
14097 i::FLAG_allow_natives_syntax = true;
14098 v8::HandleScope scope;
14099
14100 LocalContext context;
14101
14102 const char* code =
14103 "(function() {"
14104 " var key0 = 'a';"
14105 " var key1 = 'b';"
14106 " var r0 = %_GetFromCache(0, key0);"
14107 " var r1 = %_GetFromCache(0, key1);"
14108 " var r0_ = %_GetFromCache(0, key0);"
14109 " if (r0 !== r0_)"
14110 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
14111 " var r1_ = %_GetFromCache(0, key1);"
14112 " if (r1 !== r1_)"
14113 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
14114 " return 'PASSED';"
14115 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014116 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014117 ExpectString(code, "PASSED");
14118}
14119
14120
14121static const int k0CacheSize = 16;
14122
14123THREADED_TEST(FillJSFunctionResultCache) {
14124 i::FLAG_allow_natives_syntax = true;
14125 v8::HandleScope scope;
14126
14127 LocalContext context;
14128
14129 const char* code =
14130 "(function() {"
14131 " var k = 'a';"
14132 " var r = %_GetFromCache(0, k);"
14133 " for (var i = 0; i < 16; i++) {"
14134 " %_GetFromCache(0, 'a' + i);"
14135 " };"
14136 " if (r === %_GetFromCache(0, k))"
14137 " return 'FAILED: k0CacheSize is too small';"
14138 " return 'PASSED';"
14139 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014140 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014141 ExpectString(code, "PASSED");
14142}
14143
14144
14145THREADED_TEST(RoundRobinGetFromCache) {
14146 i::FLAG_allow_natives_syntax = true;
14147 v8::HandleScope scope;
14148
14149 LocalContext context;
14150
14151 const char* code =
14152 "(function() {"
14153 " var keys = [];"
14154 " for (var i = 0; i < 16; i++) keys.push(i);"
14155 " var values = [];"
14156 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
14157 " for (var i = 0; i < 16; i++) {"
14158 " var v = %_GetFromCache(0, keys[i]);"
14159 " if (v !== values[i])"
14160 " return 'Wrong value for ' + "
14161 " keys[i] + ': ' + v + ' vs. ' + values[i];"
14162 " };"
14163 " return 'PASSED';"
14164 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014165 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014166 ExpectString(code, "PASSED");
14167}
14168
14169
14170THREADED_TEST(ReverseGetFromCache) {
14171 i::FLAG_allow_natives_syntax = true;
14172 v8::HandleScope scope;
14173
14174 LocalContext context;
14175
14176 const char* code =
14177 "(function() {"
14178 " var keys = [];"
14179 " for (var i = 0; i < 16; i++) keys.push(i);"
14180 " var values = [];"
14181 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
14182 " for (var i = 15; i >= 16; i--) {"
14183 " var v = %_GetFromCache(0, keys[i]);"
14184 " if (v !== values[i])"
14185 " return 'Wrong value for ' + "
14186 " keys[i] + ': ' + v + ' vs. ' + values[i];"
14187 " };"
14188 " return 'PASSED';"
14189 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014190 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014191 ExpectString(code, "PASSED");
14192}
14193
14194
14195THREADED_TEST(TestEviction) {
14196 i::FLAG_allow_natives_syntax = true;
14197 v8::HandleScope scope;
14198
14199 LocalContext context;
14200
14201 const char* code =
14202 "(function() {"
14203 " for (var i = 0; i < 2*16; i++) {"
14204 " %_GetFromCache(0, 'a' + i);"
14205 " };"
14206 " return 'PASSED';"
14207 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014208 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014209 ExpectString(code, "PASSED");
14210}
lrn@chromium.org32d961d2010-06-30 09:09:34 +000014211
14212
14213THREADED_TEST(TwoByteStringInAsciiCons) {
14214 // See Chromium issue 47824.
14215 v8::HandleScope scope;
14216
14217 LocalContext context;
14218 const char* init_code =
14219 "var str1 = 'abelspendabel';"
14220 "var str2 = str1 + str1 + str1;"
14221 "str2;";
14222 Local<Value> result = CompileRun(init_code);
14223
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000014224 Local<Value> indexof = CompileRun("str2.indexOf('els')");
14225 Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
14226
lrn@chromium.org32d961d2010-06-30 09:09:34 +000014227 CHECK(result->IsString());
14228 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
14229 int length = string->length();
14230 CHECK(string->IsAsciiRepresentation());
14231
14232 FlattenString(string);
14233 i::Handle<i::String> flat_string = FlattenGetString(string);
14234
14235 CHECK(string->IsAsciiRepresentation());
14236 CHECK(flat_string->IsAsciiRepresentation());
14237
14238 // Create external resource.
14239 uint16_t* uc16_buffer = new uint16_t[length + 1];
14240
14241 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
14242 uc16_buffer[length] = 0;
14243
14244 TestResource resource(uc16_buffer);
14245
14246 flat_string->MakeExternal(&resource);
14247
14248 CHECK(flat_string->IsTwoByteRepresentation());
14249
14250 // At this point, we should have a Cons string which is flat and ASCII,
14251 // with a first half that is a two-byte string (although it only contains
14252 // ASCII characters). This is a valid sequence of steps, and it can happen
14253 // in real pages.
14254
14255 CHECK(string->IsAsciiRepresentation());
14256 i::ConsString* cons = i::ConsString::cast(*string);
14257 CHECK_EQ(0, cons->second()->length());
14258 CHECK(cons->first()->IsTwoByteRepresentation());
14259
14260 // Check that some string operations work.
14261
14262 // Atom RegExp.
14263 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
14264 CHECK_EQ(6, reresult->Int32Value());
14265
14266 // Nonatom RegExp.
14267 reresult = CompileRun("str2.match(/abe./g).length;");
14268 CHECK_EQ(6, reresult->Int32Value());
14269
14270 reresult = CompileRun("str2.search(/bel/g);");
14271 CHECK_EQ(1, reresult->Int32Value());
14272
14273 reresult = CompileRun("str2.search(/be./g);");
14274 CHECK_EQ(1, reresult->Int32Value());
14275
14276 ExpectTrue("/bel/g.test(str2);");
14277
14278 ExpectTrue("/be./g.test(str2);");
14279
14280 reresult = CompileRun("/bel/g.exec(str2);");
14281 CHECK(!reresult->IsNull());
14282
14283 reresult = CompileRun("/be./g.exec(str2);");
14284 CHECK(!reresult->IsNull());
14285
14286 ExpectString("str2.substring(2, 10);", "elspenda");
14287
14288 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
14289
14290 ExpectString("str2.charAt(2);", "e");
14291
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000014292 ExpectObject("str2.indexOf('els');", indexof);
14293
14294 ExpectObject("str2.lastIndexOf('dab');", lastindexof);
14295
lrn@chromium.org32d961d2010-06-30 09:09:34 +000014296 reresult = CompileRun("str2.charCodeAt(2);");
14297 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
14298}
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000014299
14300
14301// Failed access check callback that performs a GC on each invocation.
14302void FailedAccessCheckCallbackGC(Local<v8::Object> target,
14303 v8::AccessType type,
14304 Local<v8::Value> data) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000014305 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000014306}
14307
14308
14309TEST(GCInFailedAccessCheckCallback) {
14310 // Install a failed access check callback that performs a GC on each
14311 // invocation. Then force the callback to be called from va
14312
14313 v8::V8::Initialize();
14314 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
14315
14316 v8::HandleScope scope;
14317
14318 // Create an ObjectTemplate for global objects and install access
14319 // check callbacks that will block access.
14320 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
14321 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
14322 IndexedGetAccessBlocker,
14323 v8::Handle<v8::Value>(),
14324 false);
14325
14326 // Create a context and set an x property on it's global object.
14327 LocalContext context0(NULL, global_template);
14328 context0->Global()->Set(v8_str("x"), v8_num(42));
14329 v8::Handle<v8::Object> global0 = context0->Global();
14330
14331 // Create a context with a different security token so that the
14332 // failed access check callback will be called on each access.
14333 LocalContext context1(NULL, global_template);
14334 context1->Global()->Set(v8_str("other"), global0);
14335
14336 // Get property with failed access check.
14337 ExpectUndefined("other.x");
14338
14339 // Get element with failed access check.
14340 ExpectUndefined("other[0]");
14341
14342 // Set property with failed access check.
14343 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
14344 CHECK(result->IsObject());
14345
14346 // Set element with failed access check.
14347 result = CompileRun("other[0] = new Object()");
14348 CHECK(result->IsObject());
14349
14350 // Get property attribute with failed access check.
14351 ExpectFalse("\'x\' in other");
14352
14353 // Get property attribute for element with failed access check.
14354 ExpectFalse("0 in other");
14355
14356 // Delete property.
14357 ExpectFalse("delete other.x");
14358
14359 // Delete element.
14360 CHECK_EQ(false, global0->Delete(0));
14361
14362 // DefineAccessor.
14363 CHECK_EQ(false,
14364 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
14365
14366 // Define JavaScript accessor.
14367 ExpectUndefined("Object.prototype.__defineGetter__.call("
14368 " other, \'x\', function() { return 42; })");
14369
14370 // LookupAccessor.
14371 ExpectUndefined("Object.prototype.__lookupGetter__.call("
14372 " other, \'x\')");
14373
14374 // HasLocalElement.
14375 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
14376
14377 CHECK_EQ(false, global0->HasRealIndexedProperty(0));
14378 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
14379 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
14380
14381 // Reset the failed access check callback so it does not influence
14382 // the other tests.
14383 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
14384}
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000014385
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014386TEST(DefaultIsolateGetCurrent) {
14387 CHECK(v8::Isolate::GetCurrent() != NULL);
14388 v8::Isolate* isolate = v8::Isolate::GetCurrent();
14389 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
14390 printf("*** %s\n", "DefaultIsolateGetCurrent success");
14391}
14392
14393TEST(IsolateNewDispose) {
14394 v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
14395 v8::Isolate* isolate = v8::Isolate::New();
14396 CHECK(isolate != NULL);
14397 CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
14398 CHECK(current_isolate != isolate);
14399 CHECK(current_isolate == v8::Isolate::GetCurrent());
14400
14401 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14402 last_location = last_message = NULL;
14403 isolate->Dispose();
14404 CHECK_EQ(last_location, NULL);
14405 CHECK_EQ(last_message, NULL);
14406}
14407
14408TEST(IsolateEnterExitDefault) {
14409 v8::HandleScope scope;
14410 LocalContext context;
14411 v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
14412 CHECK(current_isolate != NULL); // Default isolate.
14413 ExpectString("'hello'", "hello");
14414 current_isolate->Enter();
14415 ExpectString("'still working'", "still working");
14416 current_isolate->Exit();
14417 ExpectString("'still working 2'", "still working 2");
14418 current_isolate->Exit();
14419 // Default isolate is always, well, 'default current'.
14420 CHECK_EQ(v8::Isolate::GetCurrent(), current_isolate);
14421 // Still working since default isolate is auto-entering any thread
14422 // that has no isolate and attempts to execute V8 APIs.
14423 ExpectString("'still working 3'", "still working 3");
14424}
14425
14426TEST(DisposeDefaultIsolate) {
14427 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14428
14429 // Run some V8 code to trigger default isolate to become 'current'.
14430 v8::HandleScope scope;
14431 LocalContext context;
14432 ExpectString("'run some V8'", "run some V8");
14433
14434 v8::Isolate* isolate = v8::Isolate::GetCurrent();
14435 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
14436 last_location = last_message = NULL;
14437 isolate->Dispose();
14438 // It is not possible to dispose default isolate via Isolate API.
14439 CHECK_NE(last_location, NULL);
14440 CHECK_NE(last_message, NULL);
14441}
14442
14443TEST(RunDefaultAndAnotherIsolate) {
14444 v8::HandleScope scope;
14445 LocalContext context;
14446
14447 // Enter new isolate.
14448 v8::Isolate* isolate = v8::Isolate::New();
14449 CHECK(isolate);
14450 isolate->Enter();
14451 { // Need this block because subsequent Exit() will deallocate Heap,
14452 // so we need all scope objects to be deconstructed when it happens.
14453 v8::HandleScope scope_new;
14454 LocalContext context_new;
14455
14456 // Run something in new isolate.
14457 CompileRun("var foo = 153;");
14458 ExpectTrue("function f() { return foo == 153; }; f()");
14459 }
14460 isolate->Exit();
14461
14462 // This runs automatically in default isolate.
14463 // Variables in another isolate should be not available.
14464 ExpectTrue("function f() {"
14465 " try {"
14466 " foo;"
14467 " return false;"
14468 " } catch(e) {"
14469 " return true;"
14470 " }"
14471 "};"
14472 "var bar = 371;"
14473 "f()");
14474
14475 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14476 last_location = last_message = NULL;
14477 isolate->Dispose();
14478 CHECK_EQ(last_location, NULL);
14479 CHECK_EQ(last_message, NULL);
14480
14481 // Check that default isolate still runs.
14482 ExpectTrue("function f() { return bar == 371; }; f()");
14483}
14484
14485TEST(DisposeIsolateWhenInUse) {
14486 v8::Isolate* isolate = v8::Isolate::New();
14487 CHECK(isolate);
14488 isolate->Enter();
14489 v8::HandleScope scope;
14490 LocalContext context;
14491 // Run something in this isolate.
14492 ExpectTrue("true");
14493 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14494 last_location = last_message = NULL;
14495 // Still entered, should fail.
14496 isolate->Dispose();
14497 CHECK_NE(last_location, NULL);
14498 CHECK_NE(last_message, NULL);
14499}
14500
14501TEST(RunTwoIsolatesOnSingleThread) {
14502 // Run isolate 1.
14503 v8::Isolate* isolate1 = v8::Isolate::New();
14504 isolate1->Enter();
14505 v8::Persistent<v8::Context> context1 = v8::Context::New();
14506
14507 {
14508 v8::Context::Scope cscope(context1);
14509 v8::HandleScope scope;
14510 // Run something in new isolate.
14511 CompileRun("var foo = 'isolate 1';");
14512 ExpectString("function f() { return foo; }; f()", "isolate 1");
14513 }
14514
14515 // Run isolate 2.
14516 v8::Isolate* isolate2 = v8::Isolate::New();
14517 v8::Persistent<v8::Context> context2;
14518
14519 {
14520 v8::Isolate::Scope iscope(isolate2);
14521 context2 = v8::Context::New();
14522 v8::Context::Scope cscope(context2);
14523 v8::HandleScope scope;
14524
14525 // Run something in new isolate.
14526 CompileRun("var foo = 'isolate 2';");
14527 ExpectString("function f() { return foo; }; f()", "isolate 2");
14528 }
14529
14530 {
14531 v8::Context::Scope cscope(context1);
14532 v8::HandleScope scope;
14533 // Now again in isolate 1
14534 ExpectString("function f() { return foo; }; f()", "isolate 1");
14535 }
14536
14537 isolate1->Exit();
14538
14539 // Run some stuff in default isolate.
14540 v8::Persistent<v8::Context> context_default = v8::Context::New();
14541
14542 {
14543 v8::Context::Scope cscope(context_default);
14544 v8::HandleScope scope;
14545 // Variables in other isolates should be not available, verify there
14546 // is an exception.
14547 ExpectTrue("function f() {"
14548 " try {"
14549 " foo;"
14550 " return false;"
14551 " } catch(e) {"
14552 " return true;"
14553 " }"
14554 "};"
14555 "var isDefaultIsolate = true;"
14556 "f()");
14557 }
14558
14559 isolate1->Enter();
14560
14561 {
14562 v8::Isolate::Scope iscope(isolate2);
14563 v8::Context::Scope cscope(context2);
14564 v8::HandleScope scope;
14565 ExpectString("function f() { return foo; }; f()", "isolate 2");
14566 }
14567
14568 {
14569 v8::Context::Scope cscope(context1);
14570 v8::HandleScope scope;
14571 ExpectString("function f() { return foo; }; f()", "isolate 1");
14572 }
14573
14574 {
14575 v8::Isolate::Scope iscope(isolate2);
14576 context2.Dispose();
14577 }
14578
14579 context1.Dispose();
14580 isolate1->Exit();
14581
14582 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14583 last_location = last_message = NULL;
14584
14585 isolate1->Dispose();
14586 CHECK_EQ(last_location, NULL);
14587 CHECK_EQ(last_message, NULL);
14588
14589 isolate2->Dispose();
14590 CHECK_EQ(last_location, NULL);
14591 CHECK_EQ(last_message, NULL);
14592
14593 // Check that default isolate still runs.
14594 {
14595 v8::Context::Scope cscope(context_default);
14596 v8::HandleScope scope;
14597 ExpectTrue("function f() { return isDefaultIsolate; }; f()");
14598 }
14599}
14600
14601static int CalcFibonacci(v8::Isolate* isolate, int limit) {
14602 v8::Isolate::Scope isolate_scope(isolate);
14603 v8::HandleScope scope;
14604 LocalContext context;
14605 i::ScopedVector<char> code(1024);
14606 i::OS::SNPrintF(code, "function fib(n) {"
14607 " if (n <= 2) return 1;"
14608 " return fib(n-1) + fib(n-2);"
14609 "}"
14610 "fib(%d)", limit);
14611 Local<Value> value = CompileRun(code.start());
14612 CHECK(value->IsNumber());
14613 return static_cast<int>(value->NumberValue());
14614}
14615
14616class IsolateThread : public v8::internal::Thread {
14617 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000014618 IsolateThread(v8::Isolate* isolate, int fib_limit)
14619 : Thread("IsolateThread"),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014620 isolate_(isolate),
14621 fib_limit_(fib_limit),
14622 result_(0) { }
14623
14624 void Run() {
14625 result_ = CalcFibonacci(isolate_, fib_limit_);
14626 }
14627
14628 int result() { return result_; }
14629
14630 private:
14631 v8::Isolate* isolate_;
14632 int fib_limit_;
14633 int result_;
14634};
14635
14636TEST(MultipleIsolatesOnIndividualThreads) {
14637 v8::Isolate* isolate1 = v8::Isolate::New();
14638 v8::Isolate* isolate2 = v8::Isolate::New();
14639
14640 IsolateThread thread1(isolate1, 21);
14641 IsolateThread thread2(isolate2, 12);
14642
14643 // Compute some fibonacci numbers on 3 threads in 3 isolates.
14644 thread1.Start();
14645 thread2.Start();
14646
14647 int result1 = CalcFibonacci(v8::Isolate::GetCurrent(), 21);
14648 int result2 = CalcFibonacci(v8::Isolate::GetCurrent(), 12);
14649
14650 thread1.Join();
14651 thread2.Join();
14652
14653 // Compare results. The actual fibonacci numbers for 12 and 21 are taken
14654 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
14655 CHECK_EQ(result1, 10946);
14656 CHECK_EQ(result2, 144);
14657 CHECK_EQ(result1, thread1.result());
14658 CHECK_EQ(result2, thread2.result());
14659
14660 isolate1->Dispose();
14661 isolate2->Dispose();
14662}
14663
lrn@chromium.org1c092762011-05-09 09:42:16 +000014664TEST(IsolateDifferentContexts) {
14665 v8::Isolate* isolate = v8::Isolate::New();
14666 Persistent<v8::Context> context;
14667 {
14668 v8::Isolate::Scope isolate_scope(isolate);
14669 v8::HandleScope handle_scope;
14670 context = v8::Context::New();
14671 v8::Context::Scope context_scope(context);
14672 Local<Value> v = CompileRun("2");
14673 CHECK(v->IsNumber());
14674 CHECK_EQ(2, static_cast<int>(v->NumberValue()));
14675 }
14676 {
14677 v8::Isolate::Scope isolate_scope(isolate);
14678 v8::HandleScope handle_scope;
14679 context = v8::Context::New();
14680 v8::Context::Scope context_scope(context);
14681 Local<Value> v = CompileRun("22");
14682 CHECK(v->IsNumber());
14683 CHECK_EQ(22, static_cast<int>(v->NumberValue()));
14684 }
14685}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014686
14687class InitDefaultIsolateThread : public v8::internal::Thread {
14688 public:
sgjesse@chromium.orge0599052011-03-25 07:34:35 +000014689 enum TestCase {
14690 IgnoreOOM,
14691 SetResourceConstraints,
14692 SetFatalHandler,
14693 SetCounterFunction,
14694 SetCreateHistogramFunction,
14695 SetAddHistogramSampleFunction
14696 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014697
14698 explicit InitDefaultIsolateThread(TestCase testCase)
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000014699 : Thread("InitDefaultIsolateThread"),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014700 testCase_(testCase),
14701 result_(false) { }
14702
14703 void Run() {
14704 switch (testCase_) {
14705 case IgnoreOOM:
14706 v8::V8::IgnoreOutOfMemoryException();
14707 break;
14708
14709 case SetResourceConstraints: {
14710 static const int K = 1024;
14711 v8::ResourceConstraints constraints;
14712 constraints.set_max_young_space_size(256 * K);
14713 constraints.set_max_old_space_size(4 * K * K);
14714 v8::SetResourceConstraints(&constraints);
14715 break;
14716 }
14717
14718 case SetFatalHandler:
14719 v8::V8::SetFatalErrorHandler(NULL);
14720 break;
sgjesse@chromium.orge0599052011-03-25 07:34:35 +000014721
14722 case SetCounterFunction:
14723 v8::V8::SetCounterFunction(NULL);
14724 break;
14725
14726 case SetCreateHistogramFunction:
14727 v8::V8::SetCreateHistogramFunction(NULL);
14728 break;
14729
14730 case SetAddHistogramSampleFunction:
14731 v8::V8::SetAddHistogramSampleFunction(NULL);
14732 break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014733 }
14734 result_ = true;
14735 }
14736
14737 bool result() { return result_; }
14738
14739 private:
14740 TestCase testCase_;
14741 bool result_;
14742};
14743
14744
14745static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
14746 InitDefaultIsolateThread thread(testCase);
14747 thread.Start();
14748 thread.Join();
14749 CHECK_EQ(thread.result(), true);
14750}
14751
14752TEST(InitializeDefaultIsolateOnSecondaryThread1) {
14753 InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM);
14754}
14755
14756TEST(InitializeDefaultIsolateOnSecondaryThread2) {
14757 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
14758}
14759
14760TEST(InitializeDefaultIsolateOnSecondaryThread3) {
14761 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
14762}
14763
sgjesse@chromium.orge0599052011-03-25 07:34:35 +000014764TEST(InitializeDefaultIsolateOnSecondaryThread4) {
14765 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
14766}
14767
14768TEST(InitializeDefaultIsolateOnSecondaryThread5) {
14769 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
14770}
14771
14772TEST(InitializeDefaultIsolateOnSecondaryThread6) {
14773 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
14774}
14775
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000014776
14777TEST(StringCheckMultipleContexts) {
14778 const char* code =
14779 "(function() { return \"a\".charAt(0); })()";
14780
14781 {
14782 // Run the code twice in the first context to initialize the call IC.
14783 v8::HandleScope scope;
14784 LocalContext context1;
14785 ExpectString(code, "a");
14786 ExpectString(code, "a");
14787 }
14788
14789 {
14790 // Change the String.prototype in the second context and check
14791 // that the right function gets called.
14792 v8::HandleScope scope;
14793 LocalContext context2;
14794 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
14795 ExpectString(code, "not a");
14796 }
14797}
14798
14799
14800TEST(NumberCheckMultipleContexts) {
14801 const char* code =
14802 "(function() { return (42).toString(); })()";
14803
14804 {
14805 // Run the code twice in the first context to initialize the call IC.
14806 v8::HandleScope scope;
14807 LocalContext context1;
14808 ExpectString(code, "42");
14809 ExpectString(code, "42");
14810 }
14811
14812 {
14813 // Change the Number.prototype in the second context and check
14814 // that the right function gets called.
14815 v8::HandleScope scope;
14816 LocalContext context2;
14817 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
14818 ExpectString(code, "not 42");
14819 }
14820}
14821
14822
14823TEST(BooleanCheckMultipleContexts) {
14824 const char* code =
14825 "(function() { return true.toString(); })()";
14826
14827 {
14828 // Run the code twice in the first context to initialize the call IC.
14829 v8::HandleScope scope;
14830 LocalContext context1;
14831 ExpectString(code, "true");
14832 ExpectString(code, "true");
14833 }
14834
14835 {
14836 // Change the Boolean.prototype in the second context and check
14837 // that the right function gets called.
14838 v8::HandleScope scope;
14839 LocalContext context2;
14840 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
14841 ExpectString(code, "");
14842 }
14843}
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000014844
14845
14846TEST(DontDeleteCellLoadIC) {
14847 const char* function_code =
14848 "function readCell() { while (true) { return cell; } }";
14849
14850 {
14851 // Run the code twice in the first context to initialize the load
14852 // IC for a don't delete cell.
14853 v8::HandleScope scope;
14854 LocalContext context1;
14855 CompileRun("var cell = \"first\";");
14856 ExpectBoolean("delete cell", false);
14857 CompileRun(function_code);
14858 ExpectString("readCell()", "first");
14859 ExpectString("readCell()", "first");
14860 }
14861
14862 {
14863 // Use a deletable cell in the second context.
14864 v8::HandleScope scope;
14865 LocalContext context2;
14866 CompileRun("cell = \"second\";");
14867 CompileRun(function_code);
14868 ExpectString("readCell()", "second");
14869 ExpectBoolean("delete cell", true);
14870 ExpectString("(function() {"
14871 " try {"
14872 " return readCell();"
14873 " } catch(e) {"
14874 " return e.toString();"
14875 " }"
14876 "})()",
14877 "ReferenceError: cell is not defined");
14878 CompileRun("cell = \"new_second\";");
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000014879 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000014880 ExpectString("readCell()", "new_second");
14881 ExpectString("readCell()", "new_second");
14882 }
14883}
14884
14885
14886TEST(DontDeleteCellLoadICForceDelete) {
14887 const char* function_code =
14888 "function readCell() { while (true) { return cell; } }";
14889
14890 // Run the code twice to initialize the load IC for a don't delete
14891 // cell.
14892 v8::HandleScope scope;
14893 LocalContext context;
14894 CompileRun("var cell = \"value\";");
14895 ExpectBoolean("delete cell", false);
14896 CompileRun(function_code);
14897 ExpectString("readCell()", "value");
14898 ExpectString("readCell()", "value");
14899
14900 // Delete the cell using the API and check the inlined code works
14901 // correctly.
14902 CHECK(context->Global()->ForceDelete(v8_str("cell")));
14903 ExpectString("(function() {"
14904 " try {"
14905 " return readCell();"
14906 " } catch(e) {"
14907 " return e.toString();"
14908 " }"
14909 "})()",
14910 "ReferenceError: cell is not defined");
14911}
14912
14913
14914TEST(DontDeleteCellLoadICAPI) {
14915 const char* function_code =
14916 "function readCell() { while (true) { return cell; } }";
14917
14918 // Run the code twice to initialize the load IC for a don't delete
14919 // cell created using the API.
14920 v8::HandleScope scope;
14921 LocalContext context;
14922 context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
14923 ExpectBoolean("delete cell", false);
14924 CompileRun(function_code);
14925 ExpectString("readCell()", "value");
14926 ExpectString("readCell()", "value");
14927
14928 // Delete the cell using the API and check the inlined code works
14929 // correctly.
14930 CHECK(context->Global()->ForceDelete(v8_str("cell")));
14931 ExpectString("(function() {"
14932 " try {"
14933 " return readCell();"
14934 " } catch(e) {"
14935 " return e.toString();"
14936 " }"
14937 "})()",
14938 "ReferenceError: cell is not defined");
14939}
14940
14941
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000014942TEST(RegExp) {
14943 v8::HandleScope scope;
14944 LocalContext context;
14945
14946 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
14947 CHECK(re->IsRegExp());
14948 CHECK(re->GetSource()->Equals(v8_str("foo")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000014949 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000014950
14951 re = v8::RegExp::New(v8_str("bar"),
14952 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
14953 v8::RegExp::kGlobal));
14954 CHECK(re->IsRegExp());
14955 CHECK(re->GetSource()->Equals(v8_str("bar")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000014956 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
14957 static_cast<int>(re->GetFlags()));
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000014958
14959 re = v8::RegExp::New(v8_str("baz"),
14960 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
14961 v8::RegExp::kMultiline));
14962 CHECK(re->IsRegExp());
14963 CHECK(re->GetSource()->Equals(v8_str("baz")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000014964 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
14965 static_cast<int>(re->GetFlags()));
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000014966
14967 re = CompileRun("/quux/").As<v8::RegExp>();
14968 CHECK(re->IsRegExp());
14969 CHECK(re->GetSource()->Equals(v8_str("quux")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000014970 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000014971
14972 re = CompileRun("/quux/gm").As<v8::RegExp>();
14973 CHECK(re->IsRegExp());
14974 CHECK(re->GetSource()->Equals(v8_str("quux")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000014975 CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
14976 static_cast<int>(re->GetFlags()));
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000014977
14978 // Override the RegExp constructor and check the API constructor
14979 // still works.
14980 CompileRun("RegExp = function() {}");
14981
14982 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
14983 CHECK(re->IsRegExp());
14984 CHECK(re->GetSource()->Equals(v8_str("foobar")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000014985 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000014986
14987 re = v8::RegExp::New(v8_str("foobarbaz"),
14988 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
14989 v8::RegExp::kMultiline));
14990 CHECK(re->IsRegExp());
14991 CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000014992 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
14993 static_cast<int>(re->GetFlags()));
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000014994
14995 context->Global()->Set(v8_str("re"), re);
14996 ExpectTrue("re.test('FoobarbaZ')");
14997
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000014998 // RegExps are objects on which you can set properties.
14999 re->Set(v8_str("property"), v8::Integer::New(32));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000015000 v8::Handle<v8::Value> value(CompileRun("re.property"));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000015001 ASSERT_EQ(32, value->Int32Value());
15002
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000015003 v8::TryCatch try_catch;
15004 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
15005 CHECK(re.IsEmpty());
15006 CHECK(try_catch.HasCaught());
15007 context->Global()->Set(v8_str("ex"), try_catch.Exception());
15008 ExpectTrue("ex instanceof SyntaxError");
15009}
15010
15011
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000015012THREADED_TEST(Equals) {
15013 v8::HandleScope handleScope;
15014 LocalContext localContext;
15015
15016 v8::Handle<v8::Object> globalProxy = localContext->Global();
15017 v8::Handle<Value> global = globalProxy->GetPrototype();
15018
15019 CHECK(global->StrictEquals(global));
15020 CHECK(!global->StrictEquals(globalProxy));
15021 CHECK(!globalProxy->StrictEquals(global));
15022 CHECK(globalProxy->StrictEquals(globalProxy));
15023
15024 CHECK(global->Equals(global));
15025 CHECK(!global->Equals(globalProxy));
15026 CHECK(!globalProxy->Equals(global));
15027 CHECK(globalProxy->Equals(globalProxy));
15028}
15029
15030
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000015031static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
15032 const v8::AccessorInfo& info ) {
15033 return v8_str("42!");
15034}
15035
15036
15037static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo& info) {
15038 v8::Handle<v8::Array> result = v8::Array::New();
15039 result->Set(0, v8_str("universalAnswer"));
15040 return result;
15041}
15042
15043
15044TEST(NamedEnumeratorAndForIn) {
15045 v8::HandleScope handle_scope;
15046 LocalContext context;
15047 v8::Context::Scope context_scope(context.local());
15048
15049 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New();
15050 tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
15051 context->Global()->Set(v8_str("o"), tmpl->NewInstance());
15052 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
15053 "var result = []; for (var k in o) result.push(k); result"));
15054 CHECK_EQ(1, result->Length());
15055 CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
15056}
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000015057
15058
15059TEST(DefinePropertyPostDetach) {
15060 v8::HandleScope scope;
15061 LocalContext context;
15062 v8::Handle<v8::Object> proxy = context->Global();
15063 v8::Handle<v8::Function> define_property =
15064 CompileRun("(function() {"
15065 " Object.defineProperty("
15066 " this,"
15067 " 1,"
15068 " { configurable: true, enumerable: true, value: 3 });"
15069 "})").As<Function>();
15070 context->DetachGlobal();
15071 define_property->Call(proxy, 0, NULL);
15072}
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000015073
15074
15075static void InstallContextId(v8::Handle<Context> context, int id) {
15076 Context::Scope scope(context);
15077 CompileRun("Object.prototype").As<Object>()->
15078 Set(v8_str("context_id"), v8::Integer::New(id));
15079}
15080
15081
15082static void CheckContextId(v8::Handle<Object> object, int expected) {
15083 CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
15084}
15085
15086
15087THREADED_TEST(CreationContext) {
15088 HandleScope handle_scope;
15089 Persistent<Context> context1 = Context::New();
15090 InstallContextId(context1, 1);
15091 Persistent<Context> context2 = Context::New();
15092 InstallContextId(context2, 2);
15093 Persistent<Context> context3 = Context::New();
15094 InstallContextId(context3, 3);
15095
15096 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New();
15097
15098 Local<Object> object1;
15099 Local<Function> func1;
15100 {
15101 Context::Scope scope(context1);
15102 object1 = Object::New();
15103 func1 = tmpl->GetFunction();
15104 }
15105
15106 Local<Object> object2;
15107 Local<Function> func2;
15108 {
15109 Context::Scope scope(context2);
15110 object2 = Object::New();
15111 func2 = tmpl->GetFunction();
15112 }
15113
15114 Local<Object> instance1;
15115 Local<Object> instance2;
15116
15117 {
15118 Context::Scope scope(context3);
15119 instance1 = func1->NewInstance();
15120 instance2 = func2->NewInstance();
15121 }
15122
15123 CHECK(object1->CreationContext() == context1);
15124 CheckContextId(object1, 1);
15125 CHECK(func1->CreationContext() == context1);
15126 CheckContextId(func1, 1);
15127 CHECK(instance1->CreationContext() == context1);
15128 CheckContextId(instance1, 1);
15129 CHECK(object2->CreationContext() == context2);
15130 CheckContextId(object2, 2);
15131 CHECK(func2->CreationContext() == context2);
15132 CheckContextId(func2, 2);
15133 CHECK(instance2->CreationContext() == context2);
15134 CheckContextId(instance2, 2);
15135
15136 {
15137 Context::Scope scope(context1);
15138 CHECK(object1->CreationContext() == context1);
15139 CheckContextId(object1, 1);
15140 CHECK(func1->CreationContext() == context1);
15141 CheckContextId(func1, 1);
15142 CHECK(instance1->CreationContext() == context1);
15143 CheckContextId(instance1, 1);
15144 CHECK(object2->CreationContext() == context2);
15145 CheckContextId(object2, 2);
15146 CHECK(func2->CreationContext() == context2);
15147 CheckContextId(func2, 2);
15148 CHECK(instance2->CreationContext() == context2);
15149 CheckContextId(instance2, 2);
15150 }
15151
15152 {
15153 Context::Scope scope(context2);
15154 CHECK(object1->CreationContext() == context1);
15155 CheckContextId(object1, 1);
15156 CHECK(func1->CreationContext() == context1);
15157 CheckContextId(func1, 1);
15158 CHECK(instance1->CreationContext() == context1);
15159 CheckContextId(instance1, 1);
15160 CHECK(object2->CreationContext() == context2);
15161 CheckContextId(object2, 2);
15162 CHECK(func2->CreationContext() == context2);
15163 CheckContextId(func2, 2);
15164 CHECK(instance2->CreationContext() == context2);
15165 CheckContextId(instance2, 2);
15166 }
15167
15168 context1.Dispose();
15169 context2.Dispose();
15170 context3.Dispose();
15171}
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +000015172
15173
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000015174THREADED_TEST(CreationContextOfJsFunction) {
15175 HandleScope handle_scope;
15176 Persistent<Context> context = Context::New();
15177 InstallContextId(context, 1);
15178
15179 Local<Object> function;
15180 {
15181 Context::Scope scope(context);
15182 function = CompileRun("function foo() {}; foo").As<Object>();
15183 }
15184
15185 CHECK(function->CreationContext() == context);
15186 CheckContextId(function, 1);
15187
15188 context.Dispose();
15189}
15190
15191
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +000015192Handle<Value> HasOwnPropertyIndexedPropertyGetter(uint32_t index,
15193 const AccessorInfo& info) {
15194 if (index == 42) return v8_str("yes");
15195 return Handle<v8::Integer>();
15196}
15197
15198
15199Handle<Value> HasOwnPropertyNamedPropertyGetter(Local<String> property,
15200 const AccessorInfo& info) {
15201 if (property->Equals(v8_str("foo"))) return v8_str("yes");
15202 return Handle<Value>();
15203}
15204
15205
15206Handle<v8::Integer> HasOwnPropertyIndexedPropertyQuery(
15207 uint32_t index, const AccessorInfo& info) {
15208 if (index == 42) return v8_num(1).As<v8::Integer>();
15209 return Handle<v8::Integer>();
15210}
15211
15212
15213Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery(
15214 Local<String> property, const AccessorInfo& info) {
15215 if (property->Equals(v8_str("foo"))) return v8_num(1).As<v8::Integer>();
15216 return Handle<v8::Integer>();
15217}
15218
15219
15220Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery2(
15221 Local<String> property, const AccessorInfo& info) {
15222 if (property->Equals(v8_str("bar"))) return v8_num(1).As<v8::Integer>();
15223 return Handle<v8::Integer>();
15224}
15225
15226
15227Handle<Value> HasOwnPropertyAccessorGetter(Local<String> property,
15228 const AccessorInfo& info) {
15229 return v8_str("yes");
15230}
15231
15232
15233TEST(HasOwnProperty) {
15234 v8::HandleScope scope;
15235 LocalContext env;
15236 { // Check normal properties and defined getters.
15237 Handle<Value> value = CompileRun(
15238 "function Foo() {"
15239 " this.foo = 11;"
15240 " this.__defineGetter__('baz', function() { return 1; });"
15241 "};"
15242 "function Bar() { "
15243 " this.bar = 13;"
15244 " this.__defineGetter__('bla', function() { return 2; });"
15245 "};"
15246 "Bar.prototype = new Foo();"
15247 "new Bar();");
15248 CHECK(value->IsObject());
15249 Handle<Object> object = value->ToObject();
15250 CHECK(object->Has(v8_str("foo")));
15251 CHECK(!object->HasOwnProperty(v8_str("foo")));
15252 CHECK(object->HasOwnProperty(v8_str("bar")));
15253 CHECK(object->Has(v8_str("baz")));
15254 CHECK(!object->HasOwnProperty(v8_str("baz")));
15255 CHECK(object->HasOwnProperty(v8_str("bla")));
15256 }
15257 { // Check named getter interceptors.
15258 Handle<ObjectTemplate> templ = ObjectTemplate::New();
15259 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
15260 Handle<Object> instance = templ->NewInstance();
15261 CHECK(!instance->HasOwnProperty(v8_str("42")));
15262 CHECK(instance->HasOwnProperty(v8_str("foo")));
15263 CHECK(!instance->HasOwnProperty(v8_str("bar")));
15264 }
15265 { // Check indexed getter interceptors.
15266 Handle<ObjectTemplate> templ = ObjectTemplate::New();
15267 templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
15268 Handle<Object> instance = templ->NewInstance();
15269 CHECK(instance->HasOwnProperty(v8_str("42")));
15270 CHECK(!instance->HasOwnProperty(v8_str("43")));
15271 CHECK(!instance->HasOwnProperty(v8_str("foo")));
15272 }
15273 { // Check named query interceptors.
15274 Handle<ObjectTemplate> templ = ObjectTemplate::New();
15275 templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
15276 Handle<Object> instance = templ->NewInstance();
15277 CHECK(instance->HasOwnProperty(v8_str("foo")));
15278 CHECK(!instance->HasOwnProperty(v8_str("bar")));
15279 }
15280 { // Check indexed query interceptors.
15281 Handle<ObjectTemplate> templ = ObjectTemplate::New();
15282 templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
15283 Handle<Object> instance = templ->NewInstance();
15284 CHECK(instance->HasOwnProperty(v8_str("42")));
15285 CHECK(!instance->HasOwnProperty(v8_str("41")));
15286 }
15287 { // Check callbacks.
15288 Handle<ObjectTemplate> templ = ObjectTemplate::New();
15289 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
15290 Handle<Object> instance = templ->NewInstance();
15291 CHECK(instance->HasOwnProperty(v8_str("foo")));
15292 CHECK(!instance->HasOwnProperty(v8_str("bar")));
15293 }
15294 { // Check that query wins on disagreement.
15295 Handle<ObjectTemplate> templ = ObjectTemplate::New();
15296 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
15297 0,
15298 HasOwnPropertyNamedPropertyQuery2);
15299 Handle<Object> instance = templ->NewInstance();
15300 CHECK(!instance->HasOwnProperty(v8_str("foo")));
15301 CHECK(instance->HasOwnProperty(v8_str("bar")));
15302 }
15303}
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000015304
15305
15306void CheckCodeGenerationAllowed() {
15307 Handle<Value> result = CompileRun("eval('42')");
15308 CHECK_EQ(42, result->Int32Value());
15309 result = CompileRun("(function(e) { return e('42'); })(eval)");
15310 CHECK_EQ(42, result->Int32Value());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000015311 result = CompileRun("var f = new Function('return 42'); f()");
15312 CHECK_EQ(42, result->Int32Value());
15313}
15314
15315
15316void CheckCodeGenerationDisallowed() {
15317 TryCatch try_catch;
15318
15319 Handle<Value> result = CompileRun("eval('42')");
15320 CHECK(result.IsEmpty());
15321 CHECK(try_catch.HasCaught());
15322 try_catch.Reset();
15323
15324 result = CompileRun("(function(e) { return e('42'); })(eval)");
15325 CHECK(result.IsEmpty());
15326 CHECK(try_catch.HasCaught());
15327 try_catch.Reset();
15328
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000015329 result = CompileRun("var f = new Function('return 42'); f()");
15330 CHECK(result.IsEmpty());
15331 CHECK(try_catch.HasCaught());
15332}
15333
15334
15335bool CodeGenerationAllowed(Local<Context> context) {
15336 ApiTestFuzzer::Fuzz();
15337 return true;
15338}
15339
15340
15341bool CodeGenerationDisallowed(Local<Context> context) {
15342 ApiTestFuzzer::Fuzz();
15343 return false;
15344}
15345
15346
15347THREADED_TEST(AllowCodeGenFromStrings) {
15348 v8::HandleScope scope;
15349 LocalContext context;
15350
ager@chromium.orgea91cc52011-05-23 06:06:11 +000015351 // eval and the Function constructor allowed by default.
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000015352 CheckCodeGenerationAllowed();
15353
ager@chromium.orgea91cc52011-05-23 06:06:11 +000015354 // Disallow eval and the Function constructor.
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000015355 context->AllowCodeGenerationFromStrings(false);
15356 CheckCodeGenerationDisallowed();
15357
15358 // Allow again.
15359 context->AllowCodeGenerationFromStrings(true);
15360 CheckCodeGenerationAllowed();
15361
15362 // Disallow but setting a global callback that will allow the calls.
15363 context->AllowCodeGenerationFromStrings(false);
15364 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
15365 CheckCodeGenerationAllowed();
15366
15367 // Set a callback that disallows the code generation.
15368 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
15369 CheckCodeGenerationDisallowed();
15370}
lrn@chromium.org1c092762011-05-09 09:42:16 +000015371
15372
15373static v8::Handle<Value> NonObjectThis(const v8::Arguments& args) {
15374 return v8::Undefined();
15375}
15376
15377
15378THREADED_TEST(CallAPIFunctionOnNonObject) {
15379 v8::HandleScope scope;
15380 LocalContext context;
15381 Handle<FunctionTemplate> templ = v8::FunctionTemplate::New(NonObjectThis);
15382 Handle<Function> function = templ->GetFunction();
15383 context->Global()->Set(v8_str("f"), function);
15384 TryCatch try_catch;
15385 CompileRun("f.call(2)");
lrn@chromium.org1c092762011-05-09 09:42:16 +000015386}
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000015387
15388
15389// Regression test for issue 1470.
15390THREADED_TEST(ReadOnlyIndexedProperties) {
15391 v8::HandleScope scope;
15392 Local<ObjectTemplate> templ = ObjectTemplate::New();
15393
15394 LocalContext context;
15395 Local<v8::Object> obj = templ->NewInstance();
15396 context->Global()->Set(v8_str("obj"), obj);
15397 obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
15398 obj->Set(v8_str("1"), v8_str("foobar"));
15399 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
15400 obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
15401 obj->Set(v8_num(2), v8_str("foobar"));
15402 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
15403
15404 // Test non-smi case.
15405 obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
15406 obj->Set(v8_str("2000000000"), v8_str("foobar"));
15407 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
15408}
ricow@chromium.org4f693d62011-07-04 14:01:31 +000015409
15410
15411THREADED_TEST(Regress1516) {
15412 v8::HandleScope scope;
15413
15414 LocalContext context;
15415 { v8::HandleScope temp_scope;
15416 CompileRun("({'a': 0})");
15417 }
15418
15419 int elements;
15420 { i::MapCache* map_cache =
15421 i::MapCache::cast(i::Isolate::Current()->context()->map_cache());
15422 elements = map_cache->NumberOfElements();
15423 CHECK_LE(1, elements);
15424 }
15425
15426 i::Isolate::Current()->heap()->CollectAllGarbage(true);
15427 { i::Object* raw_map_cache = i::Isolate::Current()->context()->map_cache();
15428 if (raw_map_cache != i::Isolate::Current()->heap()->undefined_value()) {
15429 i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
15430 CHECK_GT(elements, map_cache->NumberOfElements());
15431 }
15432 }
15433}
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000015434
15435
15436static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
15437 Local<Value> name,
15438 v8::AccessType type,
15439 Local<Value> data) {
15440 // Only block read access to __proto__.
15441 if (type == v8::ACCESS_GET &&
15442 name->IsString() &&
15443 name->ToString()->Length() == 9 &&
15444 name->ToString()->Utf8Length() == 9) {
15445 char buffer[10];
15446 CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
15447 return strncmp(buffer, "__proto__", 9) != 0;
15448 }
15449
15450 return true;
15451}
15452
15453
15454THREADED_TEST(Regress93759) {
15455 HandleScope scope;
15456
15457 // Template for object with security check.
15458 Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New();
15459 // We don't do indexing, so any callback can be used for that.
15460 no_proto_template->SetAccessCheckCallbacks(
15461 BlockProtoNamedSecurityTestCallback,
15462 IndexedSecurityTestCallback);
15463
15464 // Templates for objects with hidden prototypes and possibly security check.
15465 Local<FunctionTemplate> hidden_proto_template = v8::FunctionTemplate::New();
15466 hidden_proto_template->SetHiddenPrototype(true);
15467
15468 Local<FunctionTemplate> protected_hidden_proto_template =
15469 v8::FunctionTemplate::New();
15470 protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
15471 BlockProtoNamedSecurityTestCallback,
15472 IndexedSecurityTestCallback);
15473 protected_hidden_proto_template->SetHiddenPrototype(true);
15474
15475 // Context for "foreign" objects used in test.
15476 Persistent<Context> context = v8::Context::New();
15477 context->Enter();
15478
15479 // Plain object, no security check.
15480 Local<Object> simple_object = Object::New();
15481
15482 // Object with explicit security check.
15483 Local<Object> protected_object =
15484 no_proto_template->NewInstance();
15485
15486 // JSGlobalProxy object, always have security check.
15487 Local<Object> proxy_object =
15488 context->Global();
15489
15490 // Global object, the prototype of proxy_object. No security checks.
15491 Local<Object> global_object =
15492 proxy_object->GetPrototype()->ToObject();
15493
15494 // Hidden prototype without security check.
15495 Local<Object> hidden_prototype =
15496 hidden_proto_template->GetFunction()->NewInstance();
15497 Local<Object> object_with_hidden =
15498 Object::New();
15499 object_with_hidden->SetPrototype(hidden_prototype);
15500
15501 // Hidden prototype with security check on the hidden prototype.
15502 Local<Object> protected_hidden_prototype =
15503 protected_hidden_proto_template->GetFunction()->NewInstance();
15504 Local<Object> object_with_protected_hidden =
15505 Object::New();
15506 object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
15507
15508 context->Exit();
15509
15510 // Template for object for second context. Values to test are put on it as
15511 // properties.
15512 Local<ObjectTemplate> global_template = ObjectTemplate::New();
15513 global_template->Set(v8_str("simple"), simple_object);
15514 global_template->Set(v8_str("protected"), protected_object);
15515 global_template->Set(v8_str("global"), global_object);
15516 global_template->Set(v8_str("proxy"), proxy_object);
15517 global_template->Set(v8_str("hidden"), object_with_hidden);
15518 global_template->Set(v8_str("phidden"), object_with_protected_hidden);
15519
15520 LocalContext context2(NULL, global_template);
15521
15522 Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
15523 CHECK(result1->Equals(simple_object->GetPrototype()));
15524
15525 Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
15526 CHECK(result2->Equals(Undefined()));
15527
15528 Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
15529 CHECK(result3->Equals(global_object->GetPrototype()));
15530
15531 Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
15532 CHECK(result4->Equals(Undefined()));
15533
15534 Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
15535 CHECK(result5->Equals(
15536 object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
15537
15538 Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
15539 CHECK(result6->Equals(Undefined()));
15540
15541 context.Dispose();
15542}
15543
15544
15545static void TestReceiver(Local<Value> expected_result,
15546 Local<Value> expected_receiver,
15547 const char* code) {
15548 Local<Value> result = CompileRun(code);
15549 CHECK(result->IsObject());
15550 CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
15551 CHECK(expected_result->Equals(result->ToObject()->Get(0)));
15552}
15553
15554
15555THREADED_TEST(ForeignFunctionReceiver) {
15556 HandleScope scope;
15557
15558 // Create two contexts with different "id" properties ('i' and 'o').
15559 // Call a function both from its own context and from a the foreign
15560 // context, and see what "this" is bound to (returning both "this"
15561 // and "this.id" for comparison).
15562
15563 Persistent<Context> foreign_context = v8::Context::New();
15564 foreign_context->Enter();
15565 Local<Value> foreign_function =
15566 CompileRun("function func() { return { 0: this.id, "
15567 " 1: this, "
15568 " toString: function() { "
15569 " return this[0];"
15570 " }"
15571 " };"
15572 "}"
15573 "var id = 'i';"
15574 "func;");
15575 CHECK(foreign_function->IsFunction());
15576 foreign_context->Exit();
15577
15578 LocalContext context;
15579
15580 Local<String> password = v8_str("Password");
15581 // Don't get hit by security checks when accessing foreign_context's
15582 // global receiver (aka. global proxy).
15583 context->SetSecurityToken(password);
15584 foreign_context->SetSecurityToken(password);
15585
15586 Local<String> i = v8_str("i");
15587 Local<String> o = v8_str("o");
15588 Local<String> id = v8_str("id");
15589
15590 CompileRun("function ownfunc() { return { 0: this.id, "
15591 " 1: this, "
15592 " toString: function() { "
15593 " return this[0];"
15594 " }"
15595 " };"
15596 "}"
15597 "var id = 'o';"
15598 "ownfunc");
15599 context->Global()->Set(v8_str("func"), foreign_function);
15600
15601 // Sanity check the contexts.
15602 CHECK(i->Equals(foreign_context->Global()->Get(id)));
15603 CHECK(o->Equals(context->Global()->Get(id)));
15604
15605 // Checking local function's receiver.
15606 // Calling function using its call/apply methods.
15607 TestReceiver(o, context->Global(), "ownfunc.call()");
15608 TestReceiver(o, context->Global(), "ownfunc.apply()");
15609 // Making calls through built-in functions.
15610 TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
15611 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
15612 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
15613 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
15614 // Calling with environment record as base.
15615 TestReceiver(o, context->Global(), "ownfunc()");
15616 // Calling with no base.
15617 TestReceiver(o, context->Global(), "(1,ownfunc)()");
15618
15619 // Checking foreign function return value.
15620 // Calling function using its call/apply methods.
15621 TestReceiver(i, foreign_context->Global(), "func.call()");
15622 TestReceiver(i, foreign_context->Global(), "func.apply()");
15623 // Calling function using another context's call/apply methods.
15624 TestReceiver(i, foreign_context->Global(),
15625 "Function.prototype.call.call(func)");
15626 TestReceiver(i, foreign_context->Global(),
15627 "Function.prototype.call.apply(func)");
15628 TestReceiver(i, foreign_context->Global(),
15629 "Function.prototype.apply.call(func)");
15630 TestReceiver(i, foreign_context->Global(),
15631 "Function.prototype.apply.apply(func)");
15632 // Making calls through built-in functions.
15633 TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
15634 // ToString(func()) is func()[0], i.e., the returned this.id.
15635 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
15636 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
15637 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
15638
15639 // TODO(1547): Make the following also return "i".
15640 // Calling with environment record as base.
15641 TestReceiver(o, context->Global(), "func()");
15642 // Calling with no base.
15643 TestReceiver(o, context->Global(), "(1,func)()");
15644
15645 foreign_context.Dispose();
15646}