blob: d5e17b89a7efa346f4f90e67e28969952077822a [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
83
84static void ExpectBoolean(const char* code, bool expected) {
85 Local<Value> result = CompileRun(code);
86 CHECK(result->IsBoolean());
87 CHECK_EQ(expected, result->BooleanValue());
88}
89
90
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000091static void ExpectTrue(const char* code) {
92 ExpectBoolean(code, true);
93}
94
95
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000096static void ExpectFalse(const char* code) {
97 ExpectBoolean(code, false);
98}
99
100
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +0000101static void ExpectObject(const char* code, Local<Value> expected) {
102 Local<Value> result = CompileRun(code);
103 CHECK(result->Equals(expected));
104}
105
106
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000107static void ExpectUndefined(const char* code) {
108 Local<Value> result = CompileRun(code);
109 CHECK(result->IsUndefined());
110}
111
112
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000113static int signature_callback_count;
114static v8::Handle<Value> IncrementingSignatureCallback(
115 const v8::Arguments& args) {
116 ApiTestFuzzer::Fuzz();
117 signature_callback_count++;
118 v8::Handle<v8::Array> result = v8::Array::New(args.Length());
119 for (int i = 0; i < args.Length(); i++)
120 result->Set(v8::Integer::New(i), args[i]);
121 return result;
122}
123
124
125static v8::Handle<Value> SignatureCallback(const v8::Arguments& args) {
126 ApiTestFuzzer::Fuzz();
127 v8::Handle<v8::Array> result = v8::Array::New(args.Length());
128 for (int i = 0; i < args.Length(); i++) {
129 result->Set(v8::Integer::New(i), args[i]);
130 }
131 return result;
132}
133
134
135THREADED_TEST(Handles) {
136 v8::HandleScope scope;
137 Local<Context> local_env;
138 {
139 LocalContext env;
140 local_env = env.local();
141 }
142
143 // Local context should still be live.
144 CHECK(!local_env.IsEmpty());
145 local_env->Enter();
146
147 v8::Handle<v8::Primitive> undef = v8::Undefined();
148 CHECK(!undef.IsEmpty());
149 CHECK(undef->IsUndefined());
150
151 const char* c_source = "1 + 2 + 3";
152 Local<String> source = String::New(c_source);
153 Local<Script> script = Script::Compile(source);
154 CHECK_EQ(6, script->Run()->Int32Value());
155
156 local_env->Exit();
157}
158
159
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000160THREADED_TEST(ReceiverSignature) {
161 v8::HandleScope scope;
162 LocalContext env;
163 v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
164 v8::Handle<v8::Signature> sig = v8::Signature::New(fun);
165 fun->PrototypeTemplate()->Set(
166 v8_str("m"),
167 v8::FunctionTemplate::New(IncrementingSignatureCallback,
168 v8::Handle<Value>(),
169 sig));
170 env->Global()->Set(v8_str("Fun"), fun->GetFunction());
171 signature_callback_count = 0;
172 CompileRun(
173 "var o = new Fun();"
174 "o.m();");
175 CHECK_EQ(1, signature_callback_count);
176 v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New();
177 sub_fun->Inherit(fun);
178 env->Global()->Set(v8_str("SubFun"), sub_fun->GetFunction());
179 CompileRun(
180 "var o = new SubFun();"
181 "o.m();");
182 CHECK_EQ(2, signature_callback_count);
183
184 v8::TryCatch try_catch;
185 CompileRun(
186 "var o = { };"
187 "o.m = Fun.prototype.m;"
188 "o.m();");
189 CHECK_EQ(2, signature_callback_count);
190 CHECK(try_catch.HasCaught());
191 try_catch.Reset();
192 v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New();
193 sub_fun->Inherit(fun);
194 env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
195 CompileRun(
196 "var o = new UnrelFun();"
197 "o.m = Fun.prototype.m;"
198 "o.m();");
199 CHECK_EQ(2, signature_callback_count);
200 CHECK(try_catch.HasCaught());
201}
202
203
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000204THREADED_TEST(ArgumentSignature) {
205 v8::HandleScope scope;
206 LocalContext env;
207 v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New();
208 cons->SetClassName(v8_str("Cons"));
209 v8::Handle<v8::Signature> sig =
210 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 1, &cons);
211 v8::Handle<v8::FunctionTemplate> fun =
212 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig);
213 env->Global()->Set(v8_str("Cons"), cons->GetFunction());
214 env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
215
216 v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000217 CHECK(value1->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000218
219 v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000220 CHECK(value2->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000221
222 v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000223 CHECK(value3->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000224
225 v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New();
226 cons1->SetClassName(v8_str("Cons1"));
227 v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New();
228 cons2->SetClassName(v8_str("Cons2"));
229 v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New();
230 cons3->SetClassName(v8_str("Cons3"));
231
232 v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
233 v8::Handle<v8::Signature> wsig =
234 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 3, args);
235 v8::Handle<v8::FunctionTemplate> fun2 =
236 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig);
237
238 env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
239 env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
240 env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
241 env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
242 v8::Handle<Value> value4 = CompileRun(
243 "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
244 "'[object Cons1],[object Cons2],[object Cons3]'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000245 CHECK(value4->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000246
247 v8::Handle<Value> value5 = CompileRun(
248 "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000249 CHECK(value5->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000250
251 v8::Handle<Value> value6 = CompileRun(
252 "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000253 CHECK(value6->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000254
255 v8::Handle<Value> value7 = CompileRun(
256 "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
257 "'[object Cons1],[object Cons2],[object Cons3],d';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000258 CHECK(value7->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000259
260 v8::Handle<Value> value8 = CompileRun(
261 "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000262 CHECK(value8->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000263}
264
265
266THREADED_TEST(HulIgennem) {
267 v8::HandleScope scope;
268 LocalContext env;
269 v8::Handle<v8::Primitive> undef = v8::Undefined();
270 Local<String> undef_str = undef->ToString();
271 char* value = i::NewArray<char>(undef_str->Length() + 1);
272 undef_str->WriteAscii(value);
273 CHECK_EQ(0, strcmp(value, "undefined"));
274 i::DeleteArray(value);
275}
276
277
278THREADED_TEST(Access) {
279 v8::HandleScope scope;
280 LocalContext env;
281 Local<v8::Object> obj = v8::Object::New();
282 Local<Value> foo_before = obj->Get(v8_str("foo"));
283 CHECK(foo_before->IsUndefined());
284 Local<String> bar_str = v8_str("bar");
285 obj->Set(v8_str("foo"), bar_str);
286 Local<Value> foo_after = obj->Get(v8_str("foo"));
287 CHECK(!foo_after->IsUndefined());
288 CHECK(foo_after->IsString());
289 CHECK_EQ(bar_str, foo_after);
290}
291
292
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000293THREADED_TEST(AccessElement) {
294 v8::HandleScope scope;
295 LocalContext env;
296 Local<v8::Object> obj = v8::Object::New();
297 Local<Value> before = obj->Get(1);
298 CHECK(before->IsUndefined());
299 Local<String> bar_str = v8_str("bar");
300 obj->Set(1, bar_str);
301 Local<Value> after = obj->Get(1);
302 CHECK(!after->IsUndefined());
303 CHECK(after->IsString());
304 CHECK_EQ(bar_str, after);
305
306 Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
307 CHECK_EQ(v8_str("a"), value->Get(0));
308 CHECK_EQ(v8_str("b"), value->Get(1));
309}
310
311
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000312THREADED_TEST(Script) {
313 v8::HandleScope scope;
314 LocalContext env;
315 const char* c_source = "1 + 2 + 3";
316 Local<String> source = String::New(c_source);
317 Local<Script> script = Script::Compile(source);
318 CHECK_EQ(6, script->Run()->Int32Value());
319}
320
321
322static uint16_t* AsciiToTwoByteString(const char* source) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000323 int array_length = i::StrLength(source) + 1;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000324 uint16_t* converted = i::NewArray<uint16_t>(array_length);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000325 for (int i = 0; i < array_length; i++) converted[i] = source[i];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000326 return converted;
327}
328
329
330class TestResource: public String::ExternalStringResource {
331 public:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000332 explicit TestResource(uint16_t* data, int* counter = NULL)
333 : data_(data), length_(0), counter_(counter) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000334 while (data[length_]) ++length_;
335 }
336
337 ~TestResource() {
338 i::DeleteArray(data_);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000339 if (counter_ != NULL) ++*counter_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000340 }
341
342 const uint16_t* data() const {
343 return data_;
344 }
345
346 size_t length() const {
347 return length_;
348 }
349 private:
350 uint16_t* data_;
351 size_t length_;
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000352 int* counter_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000353};
354
355
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000356class TestAsciiResource: public String::ExternalAsciiStringResource {
357 public:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000358 explicit TestAsciiResource(const char* data, int* counter = NULL)
359 : data_(data), length_(strlen(data)), counter_(counter) { }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000360
361 ~TestAsciiResource() {
362 i::DeleteArray(data_);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000363 if (counter_ != NULL) ++*counter_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000364 }
365
366 const char* data() const {
367 return data_;
368 }
369
370 size_t length() const {
371 return length_;
372 }
373 private:
ager@chromium.org5ec48922009-05-05 07:25:34 +0000374 const char* data_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000375 size_t length_;
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000376 int* counter_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000377};
378
379
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000380THREADED_TEST(ScriptUsingStringResource) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000381 int dispose_count = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000382 const char* c_source = "1 + 2 * 3";
383 uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
384 {
385 v8::HandleScope scope;
386 LocalContext env;
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000387 TestResource* resource = new TestResource(two_byte_source, &dispose_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000388 Local<String> source = String::NewExternal(resource);
389 Local<Script> script = Script::Compile(source);
390 Local<Value> value = script->Run();
391 CHECK(value->IsNumber());
392 CHECK_EQ(7, value->Int32Value());
393 CHECK(source->IsExternal());
394 CHECK_EQ(resource,
395 static_cast<TestResource*>(source->GetExternalStringResource()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000396 HEAP->CollectAllGarbage(false);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000397 CHECK_EQ(0, dispose_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000398 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000399 v8::internal::Isolate::Current()->compilation_cache()->Clear();
400 HEAP->CollectAllGarbage(false);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000401 CHECK_EQ(1, dispose_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000402}
403
404
405THREADED_TEST(ScriptUsingAsciiStringResource) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000406 int dispose_count = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000407 const char* c_source = "1 + 2 * 3";
408 {
409 v8::HandleScope scope;
410 LocalContext env;
411 Local<String> source =
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000412 String::NewExternal(new TestAsciiResource(i::StrDup(c_source),
413 &dispose_count));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000414 Local<Script> script = Script::Compile(source);
415 Local<Value> value = script->Run();
416 CHECK(value->IsNumber());
417 CHECK_EQ(7, value->Int32Value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000418 HEAP->CollectAllGarbage(false);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000419 CHECK_EQ(0, dispose_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000420 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000421 i::Isolate::Current()->compilation_cache()->Clear();
422 HEAP->CollectAllGarbage(false);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000423 CHECK_EQ(1, dispose_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000424}
425
426
ager@chromium.org6f10e412009-02-13 10:11:16 +0000427THREADED_TEST(ScriptMakingExternalString) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000428 int dispose_count = 0;
ager@chromium.org6f10e412009-02-13 10:11:16 +0000429 uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
430 {
431 v8::HandleScope scope;
432 LocalContext env;
433 Local<String> source = String::New(two_byte_source);
ager@chromium.org5c838252010-02-19 08:53:10 +0000434 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000435 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
436 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000437 bool success = source->MakeExternal(new TestResource(two_byte_source,
438 &dispose_count));
ager@chromium.org6f10e412009-02-13 10:11:16 +0000439 CHECK(success);
440 Local<Script> script = Script::Compile(source);
441 Local<Value> value = script->Run();
442 CHECK(value->IsNumber());
443 CHECK_EQ(7, value->Int32Value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000444 HEAP->CollectAllGarbage(false);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000445 CHECK_EQ(0, dispose_count);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000446 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000447 i::Isolate::Current()->compilation_cache()->Clear();
448 HEAP->CollectAllGarbage(false);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000449 CHECK_EQ(1, dispose_count);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000450}
451
452
453THREADED_TEST(ScriptMakingExternalAsciiString) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000454 int dispose_count = 0;
ager@chromium.org6f10e412009-02-13 10:11:16 +0000455 const char* c_source = "1 + 2 * 3";
456 {
457 v8::HandleScope scope;
458 LocalContext env;
459 Local<String> source = v8_str(c_source);
ager@chromium.org5c838252010-02-19 08:53:10 +0000460 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000461 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
462 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
ager@chromium.org6f10e412009-02-13 10:11:16 +0000463 bool success = source->MakeExternal(
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000464 new TestAsciiResource(i::StrDup(c_source), &dispose_count));
ager@chromium.org6f10e412009-02-13 10:11:16 +0000465 CHECK(success);
466 Local<Script> script = Script::Compile(source);
467 Local<Value> value = script->Run();
468 CHECK(value->IsNumber());
469 CHECK_EQ(7, value->Int32Value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000470 HEAP->CollectAllGarbage(false);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000471 CHECK_EQ(0, dispose_count);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000472 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000473 i::Isolate::Current()->compilation_cache()->Clear();
474 HEAP->CollectAllGarbage(false);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000475 CHECK_EQ(1, dispose_count);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000476}
477
478
ager@chromium.org5c838252010-02-19 08:53:10 +0000479TEST(MakingExternalStringConditions) {
480 v8::HandleScope scope;
481 LocalContext env;
482
483 // Free some space in the new space so that we can check freshness.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000484 HEAP->CollectGarbage(i::NEW_SPACE);
485 HEAP->CollectGarbage(i::NEW_SPACE);
ager@chromium.org5c838252010-02-19 08:53:10 +0000486
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000487 uint16_t* two_byte_string = AsciiToTwoByteString("small");
488 Local<String> small_string = String::New(two_byte_string);
489 i::DeleteArray(two_byte_string);
490
ager@chromium.org5c838252010-02-19 08:53:10 +0000491 // We should refuse to externalize newly created small string.
492 CHECK(!small_string->CanMakeExternal());
493 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000494 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
495 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
ager@chromium.org5c838252010-02-19 08:53:10 +0000496 // Old space strings should be accepted.
497 CHECK(small_string->CanMakeExternal());
498
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000499 two_byte_string = AsciiToTwoByteString("small 2");
500 small_string = String::New(two_byte_string);
501 i::DeleteArray(two_byte_string);
502
ager@chromium.org5c838252010-02-19 08:53:10 +0000503 // We should refuse externalizing newly created small string.
504 CHECK(!small_string->CanMakeExternal());
505 for (int i = 0; i < 100; i++) {
506 String::Value value(small_string);
507 }
508 // Frequently used strings should be accepted.
509 CHECK(small_string->CanMakeExternal());
510
511 const int buf_size = 10 * 1024;
512 char* buf = i::NewArray<char>(buf_size);
513 memset(buf, 'a', buf_size);
514 buf[buf_size - 1] = '\0';
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000515
516 two_byte_string = AsciiToTwoByteString(buf);
517 Local<String> large_string = String::New(two_byte_string);
ager@chromium.org5c838252010-02-19 08:53:10 +0000518 i::DeleteArray(buf);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000519 i::DeleteArray(two_byte_string);
ager@chromium.org5c838252010-02-19 08:53:10 +0000520 // Large strings should be immediately accepted.
521 CHECK(large_string->CanMakeExternal());
522}
523
524
525TEST(MakingExternalAsciiStringConditions) {
526 v8::HandleScope scope;
527 LocalContext env;
528
529 // Free some space in the new space so that we can check freshness.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000530 HEAP->CollectGarbage(i::NEW_SPACE);
531 HEAP->CollectGarbage(i::NEW_SPACE);
ager@chromium.org5c838252010-02-19 08:53:10 +0000532
533 Local<String> small_string = String::New("small");
534 // We should refuse to externalize newly created small string.
535 CHECK(!small_string->CanMakeExternal());
536 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000537 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
538 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
ager@chromium.org5c838252010-02-19 08:53:10 +0000539 // Old space strings should be accepted.
540 CHECK(small_string->CanMakeExternal());
541
542 small_string = String::New("small 2");
543 // We should refuse externalizing newly created small string.
544 CHECK(!small_string->CanMakeExternal());
545 for (int i = 0; i < 100; i++) {
546 String::Value value(small_string);
547 }
548 // Frequently used strings should be accepted.
549 CHECK(small_string->CanMakeExternal());
550
551 const int buf_size = 10 * 1024;
552 char* buf = i::NewArray<char>(buf_size);
553 memset(buf, 'a', buf_size);
554 buf[buf_size - 1] = '\0';
555 Local<String> large_string = String::New(buf);
556 i::DeleteArray(buf);
557 // Large strings should be immediately accepted.
558 CHECK(large_string->CanMakeExternal());
559}
560
561
ager@chromium.org6f10e412009-02-13 10:11:16 +0000562THREADED_TEST(UsingExternalString) {
ager@chromium.orge2902be2009-06-08 12:21:35 +0000563 {
564 v8::HandleScope scope;
565 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
566 Local<String> string =
567 String::NewExternal(new TestResource(two_byte_string));
568 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
569 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000570 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
571 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
572 i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
ager@chromium.orge2902be2009-06-08 12:21:35 +0000573 CHECK(isymbol->IsSymbol());
574 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000575 HEAP->CollectAllGarbage(false);
576 HEAP->CollectAllGarbage(false);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000577}
578
579
580THREADED_TEST(UsingExternalAsciiString) {
ager@chromium.orge2902be2009-06-08 12:21:35 +0000581 {
582 v8::HandleScope scope;
583 const char* one_byte_string = "test string";
584 Local<String> string = String::NewExternal(
585 new TestAsciiResource(i::StrDup(one_byte_string)));
586 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
587 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000588 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
589 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
590 i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
ager@chromium.orge2902be2009-06-08 12:21:35 +0000591 CHECK(isymbol->IsSymbol());
592 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000593 HEAP->CollectAllGarbage(false);
594 HEAP->CollectAllGarbage(false);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000595}
596
597
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000598THREADED_TEST(ScavengeExternalString) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000599 int dispose_count = 0;
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000600 bool in_new_space = false;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000601 {
602 v8::HandleScope scope;
603 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
604 Local<String> string =
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000605 String::NewExternal(new TestResource(two_byte_string,
606 &dispose_count));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000607 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000608 HEAP->CollectGarbage(i::NEW_SPACE);
609 in_new_space = HEAP->InNewSpace(*istring);
610 CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000611 CHECK_EQ(0, dispose_count);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000612 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000613 HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000614 CHECK_EQ(1, dispose_count);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000615}
616
617
618THREADED_TEST(ScavengeExternalAsciiString) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000619 int dispose_count = 0;
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000620 bool in_new_space = false;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000621 {
622 v8::HandleScope scope;
623 const char* one_byte_string = "test string";
624 Local<String> string = String::NewExternal(
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000625 new TestAsciiResource(i::StrDup(one_byte_string), &dispose_count));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000626 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000627 HEAP->CollectGarbage(i::NEW_SPACE);
628 in_new_space = HEAP->InNewSpace(*istring);
629 CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000630 CHECK_EQ(0, dispose_count);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000631 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000632 HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000633 CHECK_EQ(1, dispose_count);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000634}
635
636
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000637class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
638 public:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000639 // Only used by non-threaded tests, so it can use static fields.
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000640 static int dispose_calls;
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000641 static int dispose_count;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000642
643 TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000644 : TestAsciiResource(data, &dispose_count),
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000645 dispose_(dispose) { }
646
647 void Dispose() {
648 ++dispose_calls;
649 if (dispose_) delete this;
650 }
651 private:
652 bool dispose_;
653};
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000654
655
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000656int TestAsciiResourceWithDisposeControl::dispose_count = 0;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000657int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000658
659
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000660TEST(ExternalStringWithDisposeHandling) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000661 const char* c_source = "1 + 2 * 3";
662
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000663 // Use a stack allocated external string resource allocated object.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000664 TestAsciiResourceWithDisposeControl::dispose_count = 0;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000665 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
666 TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000667 {
668 v8::HandleScope scope;
669 LocalContext env;
670 Local<String> source = String::NewExternal(&res_stack);
671 Local<Script> script = Script::Compile(source);
672 Local<Value> value = script->Run();
673 CHECK(value->IsNumber());
674 CHECK_EQ(7, value->Int32Value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000675 HEAP->CollectAllGarbage(false);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000676 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000677 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000678 i::Isolate::Current()->compilation_cache()->Clear();
679 HEAP->CollectAllGarbage(false);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000680 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000681 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000682
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000683 // Use a heap allocated external string resource allocated object.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000684 TestAsciiResourceWithDisposeControl::dispose_count = 0;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000685 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
686 TestAsciiResource* res_heap =
687 new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000688 {
689 v8::HandleScope scope;
690 LocalContext env;
691 Local<String> source = String::NewExternal(res_heap);
692 Local<Script> script = Script::Compile(source);
693 Local<Value> value = script->Run();
694 CHECK(value->IsNumber());
695 CHECK_EQ(7, value->Int32Value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000696 HEAP->CollectAllGarbage(false);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000697 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000698 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000699 i::Isolate::Current()->compilation_cache()->Clear();
700 HEAP->CollectAllGarbage(false);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000701 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000702 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_count);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000703}
704
705
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000706THREADED_TEST(StringConcat) {
707 {
708 v8::HandleScope scope;
709 LocalContext env;
710 const char* one_byte_string_1 = "function a_times_t";
711 const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
712 const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
713 const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
714 const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
715 const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
716 const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
717 Local<String> left = v8_str(one_byte_string_1);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000718
719 uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
720 Local<String> right = String::New(two_byte_source);
721 i::DeleteArray(two_byte_source);
722
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000723 Local<String> source = String::Concat(left, right);
724 right = String::NewExternal(
725 new TestAsciiResource(i::StrDup(one_byte_extern_1)));
726 source = String::Concat(source, right);
727 right = String::NewExternal(
728 new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
729 source = String::Concat(source, right);
730 right = v8_str(one_byte_string_2);
731 source = String::Concat(source, right);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000732
733 two_byte_source = AsciiToTwoByteString(two_byte_string_2);
734 right = String::New(two_byte_source);
735 i::DeleteArray(two_byte_source);
736
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000737 source = String::Concat(source, right);
738 right = String::NewExternal(
739 new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
740 source = String::Concat(source, right);
741 Local<Script> script = Script::Compile(source);
742 Local<Value> value = script->Run();
743 CHECK(value->IsNumber());
744 CHECK_EQ(68, value->Int32Value());
745 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000746 i::Isolate::Current()->compilation_cache()->Clear();
747 HEAP->CollectAllGarbage(false);
748 HEAP->CollectAllGarbage(false);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000749}
750
751
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000752THREADED_TEST(GlobalProperties) {
753 v8::HandleScope scope;
754 LocalContext env;
755 v8::Handle<v8::Object> global = env->Global();
756 global->Set(v8_str("pi"), v8_num(3.1415926));
757 Local<Value> pi = global->Get(v8_str("pi"));
758 CHECK_EQ(3.1415926, pi->NumberValue());
759}
760
761
762static v8::Handle<Value> handle_call(const v8::Arguments& args) {
763 ApiTestFuzzer::Fuzz();
764 return v8_num(102);
765}
766
767
768static v8::Handle<Value> construct_call(const v8::Arguments& args) {
769 ApiTestFuzzer::Fuzz();
770 args.This()->Set(v8_str("x"), v8_num(1));
771 args.This()->Set(v8_str("y"), v8_num(2));
772 return args.This();
773}
774
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000775static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
776 ApiTestFuzzer::Fuzz();
777 return v8_num(239);
778}
779
780
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000781THREADED_TEST(FunctionTemplate) {
782 v8::HandleScope scope;
783 LocalContext env;
784 {
785 Local<v8::FunctionTemplate> fun_templ =
786 v8::FunctionTemplate::New(handle_call);
787 Local<Function> fun = fun_templ->GetFunction();
788 env->Global()->Set(v8_str("obj"), fun);
789 Local<Script> script = v8_compile("obj()");
790 CHECK_EQ(102, script->Run()->Int32Value());
791 }
792 // Use SetCallHandler to initialize a function template, should work like the
793 // previous one.
794 {
795 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
796 fun_templ->SetCallHandler(handle_call);
797 Local<Function> fun = fun_templ->GetFunction();
798 env->Global()->Set(v8_str("obj"), fun);
799 Local<Script> script = v8_compile("obj()");
800 CHECK_EQ(102, script->Run()->Int32Value());
801 }
802 // Test constructor calls.
803 {
804 Local<v8::FunctionTemplate> fun_templ =
805 v8::FunctionTemplate::New(construct_call);
806 fun_templ->SetClassName(v8_str("funky"));
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000807 fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), Return239);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000808 Local<Function> fun = fun_templ->GetFunction();
809 env->Global()->Set(v8_str("obj"), fun);
810 Local<Script> script = v8_compile("var s = new obj(); s.x");
811 CHECK_EQ(1, script->Run()->Int32Value());
812
813 Local<Value> result = v8_compile("(new obj()).toString()")->Run();
814 CHECK_EQ(v8_str("[object funky]"), result);
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000815
816 result = v8_compile("(new obj()).m")->Run();
817 CHECK_EQ(239, result->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000818 }
819}
820
821
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000822static void* expected_ptr;
823static v8::Handle<v8::Value> callback(const v8::Arguments& args) {
824 void* ptr = v8::External::Unwrap(args.Data());
825 CHECK_EQ(expected_ptr, ptr);
826 return v8::Boolean::New(true);
827}
828
829
830static void TestExternalPointerWrapping() {
831 v8::HandleScope scope;
832 LocalContext env;
833
834 v8::Handle<v8::Value> data = v8::External::Wrap(expected_ptr);
835
836 v8::Handle<v8::Object> obj = v8::Object::New();
837 obj->Set(v8_str("func"),
838 v8::FunctionTemplate::New(callback, data)->GetFunction());
839 env->Global()->Set(v8_str("obj"), obj);
840
841 CHECK(CompileRun(
842 "function foo() {\n"
843 " for (var i = 0; i < 13; i++) obj.func();\n"
844 "}\n"
845 "foo(), true")->BooleanValue());
846}
847
848
849THREADED_TEST(ExternalWrap) {
850 // Check heap allocated object.
851 int* ptr = new int;
852 expected_ptr = ptr;
853 TestExternalPointerWrapping();
854 delete ptr;
855
856 // Check stack allocated object.
857 int foo;
858 expected_ptr = &foo;
859 TestExternalPointerWrapping();
860
861 // Check not aligned addresses.
862 const int n = 100;
863 char* s = new char[n];
864 for (int i = 0; i < n; i++) {
865 expected_ptr = s + i;
866 TestExternalPointerWrapping();
867 }
868
869 delete[] s;
870
871 // Check several invalid addresses.
872 expected_ptr = reinterpret_cast<void*>(1);
873 TestExternalPointerWrapping();
874
875 expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
876 TestExternalPointerWrapping();
877
878 expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
879 TestExternalPointerWrapping();
880
881#if defined(V8_HOST_ARCH_X64)
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000882 // Check a value with a leading 1 bit in x64 Smi encoding.
883 expected_ptr = reinterpret_cast<void*>(0x400000000);
884 TestExternalPointerWrapping();
885
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000886 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
887 TestExternalPointerWrapping();
888
889 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
890 TestExternalPointerWrapping();
891#endif
892}
893
894
sgjesse@chromium.org900d3b72009-08-07 11:24:25 +0000895THREADED_TEST(FindInstanceInPrototypeChain) {
896 v8::HandleScope scope;
897 LocalContext env;
898
899 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
900 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
901 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
902 derived->Inherit(base);
903
904 Local<v8::Function> base_function = base->GetFunction();
905 Local<v8::Function> derived_function = derived->GetFunction();
906 Local<v8::Function> other_function = other->GetFunction();
907
908 Local<v8::Object> base_instance = base_function->NewInstance();
909 Local<v8::Object> derived_instance = derived_function->NewInstance();
910 Local<v8::Object> derived_instance2 = derived_function->NewInstance();
911 Local<v8::Object> other_instance = other_function->NewInstance();
912 derived_instance2->Set(v8_str("__proto__"), derived_instance);
913 other_instance->Set(v8_str("__proto__"), derived_instance2);
914
915 // base_instance is only an instance of base.
916 CHECK_EQ(base_instance,
917 base_instance->FindInstanceInPrototypeChain(base));
918 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
919 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
920
921 // derived_instance is an instance of base and derived.
922 CHECK_EQ(derived_instance,
923 derived_instance->FindInstanceInPrototypeChain(base));
924 CHECK_EQ(derived_instance,
925 derived_instance->FindInstanceInPrototypeChain(derived));
926 CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
927
928 // other_instance is an instance of other and its immediate
929 // prototype derived_instance2 is an instance of base and derived.
930 // Note, derived_instance is an instance of base and derived too,
931 // but it comes after derived_instance2 in the prototype chain of
932 // other_instance.
933 CHECK_EQ(derived_instance2,
934 other_instance->FindInstanceInPrototypeChain(base));
935 CHECK_EQ(derived_instance2,
936 other_instance->FindInstanceInPrototypeChain(derived));
937 CHECK_EQ(other_instance,
938 other_instance->FindInstanceInPrototypeChain(other));
939}
940
941
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000942THREADED_TEST(TinyInteger) {
943 v8::HandleScope scope;
944 LocalContext env;
945 int32_t value = 239;
946 Local<v8::Integer> value_obj = v8::Integer::New(value);
947 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
948}
949
950
951THREADED_TEST(BigSmiInteger) {
952 v8::HandleScope scope;
953 LocalContext env;
954 int32_t value = i::Smi::kMaxValue;
955 // We cannot add one to a Smi::kMaxValue without wrapping.
956 if (i::kSmiValueSize < 32) {
957 CHECK(i::Smi::IsValid(value));
958 CHECK(!i::Smi::IsValid(value + 1));
959 Local<v8::Integer> value_obj = v8::Integer::New(value);
960 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
961 }
962}
963
964
965THREADED_TEST(BigInteger) {
966 v8::HandleScope scope;
967 LocalContext env;
968 // We cannot add one to a Smi::kMaxValue without wrapping.
969 if (i::kSmiValueSize < 32) {
970 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
971 // The code will not be run in that case, due to the "if" guard.
972 int32_t value =
973 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
974 CHECK(value > i::Smi::kMaxValue);
975 CHECK(!i::Smi::IsValid(value));
976 Local<v8::Integer> value_obj = v8::Integer::New(value);
977 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
978 }
979}
980
981
982THREADED_TEST(TinyUnsignedInteger) {
983 v8::HandleScope scope;
984 LocalContext env;
985 uint32_t value = 239;
986 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
987 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
988}
989
990
991THREADED_TEST(BigUnsignedSmiInteger) {
992 v8::HandleScope scope;
993 LocalContext env;
994 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
995 CHECK(i::Smi::IsValid(value));
996 CHECK(!i::Smi::IsValid(value + 1));
997 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
998 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
999}
1000
1001
1002THREADED_TEST(BigUnsignedInteger) {
1003 v8::HandleScope scope;
1004 LocalContext env;
1005 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1006 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1007 CHECK(!i::Smi::IsValid(value));
1008 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1009 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1010}
1011
1012
1013THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1014 v8::HandleScope scope;
1015 LocalContext env;
1016 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1017 uint32_t value = INT32_MAX_AS_UINT + 1;
1018 CHECK(value > INT32_MAX_AS_UINT); // No overflow.
1019 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1020 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1021}
1022
1023
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001024THREADED_TEST(IsNativeError) {
1025 v8::HandleScope scope;
1026 LocalContext env;
1027 v8::Handle<Value> syntax_error = CompileRun(
1028 "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1029 CHECK(syntax_error->IsNativeError());
1030 v8::Handle<Value> not_error = CompileRun("{a:42}");
1031 CHECK(!not_error->IsNativeError());
1032 v8::Handle<Value> not_object = CompileRun("42");
1033 CHECK(!not_object->IsNativeError());
1034}
1035
1036
1037THREADED_TEST(StringObject) {
1038 v8::HandleScope scope;
1039 LocalContext env;
1040 v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1041 CHECK(boxed_string->IsStringObject());
1042 v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1043 CHECK(!unboxed_string->IsStringObject());
1044 v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1045 CHECK(!boxed_not_string->IsStringObject());
1046 v8::Handle<Value> not_object = CompileRun("0");
1047 CHECK(!not_object->IsStringObject());
1048 v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1049 CHECK(!as_boxed.IsEmpty());
1050 Local<v8::String> the_string = as_boxed->StringValue();
1051 CHECK(!the_string.IsEmpty());
1052 ExpectObject("\"test\"", the_string);
1053 v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1054 CHECK(new_boxed_string->IsStringObject());
1055 as_boxed = new_boxed_string.As<v8::StringObject>();
1056 the_string = as_boxed->StringValue();
1057 CHECK(!the_string.IsEmpty());
1058 ExpectObject("\"test\"", the_string);
1059}
1060
1061
1062THREADED_TEST(NumberObject) {
1063 v8::HandleScope scope;
1064 LocalContext env;
1065 v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1066 CHECK(boxed_number->IsNumberObject());
1067 v8::Handle<Value> unboxed_number = CompileRun("42");
1068 CHECK(!unboxed_number->IsNumberObject());
1069 v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1070 CHECK(!boxed_not_number->IsNumberObject());
1071 v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1072 CHECK(!as_boxed.IsEmpty());
1073 double the_number = as_boxed->NumberValue();
1074 CHECK_EQ(42.0, the_number);
1075 v8::Handle<v8::Value> new_boxed_number = v8::NumberObject::New(43);
1076 CHECK(new_boxed_number->IsNumberObject());
1077 as_boxed = new_boxed_number.As<v8::NumberObject>();
1078 the_number = as_boxed->NumberValue();
1079 CHECK_EQ(43.0, the_number);
1080}
1081
1082
1083THREADED_TEST(BooleanObject) {
1084 v8::HandleScope scope;
1085 LocalContext env;
1086 v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1087 CHECK(boxed_boolean->IsBooleanObject());
1088 v8::Handle<Value> unboxed_boolean = CompileRun("true");
1089 CHECK(!unboxed_boolean->IsBooleanObject());
1090 v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1091 CHECK(!boxed_not_boolean->IsBooleanObject());
1092 v8::Handle<v8::BooleanObject> as_boxed =
1093 boxed_boolean.As<v8::BooleanObject>();
1094 CHECK(!as_boxed.IsEmpty());
1095 bool the_boolean = as_boxed->BooleanValue();
1096 CHECK_EQ(true, the_boolean);
1097 v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1098 v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1099 CHECK(boxed_true->IsBooleanObject());
1100 CHECK(boxed_false->IsBooleanObject());
1101 as_boxed = boxed_true.As<v8::BooleanObject>();
1102 CHECK_EQ(true, as_boxed->BooleanValue());
1103 as_boxed = boxed_false.As<v8::BooleanObject>();
1104 CHECK_EQ(false, as_boxed->BooleanValue());
1105}
1106
1107
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001108THREADED_TEST(Number) {
1109 v8::HandleScope scope;
1110 LocalContext env;
1111 double PI = 3.1415926;
1112 Local<v8::Number> pi_obj = v8::Number::New(PI);
1113 CHECK_EQ(PI, pi_obj->NumberValue());
1114}
1115
1116
1117THREADED_TEST(ToNumber) {
1118 v8::HandleScope scope;
1119 LocalContext env;
1120 Local<String> str = v8_str("3.1415926");
1121 CHECK_EQ(3.1415926, str->NumberValue());
1122 v8::Handle<v8::Boolean> t = v8::True();
1123 CHECK_EQ(1.0, t->NumberValue());
1124 v8::Handle<v8::Boolean> f = v8::False();
1125 CHECK_EQ(0.0, f->NumberValue());
1126}
1127
1128
1129THREADED_TEST(Date) {
1130 v8::HandleScope scope;
1131 LocalContext env;
1132 double PI = 3.1415926;
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001133 Local<Value> date = v8::Date::New(PI);
1134 CHECK_EQ(3.0, date->NumberValue());
1135 date.As<v8::Date>()->Set(v8_str("property"), v8::Integer::New(42));
1136 CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001137}
1138
1139
1140THREADED_TEST(Boolean) {
1141 v8::HandleScope scope;
1142 LocalContext env;
1143 v8::Handle<v8::Boolean> t = v8::True();
1144 CHECK(t->Value());
1145 v8::Handle<v8::Boolean> f = v8::False();
1146 CHECK(!f->Value());
1147 v8::Handle<v8::Primitive> u = v8::Undefined();
1148 CHECK(!u->BooleanValue());
1149 v8::Handle<v8::Primitive> n = v8::Null();
1150 CHECK(!n->BooleanValue());
1151 v8::Handle<String> str1 = v8_str("");
1152 CHECK(!str1->BooleanValue());
1153 v8::Handle<String> str2 = v8_str("x");
1154 CHECK(str2->BooleanValue());
1155 CHECK(!v8::Number::New(0)->BooleanValue());
1156 CHECK(v8::Number::New(-1)->BooleanValue());
1157 CHECK(v8::Number::New(1)->BooleanValue());
1158 CHECK(v8::Number::New(42)->BooleanValue());
1159 CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1160}
1161
1162
1163static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
1164 ApiTestFuzzer::Fuzz();
1165 return v8_num(13.4);
1166}
1167
1168
1169static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
1170 ApiTestFuzzer::Fuzz();
1171 return v8_num(876);
1172}
1173
1174
1175THREADED_TEST(GlobalPrototype) {
1176 v8::HandleScope scope;
1177 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
1178 func_templ->PrototypeTemplate()->Set(
1179 "dummy",
1180 v8::FunctionTemplate::New(DummyCallHandler));
1181 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1182 templ->Set("x", v8_num(200));
1183 templ->SetAccessor(v8_str("m"), GetM);
1184 LocalContext env(0, templ);
1185 v8::Handle<v8::Object> obj = env->Global();
1186 v8::Handle<Script> script = v8_compile("dummy()");
1187 v8::Handle<Value> result = script->Run();
1188 CHECK_EQ(13.4, result->NumberValue());
1189 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1190 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1191}
1192
1193
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001194THREADED_TEST(ObjectTemplate) {
1195 v8::HandleScope scope;
1196 Local<ObjectTemplate> templ1 = ObjectTemplate::New();
1197 templ1->Set("x", v8_num(10));
1198 templ1->Set("y", v8_num(13));
1199 LocalContext env;
1200 Local<v8::Object> instance1 = templ1->NewInstance();
1201 env->Global()->Set(v8_str("p"), instance1);
1202 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1203 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1204 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
1205 fun->PrototypeTemplate()->Set("nirk", v8_num(123));
1206 Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1207 templ2->Set("a", v8_num(12));
1208 templ2->Set("b", templ1);
1209 Local<v8::Object> instance2 = templ2->NewInstance();
1210 env->Global()->Set(v8_str("q"), instance2);
1211 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1212 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1213 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1214 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1215}
1216
1217
1218static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
1219 ApiTestFuzzer::Fuzz();
1220 return v8_num(17.2);
1221}
1222
1223
1224static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
1225 ApiTestFuzzer::Fuzz();
1226 return v8_num(15.2);
1227}
1228
1229
1230THREADED_TEST(DescriptorInheritance) {
1231 v8::HandleScope scope;
1232 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
1233 super->PrototypeTemplate()->Set("flabby",
1234 v8::FunctionTemplate::New(GetFlabby));
1235 super->PrototypeTemplate()->Set("PI", v8_num(3.14));
1236
1237 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1238
1239 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
1240 base1->Inherit(super);
1241 base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
1242
1243 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
1244 base2->Inherit(super);
1245 base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
1246
1247 LocalContext env;
1248
1249 env->Global()->Set(v8_str("s"), super->GetFunction());
1250 env->Global()->Set(v8_str("base1"), base1->GetFunction());
1251 env->Global()->Set(v8_str("base2"), base2->GetFunction());
1252
1253 // Checks right __proto__ chain.
1254 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1255 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1256
1257 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1258
1259 // Instance accessor should not be visible on function object or its prototype
1260 CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1261 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1262 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1263
1264 env->Global()->Set(v8_str("obj"),
1265 base1->GetFunction()->NewInstance());
1266 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1267 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1268 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1269 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1270 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1271
1272 env->Global()->Set(v8_str("obj2"),
1273 base2->GetFunction()->NewInstance());
1274 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1275 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1276 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1277 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1278 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1279
1280 // base1 and base2 cannot cross reference to each's prototype
1281 CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1282 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1283}
1284
1285
1286int echo_named_call_count;
1287
1288
1289static v8::Handle<Value> EchoNamedProperty(Local<String> name,
1290 const AccessorInfo& info) {
1291 ApiTestFuzzer::Fuzz();
1292 CHECK_EQ(v8_str("data"), info.Data());
1293 echo_named_call_count++;
1294 return name;
1295}
1296
1297
1298THREADED_TEST(NamedPropertyHandlerGetter) {
1299 echo_named_call_count = 0;
1300 v8::HandleScope scope;
1301 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1302 templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
1303 0, 0, 0, 0,
1304 v8_str("data"));
1305 LocalContext env;
1306 env->Global()->Set(v8_str("obj"),
1307 templ->GetFunction()->NewInstance());
1308 CHECK_EQ(echo_named_call_count, 0);
1309 v8_compile("obj.x")->Run();
1310 CHECK_EQ(echo_named_call_count, 1);
1311 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
1312 v8::Handle<Value> str = CompileRun(code);
1313 String::AsciiValue value(str);
1314 CHECK_EQ(*value, "oddlepoddle");
1315 // Check default behavior
1316 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
1317 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
1318 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
1319}
1320
1321
1322int echo_indexed_call_count = 0;
1323
1324
1325static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
1326 const AccessorInfo& info) {
1327 ApiTestFuzzer::Fuzz();
1328 CHECK_EQ(v8_num(637), info.Data());
1329 echo_indexed_call_count++;
1330 return v8_num(index);
1331}
1332
1333
1334THREADED_TEST(IndexedPropertyHandlerGetter) {
1335 v8::HandleScope scope;
1336 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1337 templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
1338 0, 0, 0, 0,
1339 v8_num(637));
1340 LocalContext env;
1341 env->Global()->Set(v8_str("obj"),
1342 templ->GetFunction()->NewInstance());
1343 Local<Script> script = v8_compile("obj[900]");
1344 CHECK_EQ(script->Run()->Int32Value(), 900);
1345}
1346
1347
1348v8::Handle<v8::Object> bottom;
1349
1350static v8::Handle<Value> CheckThisIndexedPropertyHandler(
1351 uint32_t index,
1352 const AccessorInfo& info) {
1353 ApiTestFuzzer::Fuzz();
1354 CHECK(info.This()->Equals(bottom));
1355 return v8::Handle<Value>();
1356}
1357
1358static v8::Handle<Value> CheckThisNamedPropertyHandler(
1359 Local<String> name,
1360 const AccessorInfo& info) {
1361 ApiTestFuzzer::Fuzz();
1362 CHECK(info.This()->Equals(bottom));
1363 return v8::Handle<Value>();
1364}
1365
1366
1367v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
1368 Local<Value> value,
1369 const AccessorInfo& info) {
1370 ApiTestFuzzer::Fuzz();
1371 CHECK(info.This()->Equals(bottom));
1372 return v8::Handle<Value>();
1373}
1374
1375
1376v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
1377 Local<Value> value,
1378 const AccessorInfo& info) {
1379 ApiTestFuzzer::Fuzz();
1380 CHECK(info.This()->Equals(bottom));
1381 return v8::Handle<Value>();
1382}
1383
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001384v8::Handle<v8::Integer> CheckThisIndexedPropertyQuery(
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001385 uint32_t index,
1386 const AccessorInfo& info) {
1387 ApiTestFuzzer::Fuzz();
1388 CHECK(info.This()->Equals(bottom));
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001389 return v8::Handle<v8::Integer>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001390}
1391
1392
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001393v8::Handle<v8::Integer> CheckThisNamedPropertyQuery(Local<String> property,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001394 const AccessorInfo& info) {
1395 ApiTestFuzzer::Fuzz();
1396 CHECK(info.This()->Equals(bottom));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001397 return v8::Handle<v8::Integer>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001398}
1399
1400
1401v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
1402 uint32_t index,
1403 const AccessorInfo& info) {
1404 ApiTestFuzzer::Fuzz();
1405 CHECK(info.This()->Equals(bottom));
1406 return v8::Handle<v8::Boolean>();
1407}
1408
1409
1410v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
1411 Local<String> property,
1412 const AccessorInfo& info) {
1413 ApiTestFuzzer::Fuzz();
1414 CHECK(info.This()->Equals(bottom));
1415 return v8::Handle<v8::Boolean>();
1416}
1417
1418
1419v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
1420 const AccessorInfo& info) {
1421 ApiTestFuzzer::Fuzz();
1422 CHECK(info.This()->Equals(bottom));
1423 return v8::Handle<v8::Array>();
1424}
1425
1426
1427v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
1428 const AccessorInfo& info) {
1429 ApiTestFuzzer::Fuzz();
1430 CHECK(info.This()->Equals(bottom));
1431 return v8::Handle<v8::Array>();
1432}
1433
1434
1435THREADED_TEST(PropertyHandlerInPrototype) {
1436 v8::HandleScope scope;
1437 LocalContext env;
1438
1439 // Set up a prototype chain with three interceptors.
1440 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1441 templ->InstanceTemplate()->SetIndexedPropertyHandler(
1442 CheckThisIndexedPropertyHandler,
1443 CheckThisIndexedPropertySetter,
1444 CheckThisIndexedPropertyQuery,
1445 CheckThisIndexedPropertyDeleter,
1446 CheckThisIndexedPropertyEnumerator);
1447
1448 templ->InstanceTemplate()->SetNamedPropertyHandler(
1449 CheckThisNamedPropertyHandler,
1450 CheckThisNamedPropertySetter,
1451 CheckThisNamedPropertyQuery,
1452 CheckThisNamedPropertyDeleter,
1453 CheckThisNamedPropertyEnumerator);
1454
1455 bottom = templ->GetFunction()->NewInstance();
1456 Local<v8::Object> top = templ->GetFunction()->NewInstance();
1457 Local<v8::Object> middle = templ->GetFunction()->NewInstance();
1458
1459 bottom->Set(v8_str("__proto__"), middle);
1460 middle->Set(v8_str("__proto__"), top);
1461 env->Global()->Set(v8_str("obj"), bottom);
1462
1463 // Indexed and named get.
1464 Script::Compile(v8_str("obj[0]"))->Run();
1465 Script::Compile(v8_str("obj.x"))->Run();
1466
1467 // Indexed and named set.
1468 Script::Compile(v8_str("obj[1] = 42"))->Run();
1469 Script::Compile(v8_str("obj.y = 42"))->Run();
1470
1471 // Indexed and named query.
1472 Script::Compile(v8_str("0 in obj"))->Run();
1473 Script::Compile(v8_str("'x' in obj"))->Run();
1474
1475 // Indexed and named deleter.
1476 Script::Compile(v8_str("delete obj[0]"))->Run();
1477 Script::Compile(v8_str("delete obj.x"))->Run();
1478
1479 // Enumerators.
1480 Script::Compile(v8_str("for (var p in obj) ;"))->Run();
1481}
1482
1483
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001484static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
1485 const AccessorInfo& info) {
1486 ApiTestFuzzer::Fuzz();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001487 if (v8_str("pre")->Equals(key)) {
1488 return v8_str("PrePropertyHandler: pre");
1489 }
1490 return v8::Handle<String>();
1491}
1492
1493
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001494static v8::Handle<v8::Integer> PrePropertyHandlerQuery(Local<String> key,
1495 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001496 if (v8_str("pre")->Equals(key)) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001497 return v8::Integer::New(v8::None);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001498 }
1499
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001500 return v8::Handle<v8::Integer>(); // do not intercept the call
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001501}
1502
1503
1504THREADED_TEST(PrePropertyHandler) {
1505 v8::HandleScope scope;
1506 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
1507 desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
1508 0,
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001509 PrePropertyHandlerQuery);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001510 LocalContext env(NULL, desc->InstanceTemplate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001511 Script::Compile(v8_str(
1512 "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
1513 v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
1514 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
1515 v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
1516 CHECK_EQ(v8_str("Object: on"), result_on);
1517 v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
1518 CHECK(result_post.IsEmpty());
1519}
1520
1521
ager@chromium.org870a0b62008-11-04 11:43:05 +00001522THREADED_TEST(UndefinedIsNotEnumerable) {
1523 v8::HandleScope scope;
1524 LocalContext env;
1525 v8::Handle<Value> result = Script::Compile(v8_str(
1526 "this.propertyIsEnumerable(undefined)"))->Run();
1527 CHECK(result->IsFalse());
1528}
1529
1530
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001531v8::Handle<Script> call_recursively_script;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001532static const int kTargetRecursionDepth = 200; // near maximum
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001533
1534
1535static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
1536 ApiTestFuzzer::Fuzz();
1537 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1538 if (depth == kTargetRecursionDepth) return v8::Undefined();
1539 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1540 return call_recursively_script->Run();
1541}
1542
1543
1544static v8::Handle<Value> CallFunctionRecursivelyCall(
1545 const v8::Arguments& args) {
1546 ApiTestFuzzer::Fuzz();
1547 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1548 if (depth == kTargetRecursionDepth) {
1549 printf("[depth = %d]\n", depth);
1550 return v8::Undefined();
1551 }
1552 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1553 v8::Handle<Value> function =
1554 args.This()->Get(v8_str("callFunctionRecursively"));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001555 return function.As<Function>()->Call(args.This(), 0, NULL);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001556}
1557
1558
1559THREADED_TEST(DeepCrossLanguageRecursion) {
1560 v8::HandleScope scope;
1561 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
1562 global->Set(v8_str("callScriptRecursively"),
1563 v8::FunctionTemplate::New(CallScriptRecursivelyCall));
1564 global->Set(v8_str("callFunctionRecursively"),
1565 v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
1566 LocalContext env(NULL, global);
1567
1568 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1569 call_recursively_script = v8_compile("callScriptRecursively()");
1570 v8::Handle<Value> result = call_recursively_script->Run();
1571 call_recursively_script = v8::Handle<Script>();
1572
1573 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1574 Script::Compile(v8_str("callFunctionRecursively()"))->Run();
1575}
1576
1577
1578static v8::Handle<Value>
1579 ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1580 ApiTestFuzzer::Fuzz();
1581 return v8::ThrowException(key);
1582}
1583
1584
1585static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
1586 Local<Value>,
1587 const AccessorInfo&) {
1588 v8::ThrowException(key);
1589 return v8::Undefined(); // not the same as v8::Handle<v8::Value>()
1590}
1591
1592
1593THREADED_TEST(CallbackExceptionRegression) {
1594 v8::HandleScope scope;
1595 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1596 obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
1597 ThrowingPropertyHandlerSet);
1598 LocalContext env;
1599 env->Global()->Set(v8_str("obj"), obj->NewInstance());
1600 v8::Handle<Value> otto = Script::Compile(v8_str(
1601 "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
1602 CHECK_EQ(v8_str("otto"), otto);
1603 v8::Handle<Value> netto = Script::Compile(v8_str(
1604 "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
1605 CHECK_EQ(v8_str("netto"), netto);
1606}
1607
1608
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001609THREADED_TEST(FunctionPrototype) {
1610 v8::HandleScope scope;
1611 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
1612 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
1613 LocalContext env;
1614 env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
1615 Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
1616 CHECK_EQ(script->Run()->Int32Value(), 321);
1617}
1618
1619
1620THREADED_TEST(InternalFields) {
1621 v8::HandleScope scope;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001622 LocalContext env;
1623
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001624 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1625 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1626 instance_templ->SetInternalFieldCount(1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001627 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1628 CHECK_EQ(1, obj->InternalFieldCount());
1629 CHECK(obj->GetInternalField(0)->IsUndefined());
1630 obj->SetInternalField(0, v8_num(17));
1631 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
1632}
1633
1634
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001635THREADED_TEST(GlobalObjectInternalFields) {
1636 v8::HandleScope scope;
1637 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
1638 global_template->SetInternalFieldCount(1);
1639 LocalContext env(NULL, global_template);
1640 v8::Handle<v8::Object> global_proxy = env->Global();
1641 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
1642 CHECK_EQ(1, global->InternalFieldCount());
1643 CHECK(global->GetInternalField(0)->IsUndefined());
1644 global->SetInternalField(0, v8_num(17));
1645 CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
1646}
1647
1648
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001649THREADED_TEST(InternalFieldsNativePointers) {
1650 v8::HandleScope scope;
1651 LocalContext env;
1652
1653 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1654 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1655 instance_templ->SetInternalFieldCount(1);
1656 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1657 CHECK_EQ(1, obj->InternalFieldCount());
1658 CHECK(obj->GetPointerFromInternalField(0) == NULL);
1659
1660 char* data = new char[100];
1661
1662 void* aligned = data;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001663 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001664 void* unaligned = data + 1;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001665 CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001666
1667 // Check reading and writing aligned pointers.
1668 obj->SetPointerInInternalField(0, aligned);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001669 HEAP->CollectAllGarbage(false);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001670 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1671
1672 // Check reading and writing unaligned pointers.
1673 obj->SetPointerInInternalField(0, unaligned);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001674 HEAP->CollectAllGarbage(false);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001675 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1676
1677 delete[] data;
1678}
1679
1680
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001681THREADED_TEST(InternalFieldsNativePointersAndExternal) {
1682 v8::HandleScope scope;
1683 LocalContext env;
1684
1685 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1686 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1687 instance_templ->SetInternalFieldCount(1);
1688 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1689 CHECK_EQ(1, obj->InternalFieldCount());
1690 CHECK(obj->GetPointerFromInternalField(0) == NULL);
1691
1692 char* data = new char[100];
1693
1694 void* aligned = data;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001695 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001696 void* unaligned = data + 1;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001697 CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001698
1699 obj->SetPointerInInternalField(0, aligned);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001700 HEAP->CollectAllGarbage(false);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001701 CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0)));
1702
1703 obj->SetPointerInInternalField(0, unaligned);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001704 HEAP->CollectAllGarbage(false);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001705 CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0)));
1706
1707 obj->SetInternalField(0, v8::External::Wrap(aligned));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001708 HEAP->CollectAllGarbage(false);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001709 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1710
1711 obj->SetInternalField(0, v8::External::Wrap(unaligned));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001712 HEAP->CollectAllGarbage(false);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001713 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1714
1715 delete[] data;
1716}
1717
1718
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001719THREADED_TEST(IdentityHash) {
1720 v8::HandleScope scope;
1721 LocalContext env;
1722
1723 // Ensure that the test starts with an fresh heap to test whether the hash
1724 // code is based on the address.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001725 HEAP->CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001726 Local<v8::Object> obj = v8::Object::New();
1727 int hash = obj->GetIdentityHash();
1728 int hash1 = obj->GetIdentityHash();
1729 CHECK_EQ(hash, hash1);
1730 int hash2 = v8::Object::New()->GetIdentityHash();
1731 // Since the identity hash is essentially a random number two consecutive
1732 // objects should not be assigned the same hash code. If the test below fails
1733 // the random number generator should be evaluated.
1734 CHECK_NE(hash, hash2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001735 HEAP->CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001736 int hash3 = v8::Object::New()->GetIdentityHash();
1737 // Make sure that the identity hash is not based on the initial address of
1738 // the object alone. If the test below fails the random number generator
1739 // should be evaluated.
1740 CHECK_NE(hash, hash3);
1741 int hash4 = obj->GetIdentityHash();
1742 CHECK_EQ(hash, hash4);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001743
1744 // Check identity hashes behaviour in the presence of JS accessors.
1745 // Put a getter for 'v8::IdentityHash' on the Object's prototype:
1746 {
1747 CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
1748 Local<v8::Object> o1 = v8::Object::New();
1749 Local<v8::Object> o2 = v8::Object::New();
1750 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
1751 }
1752 {
1753 CompileRun(
1754 "function cnst() { return 42; };\n"
1755 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
1756 Local<v8::Object> o1 = v8::Object::New();
1757 Local<v8::Object> o2 = v8::Object::New();
1758 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
1759 }
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001760}
1761
1762
1763THREADED_TEST(HiddenProperties) {
1764 v8::HandleScope scope;
1765 LocalContext env;
1766
1767 v8::Local<v8::Object> obj = v8::Object::New();
1768 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1769 v8::Local<v8::String> empty = v8_str("");
1770 v8::Local<v8::String> prop_name = v8_str("prop_name");
1771
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001772 HEAP->CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001773
kasperl@chromium.orgacae3782009-04-11 09:17:08 +00001774 // Make sure delete of a non-existent hidden value works
1775 CHECK(obj->DeleteHiddenValue(key));
1776
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001777 CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
1778 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
1779 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
1780 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1781
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001782 HEAP->CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001783
1784 // Make sure we do not find the hidden property.
1785 CHECK(!obj->Has(empty));
1786 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1787 CHECK(obj->Get(empty)->IsUndefined());
1788 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1789 CHECK(obj->Set(empty, v8::Integer::New(2003)));
1790 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1791 CHECK_EQ(2003, obj->Get(empty)->Int32Value());
1792
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001793 HEAP->CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001794
1795 // Add another property and delete it afterwards to force the object in
1796 // slow case.
1797 CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
1798 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1799 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
1800 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1801 CHECK(obj->Delete(prop_name));
1802 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1803
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001804 HEAP->CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001805
1806 CHECK(obj->DeleteHiddenValue(key));
1807 CHECK(obj->GetHiddenValue(key).IsEmpty());
1808}
1809
1810
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001811static bool interceptor_for_hidden_properties_called;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001812static v8::Handle<Value> InterceptorForHiddenProperties(
1813 Local<String> name, const AccessorInfo& info) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001814 interceptor_for_hidden_properties_called = true;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001815 return v8::Handle<Value>();
1816}
1817
1818
1819THREADED_TEST(HiddenPropertiesWithInterceptors) {
1820 v8::HandleScope scope;
1821 LocalContext context;
1822
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001823 interceptor_for_hidden_properties_called = false;
1824
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001825 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1826
1827 // Associate an interceptor with an object and start setting hidden values.
1828 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
1829 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
1830 instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
1831 Local<v8::Function> function = fun_templ->GetFunction();
1832 Local<v8::Object> obj = function->NewInstance();
1833 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
1834 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001835 CHECK(!interceptor_for_hidden_properties_called);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001836}
1837
1838
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001839THREADED_TEST(External) {
1840 v8::HandleScope scope;
1841 int x = 3;
1842 Local<v8::External> ext = v8::External::New(&x);
1843 LocalContext env;
1844 env->Global()->Set(v8_str("ext"), ext);
1845 Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001846 v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001847 int* ptr = static_cast<int*>(reext->Value());
1848 CHECK_EQ(x, 3);
1849 *ptr = 10;
1850 CHECK_EQ(x, 10);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001851
1852 // Make sure unaligned pointers are wrapped properly.
1853 char* data = i::StrDup("0123456789");
1854 Local<v8::Value> zero = v8::External::Wrap(&data[0]);
1855 Local<v8::Value> one = v8::External::Wrap(&data[1]);
1856 Local<v8::Value> two = v8::External::Wrap(&data[2]);
1857 Local<v8::Value> three = v8::External::Wrap(&data[3]);
1858
1859 char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero));
1860 CHECK_EQ('0', *char_ptr);
1861 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one));
1862 CHECK_EQ('1', *char_ptr);
1863 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two));
1864 CHECK_EQ('2', *char_ptr);
1865 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three));
1866 CHECK_EQ('3', *char_ptr);
1867 i::DeleteArray(data);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001868}
1869
1870
1871THREADED_TEST(GlobalHandle) {
1872 v8::Persistent<String> global;
1873 {
1874 v8::HandleScope scope;
1875 Local<String> str = v8_str("str");
1876 global = v8::Persistent<String>::New(str);
1877 }
1878 CHECK_EQ(global->Length(), 3);
1879 global.Dispose();
1880}
1881
1882
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001883static int NumberOfWeakCalls = 0;
1884static void WeakPointerCallback(Persistent<Value> handle, void* id) {
1885 CHECK_EQ(reinterpret_cast<void*>(1234), id);
1886 NumberOfWeakCalls++;
1887 handle.Dispose();
1888}
1889
1890THREADED_TEST(ApiObjectGroups) {
1891 HandleScope scope;
1892 LocalContext env;
1893
1894 NumberOfWeakCalls = 0;
1895
1896 Persistent<Object> g1s1;
1897 Persistent<Object> g1s2;
1898 Persistent<Object> g1c1;
1899 Persistent<Object> g2s1;
1900 Persistent<Object> g2s2;
1901 Persistent<Object> g2c1;
1902
1903 {
1904 HandleScope scope;
1905 g1s1 = Persistent<Object>::New(Object::New());
1906 g1s2 = Persistent<Object>::New(Object::New());
1907 g1c1 = Persistent<Object>::New(Object::New());
1908 g1s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1909 g1s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1910 g1c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1911
1912 g2s1 = Persistent<Object>::New(Object::New());
1913 g2s2 = Persistent<Object>::New(Object::New());
1914 g2c1 = Persistent<Object>::New(Object::New());
1915 g2s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1916 g2s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1917 g2c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1918 }
1919
1920 Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
1921
1922 // Connect group 1 and 2, make a cycle.
1923 CHECK(g1s2->Set(0, g2s2));
1924 CHECK(g2s1->Set(0, g1s1));
1925
1926 {
1927 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
1928 Persistent<Value> g1_children[] = { g1c1 };
1929 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
1930 Persistent<Value> g2_children[] = { g2c1 };
1931 V8::AddObjectGroup(g1_objects, 2);
1932 V8::AddImplicitReferences(g1s1, g1_children, 1);
1933 V8::AddObjectGroup(g2_objects, 2);
1934 V8::AddImplicitReferences(g2s2, g2_children, 1);
1935 }
1936 // Do a full GC
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001937 HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001938
1939 // All object should be alive.
1940 CHECK_EQ(0, NumberOfWeakCalls);
1941
1942 // Weaken the root.
1943 root.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1944 // But make children strong roots---all the objects (except for children)
1945 // should be collectable now.
1946 g1c1.ClearWeak();
1947 g2c1.ClearWeak();
1948
1949 // Groups are deleted, rebuild groups.
1950 {
1951 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
1952 Persistent<Value> g1_children[] = { g1c1 };
1953 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
1954 Persistent<Value> g2_children[] = { g2c1 };
1955 V8::AddObjectGroup(g1_objects, 2);
1956 V8::AddImplicitReferences(g1s1, g1_children, 1);
1957 V8::AddObjectGroup(g2_objects, 2);
1958 V8::AddImplicitReferences(g2s2, g2_children, 1);
1959 }
1960
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001961 HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001962
1963 // All objects should be gone. 5 global handles in total.
1964 CHECK_EQ(5, NumberOfWeakCalls);
1965
1966 // And now make children weak again and collect them.
1967 g1c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1968 g2c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1969
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001970 HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001971 CHECK_EQ(7, NumberOfWeakCalls);
1972}
1973
1974
1975THREADED_TEST(ApiObjectGroupsCycle) {
1976 HandleScope scope;
1977 LocalContext env;
1978
1979 NumberOfWeakCalls = 0;
1980
1981 Persistent<Object> g1s1;
1982 Persistent<Object> g1s2;
1983 Persistent<Object> g2s1;
1984 Persistent<Object> g2s2;
1985 Persistent<Object> g3s1;
1986 Persistent<Object> g3s2;
1987
1988 {
1989 HandleScope scope;
1990 g1s1 = Persistent<Object>::New(Object::New());
1991 g1s2 = Persistent<Object>::New(Object::New());
1992 g1s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1993 g1s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1994
1995 g2s1 = Persistent<Object>::New(Object::New());
1996 g2s2 = Persistent<Object>::New(Object::New());
1997 g2s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1998 g2s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1999
2000 g3s1 = Persistent<Object>::New(Object::New());
2001 g3s2 = Persistent<Object>::New(Object::New());
2002 g3s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
2003 g3s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
2004 }
2005
2006 Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
2007
2008 // Connect groups. We're building the following cycle:
2009 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
2010 // groups.
2011 {
2012 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2013 Persistent<Value> g1_children[] = { g2s1 };
2014 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2015 Persistent<Value> g2_children[] = { g3s1 };
2016 Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2017 Persistent<Value> g3_children[] = { g1s1 };
2018 V8::AddObjectGroup(g1_objects, 2);
2019 V8::AddImplicitReferences(g1s1, g1_children, 1);
2020 V8::AddObjectGroup(g2_objects, 2);
2021 V8::AddImplicitReferences(g2s1, g2_children, 1);
2022 V8::AddObjectGroup(g3_objects, 2);
2023 V8::AddImplicitReferences(g3s1, g3_children, 1);
2024 }
2025 // Do a full GC
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002026 HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002027
2028 // All object should be alive.
2029 CHECK_EQ(0, NumberOfWeakCalls);
2030
2031 // Weaken the root.
2032 root.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
2033
2034 // Groups are deleted, rebuild groups.
2035 {
2036 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2037 Persistent<Value> g1_children[] = { g2s1 };
2038 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2039 Persistent<Value> g2_children[] = { g3s1 };
2040 Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2041 Persistent<Value> g3_children[] = { g1s1 };
2042 V8::AddObjectGroup(g1_objects, 2);
2043 V8::AddImplicitReferences(g1s1, g1_children, 1);
2044 V8::AddObjectGroup(g2_objects, 2);
2045 V8::AddImplicitReferences(g2s1, g2_children, 1);
2046 V8::AddObjectGroup(g3_objects, 2);
2047 V8::AddImplicitReferences(g3s1, g3_children, 1);
2048 }
2049
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002050 HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002051
2052 // All objects should be gone. 7 global handles in total.
2053 CHECK_EQ(7, NumberOfWeakCalls);
2054}
2055
2056
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002057THREADED_TEST(ScriptException) {
2058 v8::HandleScope scope;
2059 LocalContext env;
2060 Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
2061 v8::TryCatch try_catch;
2062 Local<Value> result = script->Run();
2063 CHECK(result.IsEmpty());
2064 CHECK(try_catch.HasCaught());
2065 String::AsciiValue exception_value(try_catch.Exception());
2066 CHECK_EQ(*exception_value, "panama!");
2067}
2068
2069
2070bool message_received;
2071
2072
2073static void check_message(v8::Handle<v8::Message> message,
2074 v8::Handle<Value> data) {
2075 CHECK_EQ(5.76, data->NumberValue());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002076 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002077 CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002078 message_received = true;
2079}
2080
2081
2082THREADED_TEST(MessageHandlerData) {
2083 message_received = false;
2084 v8::HandleScope scope;
2085 CHECK(!message_received);
2086 v8::V8::AddMessageListener(check_message, v8_num(5.76));
2087 LocalContext context;
2088 v8::ScriptOrigin origin =
2089 v8::ScriptOrigin(v8_str("6.75"));
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002090 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
2091 &origin);
2092 script->SetData(v8_str("7.56"));
2093 script->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002094 CHECK(message_received);
2095 // clear out the message listener
2096 v8::V8::RemoveMessageListeners(check_message);
2097}
2098
2099
2100THREADED_TEST(GetSetProperty) {
2101 v8::HandleScope scope;
2102 LocalContext context;
2103 context->Global()->Set(v8_str("foo"), v8_num(14));
2104 context->Global()->Set(v8_str("12"), v8_num(92));
2105 context->Global()->Set(v8::Integer::New(16), v8_num(32));
2106 context->Global()->Set(v8_num(13), v8_num(56));
2107 Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
2108 CHECK_EQ(14, foo->Int32Value());
2109 Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
2110 CHECK_EQ(92, twelve->Int32Value());
2111 Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
2112 CHECK_EQ(32, sixteen->Int32Value());
2113 Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
2114 CHECK_EQ(56, thirteen->Int32Value());
2115 CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
2116 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
2117 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
2118 CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
2119 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
2120 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
2121 CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
2122 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
2123 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
2124}
2125
2126
2127THREADED_TEST(PropertyAttributes) {
2128 v8::HandleScope scope;
2129 LocalContext context;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002130 // none
2131 Local<String> prop = v8_str("none");
2132 context->Global()->Set(prop, v8_num(7));
2133 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002134 // read-only
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002135 prop = v8_str("read_only");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002136 context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
2137 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002138 CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002139 Script::Compile(v8_str("read_only = 9"))->Run();
2140 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2141 context->Global()->Set(prop, v8_num(10));
2142 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2143 // dont-delete
2144 prop = v8_str("dont_delete");
2145 context->Global()->Set(prop, v8_num(13), v8::DontDelete);
2146 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
2147 Script::Compile(v8_str("delete dont_delete"))->Run();
2148 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002149 CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
2150 // dont-enum
2151 prop = v8_str("dont_enum");
2152 context->Global()->Set(prop, v8_num(28), v8::DontEnum);
2153 CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
2154 // absent
2155 prop = v8_str("absent");
2156 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
2157 Local<Value> fake_prop = v8_num(1);
2158 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
2159 // exception
2160 TryCatch try_catch;
2161 Local<Value> exception =
2162 CompileRun("({ toString: function() { throw 'exception';} })");
2163 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
2164 CHECK(try_catch.HasCaught());
2165 String::AsciiValue exception_value(try_catch.Exception());
2166 CHECK_EQ("exception", *exception_value);
2167 try_catch.Reset();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002168}
2169
2170
2171THREADED_TEST(Array) {
2172 v8::HandleScope scope;
2173 LocalContext context;
2174 Local<v8::Array> array = v8::Array::New();
2175 CHECK_EQ(0, array->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002176 CHECK(array->Get(0)->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002177 CHECK(!array->Has(0));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002178 CHECK(array->Get(100)->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002179 CHECK(!array->Has(100));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002180 array->Set(2, v8_num(7));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002181 CHECK_EQ(3, array->Length());
2182 CHECK(!array->Has(0));
2183 CHECK(!array->Has(1));
2184 CHECK(array->Has(2));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002185 CHECK_EQ(7, array->Get(2)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002186 Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002187 Local<v8::Array> arr = obj.As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002188 CHECK_EQ(3, arr->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002189 CHECK_EQ(1, arr->Get(0)->Int32Value());
2190 CHECK_EQ(2, arr->Get(1)->Int32Value());
2191 CHECK_EQ(3, arr->Get(2)->Int32Value());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002192 array = v8::Array::New(27);
2193 CHECK_EQ(27, array->Length());
2194 array = v8::Array::New(-27);
2195 CHECK_EQ(0, array->Length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002196}
2197
2198
2199v8::Handle<Value> HandleF(const v8::Arguments& args) {
2200 v8::HandleScope scope;
2201 ApiTestFuzzer::Fuzz();
2202 Local<v8::Array> result = v8::Array::New(args.Length());
2203 for (int i = 0; i < args.Length(); i++)
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002204 result->Set(i, args[i]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002205 return scope.Close(result);
2206}
2207
2208
2209THREADED_TEST(Vector) {
2210 v8::HandleScope scope;
2211 Local<ObjectTemplate> global = ObjectTemplate::New();
2212 global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
2213 LocalContext context(0, global);
2214
2215 const char* fun = "f()";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002216 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002217 CHECK_EQ(0, a0->Length());
2218
2219 const char* fun2 = "f(11)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002220 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002221 CHECK_EQ(1, a1->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002222 CHECK_EQ(11, a1->Get(0)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002223
2224 const char* fun3 = "f(12, 13)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002225 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002226 CHECK_EQ(2, a2->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002227 CHECK_EQ(12, a2->Get(0)->Int32Value());
2228 CHECK_EQ(13, a2->Get(1)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002229
2230 const char* fun4 = "f(14, 15, 16)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002231 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002232 CHECK_EQ(3, a3->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002233 CHECK_EQ(14, a3->Get(0)->Int32Value());
2234 CHECK_EQ(15, a3->Get(1)->Int32Value());
2235 CHECK_EQ(16, a3->Get(2)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002236
2237 const char* fun5 = "f(17, 18, 19, 20)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002238 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002239 CHECK_EQ(4, a4->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002240 CHECK_EQ(17, a4->Get(0)->Int32Value());
2241 CHECK_EQ(18, a4->Get(1)->Int32Value());
2242 CHECK_EQ(19, a4->Get(2)->Int32Value());
2243 CHECK_EQ(20, a4->Get(3)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002244}
2245
2246
2247THREADED_TEST(FunctionCall) {
2248 v8::HandleScope scope;
2249 LocalContext context;
2250 CompileRun(
2251 "function Foo() {"
2252 " var result = [];"
2253 " for (var i = 0; i < arguments.length; i++) {"
2254 " result.push(arguments[i]);"
2255 " }"
2256 " return result;"
2257 "}");
2258 Local<Function> Foo =
2259 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2260
2261 v8::Handle<Value>* args0 = NULL;
2262 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
2263 CHECK_EQ(0, a0->Length());
2264
2265 v8::Handle<Value> args1[] = { v8_num(1.1) };
2266 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
2267 CHECK_EQ(1, a1->Length());
2268 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2269
2270 v8::Handle<Value> args2[] = { v8_num(2.2),
2271 v8_num(3.3) };
2272 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
2273 CHECK_EQ(2, a2->Length());
2274 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2275 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2276
2277 v8::Handle<Value> args3[] = { v8_num(4.4),
2278 v8_num(5.5),
2279 v8_num(6.6) };
2280 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
2281 CHECK_EQ(3, a3->Length());
2282 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2283 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2284 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2285
2286 v8::Handle<Value> args4[] = { v8_num(7.7),
2287 v8_num(8.8),
2288 v8_num(9.9),
2289 v8_num(10.11) };
2290 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
2291 CHECK_EQ(4, a4->Length());
2292 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2293 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2294 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2295 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2296}
2297
2298
2299static const char* js_code_causing_out_of_memory =
2300 "var a = new Array(); while(true) a.push(a);";
2301
2302
2303// These tests run for a long time and prevent us from running tests
2304// that come after them so they cannot run in parallel.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002305TEST(OutOfMemory) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002306 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002307 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002308 // Set heap limits.
2309 static const int K = 1024;
2310 v8::ResourceConstraints constraints;
2311 constraints.set_max_young_space_size(256 * K);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002312 constraints.set_max_old_space_size(4 * K * K);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002313 v8::SetResourceConstraints(&constraints);
2314
2315 // Execute a script that causes out of memory.
2316 v8::HandleScope scope;
2317 LocalContext context;
2318 v8::V8::IgnoreOutOfMemoryException();
2319 Local<Script> script =
2320 Script::Compile(String::New(js_code_causing_out_of_memory));
2321 Local<Value> result = script->Run();
2322
2323 // Check for out of memory state.
2324 CHECK(result.IsEmpty());
2325 CHECK(context->HasOutOfMemoryException());
2326}
2327
2328
2329v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
2330 ApiTestFuzzer::Fuzz();
2331
2332 v8::HandleScope scope;
2333 LocalContext context;
2334 Local<Script> script =
2335 Script::Compile(String::New(js_code_causing_out_of_memory));
2336 Local<Value> result = script->Run();
2337
2338 // Check for out of memory state.
2339 CHECK(result.IsEmpty());
2340 CHECK(context->HasOutOfMemoryException());
2341
2342 return result;
2343}
2344
2345
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002346TEST(OutOfMemoryNested) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002347 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002348 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002349 // Set heap limits.
2350 static const int K = 1024;
2351 v8::ResourceConstraints constraints;
2352 constraints.set_max_young_space_size(256 * K);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002353 constraints.set_max_old_space_size(4 * K * K);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002354 v8::SetResourceConstraints(&constraints);
2355
2356 v8::HandleScope scope;
2357 Local<ObjectTemplate> templ = ObjectTemplate::New();
2358 templ->Set(v8_str("ProvokeOutOfMemory"),
2359 v8::FunctionTemplate::New(ProvokeOutOfMemory));
2360 LocalContext context(0, templ);
2361 v8::V8::IgnoreOutOfMemoryException();
2362 Local<Value> result = CompileRun(
2363 "var thrown = false;"
2364 "try {"
2365 " ProvokeOutOfMemory();"
2366 "} catch (e) {"
2367 " thrown = true;"
2368 "}");
2369 // Check for out of memory state.
2370 CHECK(result.IsEmpty());
2371 CHECK(context->HasOutOfMemoryException());
2372}
2373
2374
2375TEST(HugeConsStringOutOfMemory) {
2376 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002377 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002378 // Set heap limits.
2379 static const int K = 1024;
2380 v8::ResourceConstraints constraints;
2381 constraints.set_max_young_space_size(256 * K);
2382 constraints.set_max_old_space_size(2 * K * K);
2383 v8::SetResourceConstraints(&constraints);
2384
2385 // Execute a script that causes out of memory.
2386 v8::V8::IgnoreOutOfMemoryException();
2387
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002388 v8::HandleScope scope;
2389 LocalContext context;
2390
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002391 // Build huge string. This should fail with out of memory exception.
2392 Local<Value> result = CompileRun(
2393 "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002394 "for (var i = 0; i < 22; i++) { str = str + str; }");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002395
2396 // Check for out of memory state.
2397 CHECK(result.IsEmpty());
2398 CHECK(context->HasOutOfMemoryException());
2399}
2400
2401
2402THREADED_TEST(ConstructCall) {
2403 v8::HandleScope scope;
2404 LocalContext context;
2405 CompileRun(
2406 "function Foo() {"
2407 " var result = [];"
2408 " for (var i = 0; i < arguments.length; i++) {"
2409 " result.push(arguments[i]);"
2410 " }"
2411 " return result;"
2412 "}");
2413 Local<Function> Foo =
2414 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2415
2416 v8::Handle<Value>* args0 = NULL;
2417 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
2418 CHECK_EQ(0, a0->Length());
2419
2420 v8::Handle<Value> args1[] = { v8_num(1.1) };
2421 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
2422 CHECK_EQ(1, a1->Length());
2423 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2424
2425 v8::Handle<Value> args2[] = { v8_num(2.2),
2426 v8_num(3.3) };
2427 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
2428 CHECK_EQ(2, a2->Length());
2429 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2430 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2431
2432 v8::Handle<Value> args3[] = { v8_num(4.4),
2433 v8_num(5.5),
2434 v8_num(6.6) };
2435 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
2436 CHECK_EQ(3, a3->Length());
2437 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2438 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2439 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2440
2441 v8::Handle<Value> args4[] = { v8_num(7.7),
2442 v8_num(8.8),
2443 v8_num(9.9),
2444 v8_num(10.11) };
2445 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
2446 CHECK_EQ(4, a4->Length());
2447 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2448 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2449 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2450 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2451}
2452
2453
2454static void CheckUncle(v8::TryCatch* try_catch) {
2455 CHECK(try_catch->HasCaught());
2456 String::AsciiValue str_value(try_catch->Exception());
2457 CHECK_EQ(*str_value, "uncle?");
2458 try_catch->Reset();
2459}
2460
2461
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002462THREADED_TEST(ConversionNumber) {
2463 v8::HandleScope scope;
2464 LocalContext env;
2465 // Very large number.
2466 CompileRun("var obj = Math.pow(2,32) * 1237;");
2467 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2468 CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
2469 CHECK_EQ(0, obj->ToInt32()->Value());
2470 CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned.
2471 // Large number.
2472 CompileRun("var obj = -1234567890123;");
2473 obj = env->Global()->Get(v8_str("obj"));
2474 CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
2475 CHECK_EQ(-1912276171, obj->ToInt32()->Value());
2476 CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT
2477 // Small positive integer.
2478 CompileRun("var obj = 42;");
2479 obj = env->Global()->Get(v8_str("obj"));
2480 CHECK_EQ(42.0, obj->ToNumber()->Value());
2481 CHECK_EQ(42, obj->ToInt32()->Value());
2482 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
2483 // Negative integer.
2484 CompileRun("var obj = -37;");
2485 obj = env->Global()->Get(v8_str("obj"));
2486 CHECK_EQ(-37.0, obj->ToNumber()->Value());
2487 CHECK_EQ(-37, obj->ToInt32()->Value());
2488 CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT
2489 // Positive non-int32 integer.
2490 CompileRun("var obj = 0x81234567;");
2491 obj = env->Global()->Get(v8_str("obj"));
2492 CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
2493 CHECK_EQ(-2128394905, obj->ToInt32()->Value());
2494 CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT
2495 // Fraction.
2496 CompileRun("var obj = 42.3;");
2497 obj = env->Global()->Get(v8_str("obj"));
2498 CHECK_EQ(42.3, obj->ToNumber()->Value());
2499 CHECK_EQ(42, obj->ToInt32()->Value());
2500 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
2501 // Large negative fraction.
2502 CompileRun("var obj = -5726623061.75;");
2503 obj = env->Global()->Get(v8_str("obj"));
2504 CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
2505 CHECK_EQ(-1431655765, obj->ToInt32()->Value());
2506 CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT
2507}
2508
2509
2510THREADED_TEST(isNumberType) {
2511 v8::HandleScope scope;
2512 LocalContext env;
2513 // Very large number.
2514 CompileRun("var obj = Math.pow(2,32) * 1237;");
2515 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2516 CHECK(!obj->IsInt32());
2517 CHECK(!obj->IsUint32());
2518 // Large negative number.
2519 CompileRun("var obj = -1234567890123;");
2520 obj = env->Global()->Get(v8_str("obj"));
2521 CHECK(!obj->IsInt32());
2522 CHECK(!obj->IsUint32());
2523 // Small positive integer.
2524 CompileRun("var obj = 42;");
2525 obj = env->Global()->Get(v8_str("obj"));
2526 CHECK(obj->IsInt32());
2527 CHECK(obj->IsUint32());
2528 // Negative integer.
2529 CompileRun("var obj = -37;");
2530 obj = env->Global()->Get(v8_str("obj"));
2531 CHECK(obj->IsInt32());
2532 CHECK(!obj->IsUint32());
2533 // Positive non-int32 integer.
2534 CompileRun("var obj = 0x81234567;");
2535 obj = env->Global()->Get(v8_str("obj"));
2536 CHECK(!obj->IsInt32());
2537 CHECK(obj->IsUint32());
2538 // Fraction.
2539 CompileRun("var obj = 42.3;");
2540 obj = env->Global()->Get(v8_str("obj"));
2541 CHECK(!obj->IsInt32());
2542 CHECK(!obj->IsUint32());
2543 // Large negative fraction.
2544 CompileRun("var obj = -5726623061.75;");
2545 obj = env->Global()->Get(v8_str("obj"));
2546 CHECK(!obj->IsInt32());
2547 CHECK(!obj->IsUint32());
2548}
2549
2550
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002551THREADED_TEST(ConversionException) {
2552 v8::HandleScope scope;
2553 LocalContext env;
2554 CompileRun(
2555 "function TestClass() { };"
2556 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
2557 "var obj = new TestClass();");
2558 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2559
2560 v8::TryCatch try_catch;
2561
2562 Local<Value> to_string_result = obj->ToString();
2563 CHECK(to_string_result.IsEmpty());
2564 CheckUncle(&try_catch);
2565
2566 Local<Value> to_number_result = obj->ToNumber();
2567 CHECK(to_number_result.IsEmpty());
2568 CheckUncle(&try_catch);
2569
2570 Local<Value> to_integer_result = obj->ToInteger();
2571 CHECK(to_integer_result.IsEmpty());
2572 CheckUncle(&try_catch);
2573
2574 Local<Value> to_uint32_result = obj->ToUint32();
2575 CHECK(to_uint32_result.IsEmpty());
2576 CheckUncle(&try_catch);
2577
2578 Local<Value> to_int32_result = obj->ToInt32();
2579 CHECK(to_int32_result.IsEmpty());
2580 CheckUncle(&try_catch);
2581
2582 Local<Value> to_object_result = v8::Undefined()->ToObject();
2583 CHECK(to_object_result.IsEmpty());
2584 CHECK(try_catch.HasCaught());
2585 try_catch.Reset();
2586
2587 int32_t int32_value = obj->Int32Value();
2588 CHECK_EQ(0, int32_value);
2589 CheckUncle(&try_catch);
2590
2591 uint32_t uint32_value = obj->Uint32Value();
2592 CHECK_EQ(0, uint32_value);
2593 CheckUncle(&try_catch);
2594
2595 double number_value = obj->NumberValue();
2596 CHECK_NE(0, IsNaN(number_value));
2597 CheckUncle(&try_catch);
2598
2599 int64_t integer_value = obj->IntegerValue();
2600 CHECK_EQ(0.0, static_cast<double>(integer_value));
2601 CheckUncle(&try_catch);
2602}
2603
2604
2605v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
2606 ApiTestFuzzer::Fuzz();
2607 return v8::ThrowException(v8_str("konto"));
2608}
2609
2610
ager@chromium.org8bb60582008-12-11 12:02:20 +00002611v8::Handle<Value> CCatcher(const v8::Arguments& args) {
2612 if (args.Length() < 1) return v8::Boolean::New(false);
2613 v8::HandleScope scope;
2614 v8::TryCatch try_catch;
ager@chromium.org71daaf62009-04-01 07:22:49 +00002615 Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
2616 CHECK(!try_catch.HasCaught() || result.IsEmpty());
ager@chromium.org8bb60582008-12-11 12:02:20 +00002617 return v8::Boolean::New(try_catch.HasCaught());
2618}
2619
2620
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002621THREADED_TEST(APICatch) {
2622 v8::HandleScope scope;
2623 Local<ObjectTemplate> templ = ObjectTemplate::New();
2624 templ->Set(v8_str("ThrowFromC"),
2625 v8::FunctionTemplate::New(ThrowFromC));
2626 LocalContext context(0, templ);
2627 CompileRun(
2628 "var thrown = false;"
2629 "try {"
2630 " ThrowFromC();"
2631 "} catch (e) {"
2632 " thrown = true;"
2633 "}");
2634 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
2635 CHECK(thrown->BooleanValue());
2636}
2637
2638
ager@chromium.org8bb60582008-12-11 12:02:20 +00002639THREADED_TEST(APIThrowTryCatch) {
2640 v8::HandleScope scope;
2641 Local<ObjectTemplate> templ = ObjectTemplate::New();
2642 templ->Set(v8_str("ThrowFromC"),
2643 v8::FunctionTemplate::New(ThrowFromC));
2644 LocalContext context(0, templ);
2645 v8::TryCatch try_catch;
2646 CompileRun("ThrowFromC();");
2647 CHECK(try_catch.HasCaught());
2648}
2649
2650
2651// Test that a try-finally block doesn't shadow a try-catch block
2652// when setting up an external handler.
ager@chromium.org71daaf62009-04-01 07:22:49 +00002653//
2654// BUG(271): Some of the exception propagation does not work on the
2655// ARM simulator because the simulator separates the C++ stack and the
2656// JS stack. This test therefore fails on the simulator. The test is
2657// not threaded to allow the threading tests to run on the simulator.
2658TEST(TryCatchInTryFinally) {
ager@chromium.org8bb60582008-12-11 12:02:20 +00002659 v8::HandleScope scope;
2660 Local<ObjectTemplate> templ = ObjectTemplate::New();
2661 templ->Set(v8_str("CCatcher"),
2662 v8::FunctionTemplate::New(CCatcher));
2663 LocalContext context(0, templ);
2664 Local<Value> result = CompileRun("try {"
2665 " try {"
2666 " CCatcher('throw 7;');"
2667 " } finally {"
2668 " }"
2669 "} catch (e) {"
2670 "}");
2671 CHECK(result->IsTrue());
2672}
2673
2674
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002675static void check_reference_error_message(
2676 v8::Handle<v8::Message> message,
2677 v8::Handle<v8::Value> data) {
2678 const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
2679 CHECK(message->Get()->Equals(v8_str(reference_error)));
2680}
2681
2682
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00002683static v8::Handle<Value> Fail(const v8::Arguments& args) {
2684 ApiTestFuzzer::Fuzz();
2685 CHECK(false);
2686 return v8::Undefined();
2687}
2688
2689
2690// Test that overwritten methods are not invoked on uncaught exception
2691// formatting. However, they are invoked when performing normal error
2692// string conversions.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002693TEST(APIThrowMessageOverwrittenToString) {
2694 v8::HandleScope scope;
2695 v8::V8::AddMessageListener(check_reference_error_message);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00002696 Local<ObjectTemplate> templ = ObjectTemplate::New();
2697 templ->Set(v8_str("fail"), v8::FunctionTemplate::New(Fail));
2698 LocalContext context(NULL, templ);
2699 CompileRun("asdf;");
2700 CompileRun("var limit = {};"
2701 "limit.valueOf = fail;"
2702 "Error.stackTraceLimit = limit;");
2703 CompileRun("asdf");
2704 CompileRun("Array.prototype.pop = fail;");
2705 CompileRun("Object.prototype.hasOwnProperty = fail;");
2706 CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
whesse@chromium.org7a392b32011-01-31 11:30:36 +00002707 CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
2708 CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002709 CompileRun("ReferenceError.prototype.toString ="
2710 " function() { return 'Whoops' }");
2711 CompileRun("asdf;");
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002712 CompileRun("ReferenceError.prototype.constructor.name = void 0;");
2713 CompileRun("asdf;");
2714 CompileRun("ReferenceError.prototype.constructor = void 0;");
2715 CompileRun("asdf;");
ager@chromium.org0ee099b2011-01-25 14:06:47 +00002716 CompileRun("ReferenceError.prototype.__proto__ = new Object();");
2717 CompileRun("asdf;");
2718 CompileRun("ReferenceError.prototype = new Object();");
2719 CompileRun("asdf;");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002720 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
2721 CHECK(string->Equals(v8_str("Whoops")));
ager@chromium.org378b34e2011-01-28 08:04:38 +00002722 CompileRun("ReferenceError.prototype.constructor = new Object();"
2723 "ReferenceError.prototype.constructor.name = 1;"
2724 "Number.prototype.toString = function() { return 'Whoops'; };"
2725 "ReferenceError.prototype.toString = Object.prototype.toString;");
2726 CompileRun("asdf;");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002727 v8::V8::RemoveMessageListeners(check_message);
2728}
2729
2730
ager@chromium.org8bb60582008-12-11 12:02:20 +00002731static void receive_message(v8::Handle<v8::Message> message,
2732 v8::Handle<v8::Value> data) {
ager@chromium.org71daaf62009-04-01 07:22:49 +00002733 message->Get();
ager@chromium.org8bb60582008-12-11 12:02:20 +00002734 message_received = true;
2735}
2736
2737
2738TEST(APIThrowMessage) {
2739 message_received = false;
2740 v8::HandleScope scope;
2741 v8::V8::AddMessageListener(receive_message);
2742 Local<ObjectTemplate> templ = ObjectTemplate::New();
2743 templ->Set(v8_str("ThrowFromC"),
2744 v8::FunctionTemplate::New(ThrowFromC));
2745 LocalContext context(0, templ);
2746 CompileRun("ThrowFromC();");
2747 CHECK(message_received);
2748 v8::V8::RemoveMessageListeners(check_message);
2749}
2750
2751
2752TEST(APIThrowMessageAndVerboseTryCatch) {
2753 message_received = false;
2754 v8::HandleScope scope;
2755 v8::V8::AddMessageListener(receive_message);
2756 Local<ObjectTemplate> templ = ObjectTemplate::New();
2757 templ->Set(v8_str("ThrowFromC"),
2758 v8::FunctionTemplate::New(ThrowFromC));
2759 LocalContext context(0, templ);
2760 v8::TryCatch try_catch;
2761 try_catch.SetVerbose(true);
ager@chromium.org71daaf62009-04-01 07:22:49 +00002762 Local<Value> result = CompileRun("ThrowFromC();");
ager@chromium.org8bb60582008-12-11 12:02:20 +00002763 CHECK(try_catch.HasCaught());
ager@chromium.org71daaf62009-04-01 07:22:49 +00002764 CHECK(result.IsEmpty());
ager@chromium.org8bb60582008-12-11 12:02:20 +00002765 CHECK(message_received);
2766 v8::V8::RemoveMessageListeners(check_message);
2767}
2768
2769
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002770TEST(APIStackOverflowAndVerboseTryCatch) {
2771 message_received = false;
2772 v8::HandleScope scope;
2773 v8::V8::AddMessageListener(receive_message);
2774 LocalContext context;
2775 v8::TryCatch try_catch;
2776 try_catch.SetVerbose(true);
2777 Local<Value> result = CompileRun("function foo() { foo(); } foo();");
2778 CHECK(try_catch.HasCaught());
2779 CHECK(result.IsEmpty());
2780 CHECK(message_received);
2781 v8::V8::RemoveMessageListeners(receive_message);
2782}
2783
2784
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002785THREADED_TEST(ExternalScriptException) {
2786 v8::HandleScope scope;
2787 Local<ObjectTemplate> templ = ObjectTemplate::New();
2788 templ->Set(v8_str("ThrowFromC"),
2789 v8::FunctionTemplate::New(ThrowFromC));
2790 LocalContext context(0, templ);
2791
2792 v8::TryCatch try_catch;
2793 Local<Script> script
2794 = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
2795 Local<Value> result = script->Run();
2796 CHECK(result.IsEmpty());
2797 CHECK(try_catch.HasCaught());
2798 String::AsciiValue exception_value(try_catch.Exception());
2799 CHECK_EQ("konto", *exception_value);
2800}
2801
2802
2803
2804v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
2805 ApiTestFuzzer::Fuzz();
2806 CHECK_EQ(4, args.Length());
2807 int count = args[0]->Int32Value();
2808 int cInterval = args[2]->Int32Value();
2809 if (count == 0) {
2810 return v8::ThrowException(v8_str("FromC"));
2811 } else {
2812 Local<v8::Object> global = Context::GetCurrent()->Global();
2813 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
2814 v8::Handle<Value> argv[] = { v8_num(count - 1),
2815 args[1],
2816 args[2],
2817 args[3] };
2818 if (count % cInterval == 0) {
2819 v8::TryCatch try_catch;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002820 Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002821 int expected = args[3]->Int32Value();
2822 if (try_catch.HasCaught()) {
2823 CHECK_EQ(expected, count);
ager@chromium.org71daaf62009-04-01 07:22:49 +00002824 CHECK(result.IsEmpty());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002825 CHECK(!i::Isolate::Current()->has_scheduled_exception());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002826 } else {
2827 CHECK_NE(expected, count);
2828 }
2829 return result;
2830 } else {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002831 return fun.As<Function>()->Call(global, 4, argv);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002832 }
2833 }
2834}
2835
2836
2837v8::Handle<Value> JSCheck(const v8::Arguments& args) {
2838 ApiTestFuzzer::Fuzz();
2839 CHECK_EQ(3, args.Length());
2840 bool equality = args[0]->BooleanValue();
2841 int count = args[1]->Int32Value();
2842 int expected = args[2]->Int32Value();
2843 if (equality) {
2844 CHECK_EQ(count, expected);
2845 } else {
2846 CHECK_NE(count, expected);
2847 }
2848 return v8::Undefined();
2849}
2850
2851
ager@chromium.org8bb60582008-12-11 12:02:20 +00002852THREADED_TEST(EvalInTryFinally) {
2853 v8::HandleScope scope;
2854 LocalContext context;
2855 v8::TryCatch try_catch;
2856 CompileRun("(function() {"
2857 " try {"
2858 " eval('asldkf (*&^&*^');"
2859 " } finally {"
2860 " return;"
2861 " }"
2862 "})()");
2863 CHECK(!try_catch.HasCaught());
2864}
2865
2866
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002867// This test works by making a stack of alternating JavaScript and C
2868// activations. These activations set up exception handlers with regular
2869// intervals, one interval for C activations and another for JavaScript
2870// activations. When enough activations have been created an exception is
2871// thrown and we check that the right activation catches the exception and that
2872// no other activations do. The right activation is always the topmost one with
2873// a handler, regardless of whether it is in JavaScript or C.
2874//
2875// The notation used to describe a test case looks like this:
2876//
2877// *JS[4] *C[3] @JS[2] C[1] JS[0]
2878//
2879// Each entry is an activation, either JS or C. The index is the count at that
2880// level. Stars identify activations with exception handlers, the @ identifies
2881// the exception handler that should catch the exception.
ager@chromium.org71daaf62009-04-01 07:22:49 +00002882//
2883// BUG(271): Some of the exception propagation does not work on the
2884// ARM simulator because the simulator separates the C++ stack and the
2885// JS stack. This test therefore fails on the simulator. The test is
2886// not threaded to allow the threading tests to run on the simulator.
2887TEST(ExceptionOrder) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002888 v8::HandleScope scope;
2889 Local<ObjectTemplate> templ = ObjectTemplate::New();
2890 templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
2891 templ->Set(v8_str("CThrowCountDown"),
2892 v8::FunctionTemplate::New(CThrowCountDown));
2893 LocalContext context(0, templ);
2894 CompileRun(
2895 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
2896 " if (count == 0) throw 'FromJS';"
2897 " if (count % jsInterval == 0) {"
2898 " try {"
2899 " var value = CThrowCountDown(count - 1,"
2900 " jsInterval,"
2901 " cInterval,"
2902 " expected);"
2903 " check(false, count, expected);"
2904 " return value;"
2905 " } catch (e) {"
2906 " check(true, count, expected);"
2907 " }"
2908 " } else {"
2909 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
2910 " }"
2911 "}");
2912 Local<Function> fun =
2913 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
2914
2915 const int argc = 4;
2916 // count jsInterval cInterval expected
2917
2918 // *JS[4] *C[3] @JS[2] C[1] JS[0]
2919 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
2920 fun->Call(fun, argc, a0);
2921
2922 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
2923 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
2924 fun->Call(fun, argc, a1);
2925
2926 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
2927 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
2928 fun->Call(fun, argc, a2);
2929
2930 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
2931 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
2932 fun->Call(fun, argc, a3);
2933
2934 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
2935 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
2936 fun->Call(fun, argc, a4);
2937
2938 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
2939 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
2940 fun->Call(fun, argc, a5);
2941}
2942
2943
2944v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
2945 ApiTestFuzzer::Fuzz();
2946 CHECK_EQ(1, args.Length());
2947 return v8::ThrowException(args[0]);
2948}
2949
2950
2951THREADED_TEST(ThrowValues) {
2952 v8::HandleScope scope;
2953 Local<ObjectTemplate> templ = ObjectTemplate::New();
2954 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
2955 LocalContext context(0, templ);
2956 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
2957 "function Run(obj) {"
2958 " try {"
2959 " Throw(obj);"
2960 " } catch (e) {"
2961 " return e;"
2962 " }"
2963 " return 'no exception';"
2964 "}"
2965 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
2966 CHECK_EQ(5, result->Length());
2967 CHECK(result->Get(v8::Integer::New(0))->IsString());
2968 CHECK(result->Get(v8::Integer::New(1))->IsNumber());
2969 CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
2970 CHECK(result->Get(v8::Integer::New(2))->IsNumber());
2971 CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
2972 CHECK(result->Get(v8::Integer::New(3))->IsNull());
2973 CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
2974}
2975
2976
2977THREADED_TEST(CatchZero) {
2978 v8::HandleScope scope;
2979 LocalContext context;
2980 v8::TryCatch try_catch;
2981 CHECK(!try_catch.HasCaught());
2982 Script::Compile(v8_str("throw 10"))->Run();
2983 CHECK(try_catch.HasCaught());
2984 CHECK_EQ(10, try_catch.Exception()->Int32Value());
2985 try_catch.Reset();
2986 CHECK(!try_catch.HasCaught());
2987 Script::Compile(v8_str("throw 0"))->Run();
2988 CHECK(try_catch.HasCaught());
2989 CHECK_EQ(0, try_catch.Exception()->Int32Value());
2990}
2991
2992
2993THREADED_TEST(CatchExceptionFromWith) {
2994 v8::HandleScope scope;
2995 LocalContext context;
2996 v8::TryCatch try_catch;
2997 CHECK(!try_catch.HasCaught());
2998 Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
2999 CHECK(try_catch.HasCaught());
3000}
3001
3002
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003003THREADED_TEST(TryCatchAndFinallyHidingException) {
3004 v8::HandleScope scope;
3005 LocalContext context;
3006 v8::TryCatch try_catch;
3007 CHECK(!try_catch.HasCaught());
3008 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
3009 CompileRun("f({toString: function() { throw 42; }});");
3010 CHECK(!try_catch.HasCaught());
3011}
3012
3013
3014v8::Handle<v8::Value> WithTryCatch(const v8::Arguments& args) {
3015 v8::TryCatch try_catch;
3016 return v8::Undefined();
3017}
3018
3019
3020THREADED_TEST(TryCatchAndFinally) {
3021 v8::HandleScope scope;
3022 LocalContext context;
3023 context->Global()->Set(
3024 v8_str("native_with_try_catch"),
3025 v8::FunctionTemplate::New(WithTryCatch)->GetFunction());
3026 v8::TryCatch try_catch;
3027 CHECK(!try_catch.HasCaught());
3028 CompileRun(
3029 "try {\n"
3030 " throw new Error('a');\n"
3031 "} finally {\n"
3032 " native_with_try_catch();\n"
3033 "}\n");
3034 CHECK(try_catch.HasCaught());
3035}
3036
3037
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003038THREADED_TEST(Equality) {
3039 v8::HandleScope scope;
3040 LocalContext context;
3041 // Check that equality works at all before relying on CHECK_EQ
3042 CHECK(v8_str("a")->Equals(v8_str("a")));
3043 CHECK(!v8_str("a")->Equals(v8_str("b")));
3044
3045 CHECK_EQ(v8_str("a"), v8_str("a"));
3046 CHECK_NE(v8_str("a"), v8_str("b"));
3047 CHECK_EQ(v8_num(1), v8_num(1));
3048 CHECK_EQ(v8_num(1.00), v8_num(1));
3049 CHECK_NE(v8_num(1), v8_num(2));
3050
3051 // Assume String is not symbol.
3052 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
3053 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
3054 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
3055 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
3056 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
3057 CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
3058 Local<Value> not_a_number = v8_num(i::OS::nan_value());
3059 CHECK(!not_a_number->StrictEquals(not_a_number));
3060 CHECK(v8::False()->StrictEquals(v8::False()));
3061 CHECK(!v8::False()->StrictEquals(v8::Undefined()));
3062
3063 v8::Handle<v8::Object> obj = v8::Object::New();
3064 v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
3065 CHECK(alias->StrictEquals(obj));
3066 alias.Dispose();
3067}
3068
3069
3070THREADED_TEST(MultiRun) {
3071 v8::HandleScope scope;
3072 LocalContext context;
3073 Local<Script> script = Script::Compile(v8_str("x"));
3074 for (int i = 0; i < 10; i++)
3075 script->Run();
3076}
3077
3078
3079static v8::Handle<Value> GetXValue(Local<String> name,
3080 const AccessorInfo& info) {
3081 ApiTestFuzzer::Fuzz();
3082 CHECK_EQ(info.Data(), v8_str("donut"));
3083 CHECK_EQ(name, v8_str("x"));
3084 return name;
3085}
3086
3087
3088THREADED_TEST(SimplePropertyRead) {
3089 v8::HandleScope scope;
3090 Local<ObjectTemplate> templ = ObjectTemplate::New();
3091 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3092 LocalContext context;
3093 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3094 Local<Script> script = Script::Compile(v8_str("obj.x"));
3095 for (int i = 0; i < 10; i++) {
3096 Local<Value> result = script->Run();
3097 CHECK_EQ(result, v8_str("x"));
3098 }
3099}
3100
ager@chromium.org5c838252010-02-19 08:53:10 +00003101THREADED_TEST(DefinePropertyOnAPIAccessor) {
3102 v8::HandleScope scope;
3103 Local<ObjectTemplate> templ = ObjectTemplate::New();
3104 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3105 LocalContext context;
3106 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3107
3108 // Uses getOwnPropertyDescriptor to check the configurable status
3109 Local<Script> script_desc
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003110 = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
ager@chromium.org5c838252010-02-19 08:53:10 +00003111 "obj, 'x');"
3112 "prop.configurable;"));
3113 Local<Value> result = script_desc->Run();
3114 CHECK_EQ(result->BooleanValue(), true);
3115
3116 // Redefine get - but still configurable
3117 Local<Script> script_define
3118 = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
3119 " configurable: true };"
3120 "Object.defineProperty(obj, 'x', desc);"
3121 "obj.x"));
3122 result = script_define->Run();
3123 CHECK_EQ(result, v8_num(42));
3124
3125 // Check that the accessor is still configurable
3126 result = script_desc->Run();
3127 CHECK_EQ(result->BooleanValue(), true);
3128
3129 // Redefine to a non-configurable
3130 script_define
3131 = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
3132 " configurable: false };"
3133 "Object.defineProperty(obj, 'x', desc);"
3134 "obj.x"));
3135 result = script_define->Run();
3136 CHECK_EQ(result, v8_num(43));
3137 result = script_desc->Run();
3138 CHECK_EQ(result->BooleanValue(), false);
3139
3140 // Make sure that it is not possible to redefine again
3141 v8::TryCatch try_catch;
3142 result = script_define->Run();
3143 CHECK(try_catch.HasCaught());
3144 String::AsciiValue exception_value(try_catch.Exception());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003145 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
ager@chromium.org5c838252010-02-19 08:53:10 +00003146}
3147
3148THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
3149 v8::HandleScope scope;
3150 Local<ObjectTemplate> templ = ObjectTemplate::New();
3151 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3152 LocalContext context;
3153 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3154
3155 Local<Script> script_desc = Script::Compile(v8_str("var prop ="
3156 "Object.getOwnPropertyDescriptor( "
3157 "obj, 'x');"
3158 "prop.configurable;"));
3159 Local<Value> result = script_desc->Run();
3160 CHECK_EQ(result->BooleanValue(), true);
3161
3162 Local<Script> script_define =
3163 Script::Compile(v8_str("var desc = {get: function(){return 42; },"
3164 " configurable: true };"
3165 "Object.defineProperty(obj, 'x', desc);"
3166 "obj.x"));
3167 result = script_define->Run();
3168 CHECK_EQ(result, v8_num(42));
3169
3170
3171 result = script_desc->Run();
3172 CHECK_EQ(result->BooleanValue(), true);
3173
3174
3175 script_define =
3176 Script::Compile(v8_str("var desc = {get: function(){return 43; },"
3177 " configurable: false };"
3178 "Object.defineProperty(obj, 'x', desc);"
3179 "obj.x"));
3180 result = script_define->Run();
3181 CHECK_EQ(result, v8_num(43));
3182 result = script_desc->Run();
3183
3184 CHECK_EQ(result->BooleanValue(), false);
3185
3186 v8::TryCatch try_catch;
3187 result = script_define->Run();
3188 CHECK(try_catch.HasCaught());
3189 String::AsciiValue exception_value(try_catch.Exception());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003190 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
ager@chromium.org5c838252010-02-19 08:53:10 +00003191}
3192
3193
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003194static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
3195 char const* name) {
3196 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
3197}
ager@chromium.org5c838252010-02-19 08:53:10 +00003198
3199
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003200THREADED_TEST(DefineAPIAccessorOnObject) {
3201 v8::HandleScope scope;
3202 Local<ObjectTemplate> templ = ObjectTemplate::New();
3203 LocalContext context;
3204
3205 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3206 CompileRun("var obj2 = {};");
3207
3208 CHECK(CompileRun("obj1.x")->IsUndefined());
3209 CHECK(CompileRun("obj2.x")->IsUndefined());
3210
3211 CHECK(GetGlobalProperty(&context, "obj1")->
3212 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3213
3214 ExpectString("obj1.x", "x");
3215 CHECK(CompileRun("obj2.x")->IsUndefined());
3216
3217 CHECK(GetGlobalProperty(&context, "obj2")->
3218 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3219
3220 ExpectString("obj1.x", "x");
3221 ExpectString("obj2.x", "x");
3222
3223 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3224 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3225
3226 CompileRun("Object.defineProperty(obj1, 'x',"
3227 "{ get: function() { return 'y'; }, configurable: true })");
3228
3229 ExpectString("obj1.x", "y");
3230 ExpectString("obj2.x", "x");
3231
3232 CompileRun("Object.defineProperty(obj2, 'x',"
3233 "{ get: function() { return 'y'; }, configurable: true })");
3234
3235 ExpectString("obj1.x", "y");
3236 ExpectString("obj2.x", "y");
3237
3238 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3239 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3240
3241 CHECK(GetGlobalProperty(&context, "obj1")->
3242 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3243 CHECK(GetGlobalProperty(&context, "obj2")->
3244 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3245
3246 ExpectString("obj1.x", "x");
3247 ExpectString("obj2.x", "x");
3248
3249 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3250 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3251
3252 // Define getters/setters, but now make them not configurable.
3253 CompileRun("Object.defineProperty(obj1, 'x',"
3254 "{ get: function() { return 'z'; }, configurable: false })");
3255 CompileRun("Object.defineProperty(obj2, 'x',"
3256 "{ get: function() { return 'z'; }, configurable: false })");
3257
3258 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3259 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3260
3261 ExpectString("obj1.x", "z");
3262 ExpectString("obj2.x", "z");
3263
3264 CHECK(!GetGlobalProperty(&context, "obj1")->
3265 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3266 CHECK(!GetGlobalProperty(&context, "obj2")->
3267 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3268
3269 ExpectString("obj1.x", "z");
3270 ExpectString("obj2.x", "z");
3271}
3272
3273
3274THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
3275 v8::HandleScope scope;
3276 Local<ObjectTemplate> templ = ObjectTemplate::New();
3277 LocalContext context;
3278
3279 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3280 CompileRun("var obj2 = {};");
3281
3282 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3283 v8_str("x"),
3284 GetXValue, NULL,
3285 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3286 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3287 v8_str("x"),
3288 GetXValue, NULL,
3289 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3290
3291 ExpectString("obj1.x", "x");
3292 ExpectString("obj2.x", "x");
3293
3294 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3295 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3296
3297 CHECK(!GetGlobalProperty(&context, "obj1")->
3298 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3299 CHECK(!GetGlobalProperty(&context, "obj2")->
3300 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3301
3302 {
3303 v8::TryCatch try_catch;
3304 CompileRun("Object.defineProperty(obj1, 'x',"
3305 "{get: function() { return 'func'; }})");
3306 CHECK(try_catch.HasCaught());
3307 String::AsciiValue exception_value(try_catch.Exception());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003308 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003309 }
3310 {
3311 v8::TryCatch try_catch;
3312 CompileRun("Object.defineProperty(obj2, 'x',"
3313 "{get: function() { return 'func'; }})");
3314 CHECK(try_catch.HasCaught());
3315 String::AsciiValue exception_value(try_catch.Exception());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003316 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003317 }
3318}
3319
3320
3321static v8::Handle<Value> Get239Value(Local<String> name,
3322 const AccessorInfo& info) {
3323 ApiTestFuzzer::Fuzz();
3324 CHECK_EQ(info.Data(), v8_str("donut"));
3325 CHECK_EQ(name, v8_str("239"));
3326 return name;
3327}
3328
3329
3330THREADED_TEST(ElementAPIAccessor) {
3331 v8::HandleScope scope;
3332 Local<ObjectTemplate> templ = ObjectTemplate::New();
3333 LocalContext context;
3334
3335 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3336 CompileRun("var obj2 = {};");
3337
3338 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3339 v8_str("239"),
3340 Get239Value, NULL,
3341 v8_str("donut")));
3342 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3343 v8_str("239"),
3344 Get239Value, NULL,
3345 v8_str("donut")));
3346
3347 ExpectString("obj1[239]", "239");
3348 ExpectString("obj2[239]", "239");
3349 ExpectString("obj1['239']", "239");
3350 ExpectString("obj2['239']", "239");
3351}
3352
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003353
3354v8::Persistent<Value> xValue;
3355
3356
3357static void SetXValue(Local<String> name,
3358 Local<Value> value,
3359 const AccessorInfo& info) {
3360 CHECK_EQ(value, v8_num(4));
3361 CHECK_EQ(info.Data(), v8_str("donut"));
3362 CHECK_EQ(name, v8_str("x"));
3363 CHECK(xValue.IsEmpty());
3364 xValue = v8::Persistent<Value>::New(value);
3365}
3366
3367
3368THREADED_TEST(SimplePropertyWrite) {
3369 v8::HandleScope scope;
3370 Local<ObjectTemplate> templ = ObjectTemplate::New();
3371 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
3372 LocalContext context;
3373 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3374 Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
3375 for (int i = 0; i < 10; i++) {
3376 CHECK(xValue.IsEmpty());
3377 script->Run();
3378 CHECK_EQ(v8_num(4), xValue);
3379 xValue.Dispose();
3380 xValue = v8::Persistent<Value>();
3381 }
3382}
3383
3384
3385static v8::Handle<Value> XPropertyGetter(Local<String> property,
3386 const AccessorInfo& info) {
3387 ApiTestFuzzer::Fuzz();
3388 CHECK(info.Data()->IsUndefined());
3389 return property;
3390}
3391
3392
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003393THREADED_TEST(NamedInterceptorPropertyRead) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003394 v8::HandleScope scope;
3395 Local<ObjectTemplate> templ = ObjectTemplate::New();
3396 templ->SetNamedPropertyHandler(XPropertyGetter);
3397 LocalContext context;
3398 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3399 Local<Script> script = Script::Compile(v8_str("obj.x"));
3400 for (int i = 0; i < 10; i++) {
3401 Local<Value> result = script->Run();
3402 CHECK_EQ(result, v8_str("x"));
3403 }
3404}
3405
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003406
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00003407THREADED_TEST(NamedInterceptorDictionaryIC) {
3408 v8::HandleScope scope;
3409 Local<ObjectTemplate> templ = ObjectTemplate::New();
3410 templ->SetNamedPropertyHandler(XPropertyGetter);
3411 LocalContext context;
3412 // Create an object with a named interceptor.
3413 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
3414 Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
3415 for (int i = 0; i < 10; i++) {
3416 Local<Value> result = script->Run();
3417 CHECK_EQ(result, v8_str("x"));
3418 }
3419 // Create a slow case object and a function accessing a property in
3420 // that slow case object (with dictionary probing in generated
3421 // code). Then force object with a named interceptor into slow-case,
3422 // pass it to the function, and check that the interceptor is called
3423 // instead of accessing the local property.
3424 Local<Value> result =
3425 CompileRun("function get_x(o) { return o.x; };"
3426 "var obj = { x : 42, y : 0 };"
3427 "delete obj.y;"
3428 "for (var i = 0; i < 10; i++) get_x(obj);"
3429 "interceptor_obj.x = 42;"
3430 "interceptor_obj.y = 10;"
3431 "delete interceptor_obj.y;"
3432 "get_x(interceptor_obj)");
3433 CHECK_EQ(result, v8_str("x"));
3434}
3435
3436
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003437THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
3438 v8::HandleScope scope;
3439
3440 v8::Persistent<Context> context1 = Context::New();
3441
3442 context1->Enter();
3443 Local<ObjectTemplate> templ = ObjectTemplate::New();
3444 templ->SetNamedPropertyHandler(XPropertyGetter);
3445 // Create an object with a named interceptor.
3446 v8::Local<v8::Object> object = templ->NewInstance();
3447 context1->Global()->Set(v8_str("interceptor_obj"), object);
3448
3449 // Force the object into the slow case.
3450 CompileRun("interceptor_obj.y = 0;"
3451 "delete interceptor_obj.y;");
3452 context1->Exit();
3453
3454 {
3455 // Introduce the object into a different context.
3456 // Repeat named loads to exercise ICs.
3457 LocalContext context2;
3458 context2->Global()->Set(v8_str("interceptor_obj"), object);
3459 Local<Value> result =
3460 CompileRun("function get_x(o) { return o.x; }"
3461 "interceptor_obj.x = 42;"
3462 "for (var i=0; i != 10; i++) {"
3463 " get_x(interceptor_obj);"
3464 "}"
3465 "get_x(interceptor_obj)");
3466 // Check that the interceptor was actually invoked.
3467 CHECK_EQ(result, v8_str("x"));
3468 }
3469
3470 // Return to the original context and force some object to the slow case
3471 // to cause the NormalizedMapCache to verify.
3472 context1->Enter();
3473 CompileRun("var obj = { x : 0 }; delete obj.x;");
3474 context1->Exit();
3475
3476 context1.Dispose();
3477}
3478
3479
ager@chromium.org5c838252010-02-19 08:53:10 +00003480static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
3481 const AccessorInfo& info) {
3482 // Set x on the prototype object and do not handle the get request.
3483 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003484 proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
ager@chromium.org5c838252010-02-19 08:53:10 +00003485 return v8::Handle<Value>();
3486}
3487
3488
3489// This is a regression test for http://crbug.com/20104. Map
3490// transitions should not interfere with post interceptor lookup.
3491THREADED_TEST(NamedInterceptorMapTransitionRead) {
3492 v8::HandleScope scope;
3493 Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
3494 Local<v8::ObjectTemplate> instance_template
3495 = function_template->InstanceTemplate();
3496 instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
3497 LocalContext context;
3498 context->Global()->Set(v8_str("F"), function_template->GetFunction());
3499 // Create an instance of F and introduce a map transition for x.
3500 CompileRun("var o = new F(); o.x = 23;");
3501 // Create an instance of F and invoke the getter. The result should be 23.
3502 Local<Value> result = CompileRun("o = new F(); o.x");
3503 CHECK_EQ(result->Int32Value(), 23);
3504}
3505
3506
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003507static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
3508 const AccessorInfo& info) {
3509 ApiTestFuzzer::Fuzz();
3510 if (index == 37) {
3511 return v8::Handle<Value>(v8_num(625));
3512 }
3513 return v8::Handle<Value>();
3514}
3515
3516
3517static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
3518 Local<Value> value,
3519 const AccessorInfo& info) {
3520 ApiTestFuzzer::Fuzz();
3521 if (index == 39) {
3522 return value;
3523 }
3524 return v8::Handle<Value>();
3525}
3526
3527
3528THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
3529 v8::HandleScope scope;
3530 Local<ObjectTemplate> templ = ObjectTemplate::New();
3531 templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
3532 IndexedPropertySetter);
3533 LocalContext context;
3534 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3535 Local<Script> getter_script = Script::Compile(v8_str(
3536 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
3537 Local<Script> setter_script = Script::Compile(v8_str(
3538 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
3539 "obj[17] = 23;"
3540 "obj.foo;"));
3541 Local<Script> interceptor_setter_script = Script::Compile(v8_str(
3542 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
3543 "obj[39] = 47;"
3544 "obj.foo;")); // This setter should not run, due to the interceptor.
3545 Local<Script> interceptor_getter_script = Script::Compile(v8_str(
3546 "obj[37];"));
3547 Local<Value> result = getter_script->Run();
3548 CHECK_EQ(v8_num(5), result);
3549 result = setter_script->Run();
3550 CHECK_EQ(v8_num(23), result);
3551 result = interceptor_setter_script->Run();
3552 CHECK_EQ(v8_num(23), result);
3553 result = interceptor_getter_script->Run();
3554 CHECK_EQ(v8_num(625), result);
3555}
3556
3557
ricow@chromium.org9fa09672011-07-25 11:05:35 +00003558static v8::Handle<Value> UnboxedDoubleIndexedPropertyGetter(
3559 uint32_t index,
3560 const AccessorInfo& info) {
3561 ApiTestFuzzer::Fuzz();
3562 if (index < 25) {
3563 return v8::Handle<Value>(v8_num(index));
3564 }
3565 return v8::Handle<Value>();
3566}
3567
3568
3569static v8::Handle<Value> UnboxedDoubleIndexedPropertySetter(
3570 uint32_t index,
3571 Local<Value> value,
3572 const AccessorInfo& info) {
3573 ApiTestFuzzer::Fuzz();
3574 if (index < 25) {
3575 return v8::Handle<Value>(v8_num(index));
3576 }
3577 return v8::Handle<Value>();
3578}
3579
3580
3581Handle<v8::Array> UnboxedDoubleIndexedPropertyEnumerator(
3582 const AccessorInfo& info) {
3583 // Force the list of returned keys to be stored in a FastDoubleArray.
3584 Local<Script> indexed_property_names_script = Script::Compile(v8_str(
3585 "keys = new Array(); keys[125000] = 1;"
3586 "for(i = 0; i < 80000; i++) { keys[i] = i; };"
3587 "keys.length = 25; keys;"));
3588 Local<Value> result = indexed_property_names_script->Run();
3589 return Local<v8::Array>(::v8::Array::Cast(*result));
3590}
3591
3592
3593// Make sure that the the interceptor code in the runtime properly handles
3594// merging property name lists for double-array-backed arrays.
3595THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
3596 v8::HandleScope scope;
3597 Local<ObjectTemplate> templ = ObjectTemplate::New();
3598 templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
3599 UnboxedDoubleIndexedPropertySetter,
3600 0,
3601 0,
3602 UnboxedDoubleIndexedPropertyEnumerator);
3603 LocalContext context;
3604 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3605 // When obj is created, force it to be Stored in a FastDoubleArray.
3606 Local<Script> create_unboxed_double_script = Script::Compile(v8_str(
3607 "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
3608 "key_count = 0; "
3609 "for (x in obj) {key_count++;};"
3610 "obj;"));
3611 Local<Value> result = create_unboxed_double_script->Run();
3612 CHECK(result->ToObject()->HasRealIndexedProperty(2000));
3613 Local<Script> key_count_check = Script::Compile(v8_str(
3614 "key_count;"));
3615 result = key_count_check->Run();
3616 CHECK_EQ(v8_num(40013), result);
3617}
3618
3619
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00003620static v8::Handle<Value> IdentityIndexedPropertyGetter(
3621 uint32_t index,
3622 const AccessorInfo& info) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003623 return v8::Integer::NewFromUnsigned(index);
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00003624}
3625
3626
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003627THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
3628 v8::HandleScope scope;
3629 Local<ObjectTemplate> templ = ObjectTemplate::New();
3630 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3631
3632 LocalContext context;
3633 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3634
3635 // Check fast object case.
3636 const char* fast_case_code =
3637 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
3638 ExpectString(fast_case_code, "0");
3639
3640 // Check slow case.
3641 const char* slow_case_code =
3642 "obj.x = 1; delete obj.x;"
3643 "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
3644 ExpectString(slow_case_code, "1");
3645}
3646
3647
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00003648THREADED_TEST(IndexedInterceptorWithNoSetter) {
3649 v8::HandleScope scope;
3650 Local<ObjectTemplate> templ = ObjectTemplate::New();
3651 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3652
3653 LocalContext context;
3654 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3655
3656 const char* code =
3657 "try {"
3658 " obj[0] = 239;"
3659 " for (var i = 0; i < 100; i++) {"
3660 " var v = obj[0];"
3661 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
3662 " }"
3663 " 'PASSED'"
3664 "} catch(e) {"
3665 " e"
3666 "}";
3667 ExpectString(code, "PASSED");
3668}
3669
3670
ager@chromium.org5c838252010-02-19 08:53:10 +00003671THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
3672 v8::HandleScope scope;
3673 Local<ObjectTemplate> templ = ObjectTemplate::New();
3674 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3675
3676 LocalContext context;
3677 Local<v8::Object> obj = templ->NewInstance();
3678 obj->TurnOnAccessCheck();
3679 context->Global()->Set(v8_str("obj"), obj);
3680
3681 const char* code =
3682 "try {"
3683 " for (var i = 0; i < 100; i++) {"
3684 " var v = obj[0];"
3685 " if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
3686 " }"
3687 " 'PASSED'"
3688 "} catch(e) {"
3689 " e"
3690 "}";
3691 ExpectString(code, "PASSED");
3692}
3693
3694
3695THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
3696 i::FLAG_allow_natives_syntax = true;
3697 v8::HandleScope scope;
3698 Local<ObjectTemplate> templ = ObjectTemplate::New();
3699 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3700
3701 LocalContext context;
3702 Local<v8::Object> obj = templ->NewInstance();
3703 context->Global()->Set(v8_str("obj"), obj);
3704
3705 const char* code =
3706 "try {"
3707 " for (var i = 0; i < 100; i++) {"
3708 " var expected = i;"
3709 " if (i == 5) {"
3710 " %EnableAccessChecks(obj);"
3711 " expected = undefined;"
3712 " }"
3713 " var v = obj[i];"
3714 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3715 " if (i == 5) %DisableAccessChecks(obj);"
3716 " }"
3717 " 'PASSED'"
3718 "} catch(e) {"
3719 " e"
3720 "}";
3721 ExpectString(code, "PASSED");
3722}
3723
3724
3725THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
3726 v8::HandleScope scope;
3727 Local<ObjectTemplate> templ = ObjectTemplate::New();
3728 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3729
3730 LocalContext context;
3731 Local<v8::Object> obj = templ->NewInstance();
3732 context->Global()->Set(v8_str("obj"), obj);
3733
3734 const char* code =
3735 "try {"
3736 " for (var i = 0; i < 100; i++) {"
3737 " var v = obj[i];"
3738 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
3739 " }"
3740 " 'PASSED'"
3741 "} catch(e) {"
3742 " e"
3743 "}";
3744 ExpectString(code, "PASSED");
3745}
3746
3747
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003748THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
3749 v8::HandleScope scope;
3750 Local<ObjectTemplate> templ = ObjectTemplate::New();
3751 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3752
3753 LocalContext context;
3754 Local<v8::Object> obj = templ->NewInstance();
3755 context->Global()->Set(v8_str("obj"), obj);
3756
3757 const char* code =
3758 "try {"
3759 " for (var i = 0; i < 100; i++) {"
3760 " var expected = i;"
3761 " var key = i;"
3762 " if (i == 25) {"
3763 " key = -1;"
3764 " expected = undefined;"
3765 " }"
3766 " if (i == 50) {"
3767 " /* probe minimal Smi number on 32-bit platforms */"
3768 " key = -(1 << 30);"
3769 " expected = undefined;"
3770 " }"
3771 " if (i == 75) {"
3772 " /* probe minimal Smi number on 64-bit platforms */"
3773 " key = 1 << 31;"
3774 " expected = undefined;"
3775 " }"
3776 " var v = obj[key];"
3777 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3778 " }"
3779 " 'PASSED'"
3780 "} catch(e) {"
3781 " e"
3782 "}";
3783 ExpectString(code, "PASSED");
3784}
3785
3786
ager@chromium.org5c838252010-02-19 08:53:10 +00003787THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
3788 v8::HandleScope scope;
3789 Local<ObjectTemplate> templ = ObjectTemplate::New();
3790 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3791
3792 LocalContext context;
3793 Local<v8::Object> obj = templ->NewInstance();
3794 context->Global()->Set(v8_str("obj"), obj);
3795
3796 const char* code =
3797 "try {"
3798 " for (var i = 0; i < 100; i++) {"
3799 " var expected = i;"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003800 " var key = i;"
ager@chromium.org5c838252010-02-19 08:53:10 +00003801 " if (i == 50) {"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003802 " key = 'foobar';"
ager@chromium.org5c838252010-02-19 08:53:10 +00003803 " expected = undefined;"
3804 " }"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003805 " var v = obj[key];"
ager@chromium.org5c838252010-02-19 08:53:10 +00003806 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3807 " }"
3808 " 'PASSED'"
3809 "} catch(e) {"
3810 " e"
3811 "}";
3812 ExpectString(code, "PASSED");
3813}
3814
3815
3816THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
3817 v8::HandleScope scope;
3818 Local<ObjectTemplate> templ = ObjectTemplate::New();
3819 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3820
3821 LocalContext context;
3822 Local<v8::Object> obj = templ->NewInstance();
3823 context->Global()->Set(v8_str("obj"), obj);
3824
3825 const char* code =
3826 "var original = obj;"
3827 "try {"
3828 " for (var i = 0; i < 100; i++) {"
3829 " var expected = i;"
3830 " if (i == 50) {"
3831 " obj = {50: 'foobar'};"
3832 " expected = 'foobar';"
3833 " }"
3834 " var v = obj[i];"
3835 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3836 " if (i == 50) obj = original;"
3837 " }"
3838 " 'PASSED'"
3839 "} catch(e) {"
3840 " e"
3841 "}";
3842 ExpectString(code, "PASSED");
3843}
3844
3845
3846THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
3847 v8::HandleScope scope;
3848 Local<ObjectTemplate> templ = ObjectTemplate::New();
3849 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3850
3851 LocalContext context;
3852 Local<v8::Object> obj = templ->NewInstance();
3853 context->Global()->Set(v8_str("obj"), obj);
3854
3855 const char* code =
3856 "var original = obj;"
3857 "try {"
3858 " for (var i = 0; i < 100; i++) {"
3859 " var expected = i;"
3860 " if (i == 5) {"
3861 " obj = 239;"
3862 " expected = undefined;"
3863 " }"
3864 " var v = obj[i];"
3865 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3866 " if (i == 5) obj = original;"
3867 " }"
3868 " 'PASSED'"
3869 "} catch(e) {"
3870 " e"
3871 "}";
3872 ExpectString(code, "PASSED");
3873}
3874
3875
3876THREADED_TEST(IndexedInterceptorOnProto) {
3877 v8::HandleScope scope;
3878 Local<ObjectTemplate> templ = ObjectTemplate::New();
3879 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3880
3881 LocalContext context;
3882 Local<v8::Object> obj = templ->NewInstance();
3883 context->Global()->Set(v8_str("obj"), obj);
3884
3885 const char* code =
3886 "var o = {__proto__: obj};"
3887 "try {"
3888 " for (var i = 0; i < 100; i++) {"
3889 " var v = o[i];"
3890 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
3891 " }"
3892 " 'PASSED'"
3893 "} catch(e) {"
3894 " e"
3895 "}";
3896 ExpectString(code, "PASSED");
3897}
3898
3899
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003900THREADED_TEST(MultiContexts) {
3901 v8::HandleScope scope;
3902 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
3903 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
3904
3905 Local<String> password = v8_str("Password");
3906
3907 // Create an environment
3908 LocalContext context0(0, templ);
3909 context0->SetSecurityToken(password);
3910 v8::Handle<v8::Object> global0 = context0->Global();
3911 global0->Set(v8_str("custom"), v8_num(1234));
3912 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
3913
3914 // Create an independent environment
3915 LocalContext context1(0, templ);
3916 context1->SetSecurityToken(password);
3917 v8::Handle<v8::Object> global1 = context1->Global();
3918 global1->Set(v8_str("custom"), v8_num(1234));
3919 CHECK_NE(global0, global1);
3920 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
3921 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
3922
3923 // Now create a new context with the old global
3924 LocalContext context2(0, templ, global1);
3925 context2->SetSecurityToken(password);
3926 v8::Handle<v8::Object> global2 = context2->Global();
3927 CHECK_EQ(global1, global2);
3928 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
3929 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
3930}
3931
3932
3933THREADED_TEST(FunctionPrototypeAcrossContexts) {
3934 // Make sure that functions created by cloning boilerplates cannot
3935 // communicate through their __proto__ field.
3936
3937 v8::HandleScope scope;
3938
3939 LocalContext env0;
3940 v8::Handle<v8::Object> global0 =
3941 env0->Global();
3942 v8::Handle<v8::Object> object0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003943 global0->Get(v8_str("Object")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003944 v8::Handle<v8::Object> tostring0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003945 object0->Get(v8_str("toString")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003946 v8::Handle<v8::Object> proto0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003947 tostring0->Get(v8_str("__proto__")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003948 proto0->Set(v8_str("custom"), v8_num(1234));
3949
3950 LocalContext env1;
3951 v8::Handle<v8::Object> global1 =
3952 env1->Global();
3953 v8::Handle<v8::Object> object1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003954 global1->Get(v8_str("Object")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003955 v8::Handle<v8::Object> tostring1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003956 object1->Get(v8_str("toString")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003957 v8::Handle<v8::Object> proto1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003958 tostring1->Get(v8_str("__proto__")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003959 CHECK(!proto1->Has(v8_str("custom")));
3960}
3961
3962
3963THREADED_TEST(Regress892105) {
3964 // Make sure that object and array literals created by cloning
3965 // boilerplates cannot communicate through their __proto__
3966 // field. This is rather difficult to check, but we try to add stuff
3967 // to Object.prototype and Array.prototype and create a new
3968 // environment. This should succeed.
3969
3970 v8::HandleScope scope;
3971
3972 Local<String> source = v8_str("Object.prototype.obj = 1234;"
3973 "Array.prototype.arr = 4567;"
3974 "8901");
3975
3976 LocalContext env0;
3977 Local<Script> script0 = Script::Compile(source);
3978 CHECK_EQ(8901.0, script0->Run()->NumberValue());
3979
3980 LocalContext env1;
3981 Local<Script> script1 = Script::Compile(source);
3982 CHECK_EQ(8901.0, script1->Run()->NumberValue());
3983}
3984
3985
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003986THREADED_TEST(UndetectableObject) {
3987 v8::HandleScope scope;
3988 LocalContext env;
3989
3990 Local<v8::FunctionTemplate> desc =
3991 v8::FunctionTemplate::New(0, v8::Handle<Value>());
3992 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
3993
3994 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
3995 env->Global()->Set(v8_str("undetectable"), obj);
3996
3997 ExpectString("undetectable.toString()", "[object Object]");
3998 ExpectString("typeof undetectable", "undefined");
3999 ExpectString("typeof(undetectable)", "undefined");
4000 ExpectBoolean("typeof undetectable == 'undefined'", true);
4001 ExpectBoolean("typeof undetectable == 'object'", false);
4002 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
4003 ExpectBoolean("!undetectable", true);
4004
4005 ExpectObject("true&&undetectable", obj);
4006 ExpectBoolean("false&&undetectable", false);
4007 ExpectBoolean("true||undetectable", true);
4008 ExpectObject("false||undetectable", obj);
4009
4010 ExpectObject("undetectable&&true", obj);
4011 ExpectObject("undetectable&&false", obj);
4012 ExpectBoolean("undetectable||true", true);
4013 ExpectBoolean("undetectable||false", false);
4014
4015 ExpectBoolean("undetectable==null", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004016 ExpectBoolean("null==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004017 ExpectBoolean("undetectable==undefined", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004018 ExpectBoolean("undefined==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004019 ExpectBoolean("undetectable==undetectable", true);
4020
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004021
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004022 ExpectBoolean("undetectable===null", false);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004023 ExpectBoolean("null===undetectable", false);
4024 ExpectBoolean("undetectable===undefined", false);
4025 ExpectBoolean("undefined===undetectable", false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004026 ExpectBoolean("undetectable===undetectable", true);
4027}
4028
4029
ager@chromium.org04921a82011-06-27 13:21:41 +00004030THREADED_TEST(VoidLiteral) {
4031 v8::HandleScope scope;
4032 LocalContext env;
4033
4034 Local<v8::FunctionTemplate> desc =
4035 v8::FunctionTemplate::New(0, v8::Handle<Value>());
4036 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4037
4038 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4039 env->Global()->Set(v8_str("undetectable"), obj);
4040
4041 ExpectBoolean("undefined == void 0", true);
4042 ExpectBoolean("undetectable == void 0", true);
4043 ExpectBoolean("null == void 0", true);
4044 ExpectBoolean("undefined === void 0", true);
4045 ExpectBoolean("undetectable === void 0", false);
4046 ExpectBoolean("null === void 0", false);
4047
4048 ExpectBoolean("void 0 == undefined", true);
4049 ExpectBoolean("void 0 == undetectable", true);
4050 ExpectBoolean("void 0 == null", true);
4051 ExpectBoolean("void 0 === undefined", true);
4052 ExpectBoolean("void 0 === undetectable", false);
4053 ExpectBoolean("void 0 === null", false);
4054
4055 ExpectString("(function() {"
4056 " try {"
4057 " return x === void 0;"
4058 " } catch(e) {"
4059 " return e.toString();"
4060 " }"
4061 "})()",
4062 "ReferenceError: x is not defined");
4063 ExpectString("(function() {"
4064 " try {"
4065 " return void 0 === x;"
4066 " } catch(e) {"
4067 " return e.toString();"
4068 " }"
4069 "})()",
4070 "ReferenceError: x is not defined");
4071}
4072
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00004073
4074THREADED_TEST(ExtensibleOnUndetectable) {
4075 v8::HandleScope scope;
4076 LocalContext env;
4077
4078 Local<v8::FunctionTemplate> desc =
4079 v8::FunctionTemplate::New(0, v8::Handle<Value>());
4080 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4081
4082 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4083 env->Global()->Set(v8_str("undetectable"), obj);
4084
4085 Local<String> source = v8_str("undetectable.x = 42;"
4086 "undetectable.x");
4087
4088 Local<Script> script = Script::Compile(source);
4089
4090 CHECK_EQ(v8::Integer::New(42), script->Run());
4091
4092 ExpectBoolean("Object.isExtensible(undetectable)", true);
4093
4094 source = v8_str("Object.preventExtensions(undetectable);");
4095 script = Script::Compile(source);
4096 script->Run();
4097 ExpectBoolean("Object.isExtensible(undetectable)", false);
4098
4099 source = v8_str("undetectable.y = 2000;");
4100 script = Script::Compile(source);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00004101 Local<Value> result = script->Run();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004102 ExpectBoolean("undetectable.y == undefined", true);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00004103}
4104
4105
4106
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004107THREADED_TEST(UndetectableString) {
4108 v8::HandleScope scope;
4109 LocalContext env;
4110
4111 Local<String> obj = String::NewUndetectable("foo");
4112 env->Global()->Set(v8_str("undetectable"), obj);
4113
4114 ExpectString("undetectable", "foo");
4115 ExpectString("typeof undetectable", "undefined");
4116 ExpectString("typeof(undetectable)", "undefined");
4117 ExpectBoolean("typeof undetectable == 'undefined'", true);
4118 ExpectBoolean("typeof undetectable == 'string'", false);
4119 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
4120 ExpectBoolean("!undetectable", true);
4121
4122 ExpectObject("true&&undetectable", obj);
4123 ExpectBoolean("false&&undetectable", false);
4124 ExpectBoolean("true||undetectable", true);
4125 ExpectObject("false||undetectable", obj);
4126
4127 ExpectObject("undetectable&&true", obj);
4128 ExpectObject("undetectable&&false", obj);
4129 ExpectBoolean("undetectable||true", true);
4130 ExpectBoolean("undetectable||false", false);
4131
4132 ExpectBoolean("undetectable==null", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004133 ExpectBoolean("null==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004134 ExpectBoolean("undetectable==undefined", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004135 ExpectBoolean("undefined==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004136 ExpectBoolean("undetectable==undetectable", true);
4137
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004138
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004139 ExpectBoolean("undetectable===null", false);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004140 ExpectBoolean("null===undetectable", false);
4141 ExpectBoolean("undetectable===undefined", false);
4142 ExpectBoolean("undefined===undetectable", false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004143 ExpectBoolean("undetectable===undetectable", true);
4144}
4145
4146
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004147TEST(UndetectableOptimized) {
4148 i::FLAG_allow_natives_syntax = true;
4149 v8::HandleScope scope;
4150 LocalContext env;
4151
4152 Local<String> obj = String::NewUndetectable("foo");
4153 env->Global()->Set(v8_str("undetectable"), obj);
4154 env->Global()->Set(v8_str("detectable"), v8_str("bar"));
4155
4156 ExpectString(
4157 "function testBranch() {"
4158 " if (!%_IsUndetectableObject(undetectable)) throw 1;"
4159 " if (%_IsUndetectableObject(detectable)) throw 2;"
4160 "}\n"
4161 "function testBool() {"
4162 " var b1 = !%_IsUndetectableObject(undetectable);"
4163 " var b2 = %_IsUndetectableObject(detectable);"
4164 " if (b1) throw 3;"
4165 " if (b2) throw 4;"
4166 " return b1 == b2;"
4167 "}\n"
4168 "%OptimizeFunctionOnNextCall(testBranch);"
4169 "%OptimizeFunctionOnNextCall(testBool);"
4170 "for (var i = 0; i < 10; i++) {"
4171 " testBranch();"
4172 " testBool();"
4173 "}\n"
4174 "\"PASS\"",
4175 "PASS");
4176}
4177
4178
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004179template <typename T> static void USE(T) { }
4180
4181
4182// This test is not intended to be run, just type checked.
4183static void PersistentHandles() {
4184 USE(PersistentHandles);
4185 Local<String> str = v8_str("foo");
4186 v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
4187 USE(p_str);
4188 Local<Script> scr = Script::Compile(v8_str(""));
4189 v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
4190 USE(p_scr);
4191 Local<ObjectTemplate> templ = ObjectTemplate::New();
4192 v8::Persistent<ObjectTemplate> p_templ =
4193 v8::Persistent<ObjectTemplate>::New(templ);
4194 USE(p_templ);
4195}
4196
4197
4198static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
4199 ApiTestFuzzer::Fuzz();
4200 return v8::Undefined();
4201}
4202
4203
4204THREADED_TEST(GlobalObjectTemplate) {
4205 v8::HandleScope handle_scope;
4206 Local<ObjectTemplate> global_template = ObjectTemplate::New();
4207 global_template->Set(v8_str("JSNI_Log"),
4208 v8::FunctionTemplate::New(HandleLogDelegator));
4209 v8::Persistent<Context> context = Context::New(0, global_template);
4210 Context::Scope context_scope(context);
4211 Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
4212 context.Dispose();
4213}
4214
4215
4216static const char* kSimpleExtensionSource =
4217 "function Foo() {"
4218 " return 4;"
4219 "}";
4220
4221
4222THREADED_TEST(SimpleExtensions) {
4223 v8::HandleScope handle_scope;
4224 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
4225 const char* extension_names[] = { "simpletest" };
4226 v8::ExtensionConfiguration extensions(1, extension_names);
4227 v8::Handle<Context> context = Context::New(&extensions);
4228 Context::Scope lock(context);
4229 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
4230 CHECK_EQ(result, v8::Integer::New(4));
4231}
4232
4233
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004234static const char* kEvalExtensionSource1 =
4235 "function UseEval1() {"
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004236 " var x = 42;"
4237 " return eval('x');"
4238 "}";
4239
4240
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004241static const char* kEvalExtensionSource2 =
4242 "(function() {"
4243 " var x = 42;"
4244 " function e() {"
4245 " return eval('x');"
4246 " }"
4247 " this.UseEval2 = e;"
4248 "})()";
4249
4250
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004251THREADED_TEST(UseEvalFromExtension) {
4252 v8::HandleScope handle_scope;
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004253 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
4254 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
4255 const char* extension_names[] = { "evaltest1", "evaltest2" };
4256 v8::ExtensionConfiguration extensions(2, extension_names);
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004257 v8::Handle<Context> context = Context::New(&extensions);
4258 Context::Scope lock(context);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004259 v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
4260 CHECK_EQ(result, v8::Integer::New(42));
4261 result = Script::Compile(v8_str("UseEval2()"))->Run();
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004262 CHECK_EQ(result, v8::Integer::New(42));
4263}
4264
4265
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004266static const char* kWithExtensionSource1 =
4267 "function UseWith1() {"
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004268 " var x = 42;"
4269 " with({x:87}) { return x; }"
4270 "}";
4271
4272
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004273
4274static const char* kWithExtensionSource2 =
4275 "(function() {"
4276 " var x = 42;"
4277 " function e() {"
4278 " with ({x:87}) { return x; }"
4279 " }"
4280 " this.UseWith2 = e;"
4281 "})()";
4282
4283
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004284THREADED_TEST(UseWithFromExtension) {
4285 v8::HandleScope handle_scope;
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004286 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
4287 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
4288 const char* extension_names[] = { "withtest1", "withtest2" };
4289 v8::ExtensionConfiguration extensions(2, extension_names);
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004290 v8::Handle<Context> context = Context::New(&extensions);
4291 Context::Scope lock(context);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004292 v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
4293 CHECK_EQ(result, v8::Integer::New(87));
4294 result = Script::Compile(v8_str("UseWith2()"))->Run();
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004295 CHECK_EQ(result, v8::Integer::New(87));
4296}
4297
4298
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004299THREADED_TEST(AutoExtensions) {
4300 v8::HandleScope handle_scope;
4301 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
4302 extension->set_auto_enable(true);
4303 v8::RegisterExtension(extension);
4304 v8::Handle<Context> context = Context::New();
4305 Context::Scope lock(context);
4306 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
4307 CHECK_EQ(result, v8::Integer::New(4));
4308}
4309
4310
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004311static const char* kSyntaxErrorInExtensionSource =
4312 "[";
4313
4314
4315// Test that a syntax error in an extension does not cause a fatal
4316// error but results in an empty context.
4317THREADED_TEST(SyntaxErrorExtensions) {
4318 v8::HandleScope handle_scope;
4319 v8::RegisterExtension(new Extension("syntaxerror",
4320 kSyntaxErrorInExtensionSource));
4321 const char* extension_names[] = { "syntaxerror" };
4322 v8::ExtensionConfiguration extensions(1, extension_names);
4323 v8::Handle<Context> context = Context::New(&extensions);
4324 CHECK(context.IsEmpty());
4325}
4326
4327
4328static const char* kExceptionInExtensionSource =
4329 "throw 42";
4330
4331
4332// Test that an exception when installing an extension does not cause
4333// a fatal error but results in an empty context.
4334THREADED_TEST(ExceptionExtensions) {
4335 v8::HandleScope handle_scope;
4336 v8::RegisterExtension(new Extension("exception",
4337 kExceptionInExtensionSource));
4338 const char* extension_names[] = { "exception" };
4339 v8::ExtensionConfiguration extensions(1, extension_names);
4340 v8::Handle<Context> context = Context::New(&extensions);
4341 CHECK(context.IsEmpty());
4342}
4343
4344
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004345static const char* kNativeCallInExtensionSource =
4346 "function call_runtime_last_index_of(x) {"
4347 " return %StringLastIndexOf(x, 'bob', 10);"
4348 "}";
4349
4350
4351static const char* kNativeCallTest =
4352 "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
4353
4354// Test that a native runtime calls are supported in extensions.
4355THREADED_TEST(NativeCallInExtensions) {
4356 v8::HandleScope handle_scope;
4357 v8::RegisterExtension(new Extension("nativecall",
4358 kNativeCallInExtensionSource));
4359 const char* extension_names[] = { "nativecall" };
4360 v8::ExtensionConfiguration extensions(1, extension_names);
4361 v8::Handle<Context> context = Context::New(&extensions);
4362 Context::Scope lock(context);
4363 v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run();
4364 CHECK_EQ(result, v8::Integer::New(3));
4365}
4366
4367
whesse@chromium.org7b260152011-06-20 15:33:18 +00004368class NativeFunctionExtension : public Extension {
4369 public:
4370 NativeFunctionExtension(const char* name,
4371 const char* source,
4372 v8::InvocationCallback fun = &Echo)
4373 : Extension(name, source),
4374 function_(fun) { }
4375
4376 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
4377 v8::Handle<v8::String> name) {
4378 return v8::FunctionTemplate::New(function_);
4379 }
4380
4381 static v8::Handle<v8::Value> Echo(const v8::Arguments& args) {
4382 if (args.Length() >= 1) return (args[0]);
4383 return v8::Undefined();
4384 }
4385 private:
4386 v8::InvocationCallback function_;
4387};
4388
4389
4390THREADED_TEST(NativeFunctionDeclaration) {
4391 v8::HandleScope handle_scope;
4392 const char* name = "nativedecl";
4393 v8::RegisterExtension(new NativeFunctionExtension(name,
4394 "native function foo();"));
4395 const char* extension_names[] = { name };
4396 v8::ExtensionConfiguration extensions(1, extension_names);
4397 v8::Handle<Context> context = Context::New(&extensions);
4398 Context::Scope lock(context);
4399 v8::Handle<Value> result = Script::Compile(v8_str("foo(42);"))->Run();
4400 CHECK_EQ(result, v8::Integer::New(42));
4401}
4402
4403
4404THREADED_TEST(NativeFunctionDeclarationError) {
4405 v8::HandleScope handle_scope;
lrn@chromium.org67e236d2011-06-23 10:18:16 +00004406 const char* name = "nativedeclerr";
whesse@chromium.org7b260152011-06-20 15:33:18 +00004407 // Syntax error in extension code.
4408 v8::RegisterExtension(new NativeFunctionExtension(name,
4409 "native\nfunction foo();"));
4410 const char* extension_names[] = { name };
4411 v8::ExtensionConfiguration extensions(1, extension_names);
4412 v8::Handle<Context> context = Context::New(&extensions);
4413 ASSERT(context.IsEmpty());
4414}
4415
4416THREADED_TEST(NativeFunctionDeclarationErrorEscape) {
4417 v8::HandleScope handle_scope;
lrn@chromium.org67e236d2011-06-23 10:18:16 +00004418 const char* name = "nativedeclerresc";
whesse@chromium.org7b260152011-06-20 15:33:18 +00004419 // Syntax error in extension code - escape code in "native" means that
4420 // it's not treated as a keyword.
4421 v8::RegisterExtension(new NativeFunctionExtension(
4422 name,
4423 "nativ\\u0065 function foo();"));
4424 const char* extension_names[] = { name };
4425 v8::ExtensionConfiguration extensions(1, extension_names);
4426 v8::Handle<Context> context = Context::New(&extensions);
4427 ASSERT(context.IsEmpty());
4428}
4429
4430
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004431static void CheckDependencies(const char* name, const char* expected) {
4432 v8::HandleScope handle_scope;
4433 v8::ExtensionConfiguration config(1, &name);
4434 LocalContext context(&config);
4435 CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
4436}
4437
4438
4439/*
4440 * Configuration:
4441 *
4442 * /-- B <--\
4443 * A <- -- D <-- E
4444 * \-- C <--/
4445 */
4446THREADED_TEST(ExtensionDependency) {
4447 static const char* kEDeps[] = { "D" };
4448 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
4449 static const char* kDDeps[] = { "B", "C" };
4450 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
4451 static const char* kBCDeps[] = { "A" };
4452 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
4453 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
4454 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
4455 CheckDependencies("A", "undefinedA");
4456 CheckDependencies("B", "undefinedAB");
4457 CheckDependencies("C", "undefinedAC");
4458 CheckDependencies("D", "undefinedABCD");
4459 CheckDependencies("E", "undefinedABCDE");
4460 v8::HandleScope handle_scope;
4461 static const char* exts[2] = { "C", "E" };
4462 v8::ExtensionConfiguration config(2, exts);
4463 LocalContext context(&config);
4464 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
4465}
4466
4467
4468static const char* kExtensionTestScript =
4469 "native function A();"
4470 "native function B();"
4471 "native function C();"
4472 "function Foo(i) {"
4473 " if (i == 0) return A();"
4474 " if (i == 1) return B();"
4475 " if (i == 2) return C();"
4476 "}";
4477
4478
4479static v8::Handle<Value> CallFun(const v8::Arguments& args) {
4480 ApiTestFuzzer::Fuzz();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004481 if (args.IsConstructCall()) {
4482 args.This()->Set(v8_str("data"), args.Data());
4483 return v8::Null();
4484 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004485 return args.Data();
4486}
4487
4488
4489class FunctionExtension : public Extension {
4490 public:
4491 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
4492 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
4493 v8::Handle<String> name);
4494};
4495
4496
4497static int lookup_count = 0;
4498v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
4499 v8::Handle<String> name) {
4500 lookup_count++;
4501 if (name->Equals(v8_str("A"))) {
4502 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
4503 } else if (name->Equals(v8_str("B"))) {
4504 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
4505 } else if (name->Equals(v8_str("C"))) {
4506 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
4507 } else {
4508 return v8::Handle<v8::FunctionTemplate>();
4509 }
4510}
4511
4512
4513THREADED_TEST(FunctionLookup) {
4514 v8::RegisterExtension(new FunctionExtension());
4515 v8::HandleScope handle_scope;
4516 static const char* exts[1] = { "functiontest" };
4517 v8::ExtensionConfiguration config(1, exts);
4518 LocalContext context(&config);
4519 CHECK_EQ(3, lookup_count);
4520 CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
4521 CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
4522 CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
4523}
4524
4525
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004526THREADED_TEST(NativeFunctionConstructCall) {
4527 v8::RegisterExtension(new FunctionExtension());
4528 v8::HandleScope handle_scope;
4529 static const char* exts[1] = { "functiontest" };
4530 v8::ExtensionConfiguration config(1, exts);
4531 LocalContext context(&config);
4532 for (int i = 0; i < 10; i++) {
4533 // Run a few times to ensure that allocation of objects doesn't
4534 // change behavior of a constructor function.
4535 CHECK_EQ(v8::Integer::New(8),
4536 Script::Compile(v8_str("(new A()).data"))->Run());
4537 CHECK_EQ(v8::Integer::New(7),
4538 Script::Compile(v8_str("(new B()).data"))->Run());
4539 CHECK_EQ(v8::Integer::New(6),
4540 Script::Compile(v8_str("(new C()).data"))->Run());
4541 }
4542}
4543
4544
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004545static const char* last_location;
4546static const char* last_message;
4547void StoringErrorCallback(const char* location, const char* message) {
4548 if (last_location == NULL) {
4549 last_location = location;
4550 last_message = message;
4551 }
4552}
4553
4554
4555// ErrorReporting creates a circular extensions configuration and
4556// tests that the fatal error handler gets called. This renders V8
4557// unusable and therefore this test cannot be run in parallel.
4558TEST(ErrorReporting) {
4559 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
4560 static const char* aDeps[] = { "B" };
4561 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
4562 static const char* bDeps[] = { "A" };
4563 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
4564 last_location = NULL;
4565 v8::ExtensionConfiguration config(1, bDeps);
4566 v8::Handle<Context> context = Context::New(&config);
4567 CHECK(context.IsEmpty());
4568 CHECK_NE(last_location, NULL);
4569}
4570
4571
ager@chromium.org7c537e22008-10-16 08:43:32 +00004572static const char* js_code_causing_huge_string_flattening =
4573 "var str = 'X';"
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00004574 "for (var i = 0; i < 30; i++) {"
ager@chromium.org7c537e22008-10-16 08:43:32 +00004575 " str = str + str;"
4576 "}"
4577 "str.match(/X/);";
4578
4579
4580void OOMCallback(const char* location, const char* message) {
4581 exit(0);
4582}
4583
4584
4585TEST(RegexpOutOfMemory) {
4586 // Execute a script that causes out of memory when flattening a string.
4587 v8::HandleScope scope;
4588 v8::V8::SetFatalErrorHandler(OOMCallback);
4589 LocalContext context;
4590 Local<Script> script =
4591 Script::Compile(String::New(js_code_causing_huge_string_flattening));
4592 last_location = NULL;
4593 Local<Value> result = script->Run();
4594
4595 CHECK(false); // Should not return.
4596}
4597
4598
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004599static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
4600 v8::Handle<Value> data) {
4601 CHECK_EQ(v8::Undefined(), data);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004602 CHECK(message->GetScriptResourceName()->IsUndefined());
4603 CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004604 message->GetLineNumber();
4605 message->GetSourceLine();
4606}
4607
4608
4609THREADED_TEST(ErrorWithMissingScriptInfo) {
4610 v8::HandleScope scope;
4611 LocalContext context;
4612 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
4613 Script::Compile(v8_str("throw Error()"))->Run();
4614 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
4615}
4616
4617
4618int global_index = 0;
4619
4620class Snorkel {
4621 public:
4622 Snorkel() { index_ = global_index++; }
4623 int index_;
4624};
4625
4626class Whammy {
4627 public:
4628 Whammy() {
4629 cursor_ = 0;
4630 }
4631 ~Whammy() {
4632 script_.Dispose();
4633 }
4634 v8::Handle<Script> getScript() {
4635 if (script_.IsEmpty())
4636 script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
4637 return Local<Script>(*script_);
4638 }
4639
4640 public:
4641 static const int kObjectCount = 256;
4642 int cursor_;
4643 v8::Persistent<v8::Object> objects_[kObjectCount];
4644 v8::Persistent<Script> script_;
4645};
4646
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004647static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004648 Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
4649 delete snorkel;
4650 obj.ClearWeak();
4651}
4652
4653v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
4654 const AccessorInfo& info) {
4655 Whammy* whammy =
4656 static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
4657
4658 v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
4659
4660 v8::Handle<v8::Object> obj = v8::Object::New();
4661 v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
4662 if (!prev.IsEmpty()) {
4663 prev->Set(v8_str("next"), obj);
4664 prev.MakeWeak(new Snorkel(), &HandleWeakReference);
4665 whammy->objects_[whammy->cursor_].Clear();
4666 }
4667 whammy->objects_[whammy->cursor_] = global;
4668 whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
4669 return whammy->getScript()->Run();
4670}
4671
4672THREADED_TEST(WeakReference) {
4673 v8::HandleScope handle_scope;
4674 v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00004675 Whammy* whammy = new Whammy();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004676 templ->SetNamedPropertyHandler(WhammyPropertyGetter,
4677 0, 0, 0, 0,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00004678 v8::External::New(whammy));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004679 const char* extension_list[] = { "v8/gc" };
4680 v8::ExtensionConfiguration extensions(1, extension_list);
4681 v8::Persistent<Context> context = Context::New(&extensions);
4682 Context::Scope context_scope(context);
4683
4684 v8::Handle<v8::Object> interceptor = templ->NewInstance();
4685 context->Global()->Set(v8_str("whammy"), interceptor);
4686 const char* code =
4687 "var last;"
4688 "for (var i = 0; i < 10000; i++) {"
4689 " var obj = whammy.length;"
4690 " if (last) last.next = obj;"
4691 " last = obj;"
4692 "}"
4693 "gc();"
4694 "4";
4695 v8::Handle<Value> result = CompileRun(code);
4696 CHECK_EQ(4.0, result->NumberValue());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00004697 delete whammy;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004698 context.Dispose();
4699}
4700
4701
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004702static void DisposeAndSetFlag(v8::Persistent<v8::Value> obj, void* data) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004703 obj.Dispose();
4704 obj.Clear();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004705 *(reinterpret_cast<bool*>(data)) = true;
4706}
4707
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004708
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004709THREADED_TEST(IndependentWeakHandle) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004710 v8::Persistent<Context> context = Context::New();
4711 Context::Scope context_scope(context);
4712
4713 v8::Persistent<v8::Object> object_a;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004714
4715 {
4716 v8::HandleScope handle_scope;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004717 object_a = v8::Persistent<v8::Object>::New(v8::Object::New());
4718 }
4719
4720 bool object_a_disposed = false;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004721 object_a.MakeWeak(&object_a_disposed, &DisposeAndSetFlag);
4722 object_a.MarkIndependent();
4723 HEAP->PerformScavenge();
4724 CHECK(object_a_disposed);
4725}
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004726
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004727
4728static void InvokeScavenge() {
4729 HEAP->PerformScavenge();
4730}
4731
4732
4733static void InvokeMarkSweep() {
4734 HEAP->CollectAllGarbage(false);
4735}
4736
4737
4738static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
4739 obj.Dispose();
4740 obj.Clear();
4741 *(reinterpret_cast<bool*>(data)) = true;
4742 InvokeScavenge();
4743}
4744
4745
4746static void ForceMarkSweep(v8::Persistent<v8::Value> obj, void* data) {
4747 obj.Dispose();
4748 obj.Clear();
4749 *(reinterpret_cast<bool*>(data)) = true;
4750 InvokeMarkSweep();
4751}
4752
4753
4754THREADED_TEST(GCFromWeakCallbacks) {
4755 v8::Persistent<Context> context = Context::New();
4756 Context::Scope context_scope(context);
4757
4758 static const int kNumberOfGCTypes = 2;
4759 v8::WeakReferenceCallback gc_forcing_callback[kNumberOfGCTypes] =
4760 {&ForceScavenge, &ForceMarkSweep};
4761
4762 typedef void (*GCInvoker)();
4763 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
4764
4765 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
4766 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
4767 v8::Persistent<v8::Object> object;
4768 {
4769 v8::HandleScope handle_scope;
4770 object = v8::Persistent<v8::Object>::New(v8::Object::New());
4771 }
4772 bool disposed = false;
4773 object.MakeWeak(&disposed, gc_forcing_callback[inner_gc]);
4774 object.MarkIndependent();
4775 invoke_gc[outer_gc]();
4776 CHECK(disposed);
4777 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004778 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004779}
4780
4781
4782static void RevivingCallback(v8::Persistent<v8::Value> obj, void* data) {
4783 obj.ClearWeak();
4784 *(reinterpret_cast<bool*>(data)) = true;
4785}
4786
4787
4788THREADED_TEST(IndependentHandleRevival) {
4789 v8::Persistent<Context> context = Context::New();
4790 Context::Scope context_scope(context);
4791
4792 v8::Persistent<v8::Object> object;
4793 {
4794 v8::HandleScope handle_scope;
4795 object = v8::Persistent<v8::Object>::New(v8::Object::New());
4796 object->Set(v8_str("x"), v8::Integer::New(1));
4797 v8::Local<String> y_str = v8_str("y");
4798 object->Set(y_str, y_str);
4799 }
4800 bool revived = false;
4801 object.MakeWeak(&revived, &RevivingCallback);
4802 object.MarkIndependent();
4803 HEAP->PerformScavenge();
4804 CHECK(revived);
4805 HEAP->CollectAllGarbage(true);
4806 {
4807 v8::HandleScope handle_scope;
4808 v8::Local<String> y_str = v8_str("y");
4809 CHECK_EQ(v8::Integer::New(1), object->Get(v8_str("x")));
4810 CHECK(object->Get(y_str)->Equals(y_str));
4811 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004812}
4813
4814
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004815v8::Handle<Function> args_fun;
4816
4817
4818static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
4819 ApiTestFuzzer::Fuzz();
4820 CHECK_EQ(args_fun, args.Callee());
4821 CHECK_EQ(3, args.Length());
4822 CHECK_EQ(v8::Integer::New(1), args[0]);
4823 CHECK_EQ(v8::Integer::New(2), args[1]);
4824 CHECK_EQ(v8::Integer::New(3), args[2]);
4825 CHECK_EQ(v8::Undefined(), args[3]);
4826 v8::HandleScope scope;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004827 HEAP->CollectAllGarbage(false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004828 return v8::Undefined();
4829}
4830
4831
4832THREADED_TEST(Arguments) {
4833 v8::HandleScope scope;
4834 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
4835 global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
4836 LocalContext context(NULL, global);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004837 args_fun = context->Global()->Get(v8_str("f")).As<Function>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004838 v8_compile("f(1, 2, 3)")->Run();
4839}
4840
4841
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004842static v8::Handle<Value> NoBlockGetterX(Local<String> name,
4843 const AccessorInfo&) {
4844 return v8::Handle<Value>();
4845}
4846
4847
4848static v8::Handle<Value> NoBlockGetterI(uint32_t index,
4849 const AccessorInfo&) {
4850 return v8::Handle<Value>();
4851}
4852
4853
4854static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
4855 const AccessorInfo&) {
4856 if (!name->Equals(v8_str("foo"))) {
4857 return v8::Handle<v8::Boolean>(); // not intercepted
4858 }
4859
4860 return v8::False(); // intercepted, and don't delete the property
4861}
4862
4863
4864static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
4865 if (index != 2) {
4866 return v8::Handle<v8::Boolean>(); // not intercepted
4867 }
4868
4869 return v8::False(); // intercepted, and don't delete the property
4870}
4871
4872
4873THREADED_TEST(Deleter) {
4874 v8::HandleScope scope;
4875 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4876 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
4877 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
4878 LocalContext context;
4879 context->Global()->Set(v8_str("k"), obj->NewInstance());
4880 CompileRun(
4881 "k.foo = 'foo';"
4882 "k.bar = 'bar';"
4883 "k[2] = 2;"
4884 "k[4] = 4;");
4885 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
4886 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
4887
4888 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
4889 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
4890
4891 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
4892 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
4893
4894 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
4895 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
4896}
4897
4898
4899static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
4900 ApiTestFuzzer::Fuzz();
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004901 if (name->Equals(v8_str("foo")) ||
4902 name->Equals(v8_str("bar")) ||
4903 name->Equals(v8_str("baz"))) {
4904 return v8::Undefined();
4905 }
4906 return v8::Handle<Value>();
4907}
4908
4909
4910static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
4911 ApiTestFuzzer::Fuzz();
4912 if (index == 0 || index == 1) return v8::Undefined();
4913 return v8::Handle<Value>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004914}
4915
4916
4917static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
4918 ApiTestFuzzer::Fuzz();
4919 v8::Handle<v8::Array> result = v8::Array::New(3);
4920 result->Set(v8::Integer::New(0), v8_str("foo"));
4921 result->Set(v8::Integer::New(1), v8_str("bar"));
4922 result->Set(v8::Integer::New(2), v8_str("baz"));
4923 return result;
4924}
4925
4926
4927static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
4928 ApiTestFuzzer::Fuzz();
4929 v8::Handle<v8::Array> result = v8::Array::New(2);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004930 result->Set(v8::Integer::New(0), v8_str("0"));
4931 result->Set(v8::Integer::New(1), v8_str("1"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004932 return result;
4933}
4934
4935
4936THREADED_TEST(Enumerators) {
4937 v8::HandleScope scope;
4938 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4939 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004940 obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004941 LocalContext context;
4942 context->Global()->Set(v8_str("k"), obj->NewInstance());
4943 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004944 "k[10] = 0;"
4945 "k.a = 0;"
4946 "k[5] = 0;"
4947 "k.b = 0;"
4948 "k[4294967295] = 0;"
4949 "k.c = 0;"
4950 "k[4294967296] = 0;"
4951 "k.d = 0;"
4952 "k[140000] = 0;"
4953 "k.e = 0;"
4954 "k[30000000000] = 0;"
4955 "k.f = 0;"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004956 "var result = [];"
4957 "for (var prop in k) {"
4958 " result.push(prop);"
4959 "}"
4960 "result"));
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004961 // Check that we get all the property names returned including the
4962 // ones from the enumerators in the right order: indexed properties
4963 // in numerical order, indexed interceptor properties, named
4964 // properties in insertion order, named interceptor properties.
4965 // This order is not mandated by the spec, so this test is just
4966 // documenting our behavior.
4967 CHECK_EQ(17, result->Length());
4968 // Indexed properties in numerical order.
4969 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
4970 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
4971 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
4972 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
4973 // Indexed interceptor properties in the order they are returned
4974 // from the enumerator interceptor.
4975 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
4976 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
4977 // Named properties in insertion order.
4978 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
4979 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
4980 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
4981 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
4982 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
4983 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
4984 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
4985 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
4986 // Named interceptor properties.
4987 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
4988 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
4989 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004990}
4991
4992
4993int p_getter_count;
4994int p_getter_count2;
4995
4996
4997static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
4998 ApiTestFuzzer::Fuzz();
4999 p_getter_count++;
5000 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5001 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
5002 if (name->Equals(v8_str("p1"))) {
5003 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
5004 } else if (name->Equals(v8_str("p2"))) {
5005 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
5006 } else if (name->Equals(v8_str("p3"))) {
5007 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
5008 } else if (name->Equals(v8_str("p4"))) {
5009 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
5010 }
5011 return v8::Undefined();
5012}
5013
5014
5015static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
5016 ApiTestFuzzer::Fuzz();
5017 LocalContext context;
5018 context->Global()->Set(v8_str("o1"), obj->NewInstance());
5019 CompileRun(
5020 "o1.__proto__ = { };"
5021 "var o2 = { __proto__: o1 };"
5022 "var o3 = { __proto__: o2 };"
5023 "var o4 = { __proto__: o3 };"
5024 "for (var i = 0; i < 10; i++) o4.p4;"
5025 "for (var i = 0; i < 10; i++) o3.p3;"
5026 "for (var i = 0; i < 10; i++) o2.p2;"
5027 "for (var i = 0; i < 10; i++) o1.p1;");
5028}
5029
5030
5031static v8::Handle<Value> PGetter2(Local<String> name,
5032 const AccessorInfo& info) {
5033 ApiTestFuzzer::Fuzz();
5034 p_getter_count2++;
5035 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5036 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
5037 if (name->Equals(v8_str("p1"))) {
5038 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
5039 } else if (name->Equals(v8_str("p2"))) {
5040 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
5041 } else if (name->Equals(v8_str("p3"))) {
5042 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
5043 } else if (name->Equals(v8_str("p4"))) {
5044 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
5045 }
5046 return v8::Undefined();
5047}
5048
5049
5050THREADED_TEST(GetterHolders) {
5051 v8::HandleScope scope;
5052 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5053 obj->SetAccessor(v8_str("p1"), PGetter);
5054 obj->SetAccessor(v8_str("p2"), PGetter);
5055 obj->SetAccessor(v8_str("p3"), PGetter);
5056 obj->SetAccessor(v8_str("p4"), PGetter);
5057 p_getter_count = 0;
5058 RunHolderTest(obj);
5059 CHECK_EQ(40, p_getter_count);
5060}
5061
5062
5063THREADED_TEST(PreInterceptorHolders) {
5064 v8::HandleScope scope;
5065 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5066 obj->SetNamedPropertyHandler(PGetter2);
5067 p_getter_count2 = 0;
5068 RunHolderTest(obj);
5069 CHECK_EQ(40, p_getter_count2);
5070}
5071
5072
5073THREADED_TEST(ObjectInstantiation) {
5074 v8::HandleScope scope;
5075 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5076 templ->SetAccessor(v8_str("t"), PGetter2);
5077 LocalContext context;
5078 context->Global()->Set(v8_str("o"), templ->NewInstance());
5079 for (int i = 0; i < 100; i++) {
5080 v8::HandleScope inner_scope;
5081 v8::Handle<v8::Object> obj = templ->NewInstance();
5082 CHECK_NE(obj, context->Global()->Get(v8_str("o")));
5083 context->Global()->Set(v8_str("o2"), obj);
5084 v8::Handle<Value> value =
5085 Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
5086 CHECK_EQ(v8::True(), value);
5087 context->Global()->Set(v8_str("o"), obj);
5088 }
5089}
5090
5091
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005092static int StrCmp16(uint16_t* a, uint16_t* b) {
5093 while (true) {
5094 if (*a == 0 && *b == 0) return 0;
5095 if (*a != *b) return 0 + *a - *b;
5096 a++;
5097 b++;
5098 }
5099}
5100
5101
5102static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
5103 while (true) {
5104 if (n-- == 0) return 0;
5105 if (*a == 0 && *b == 0) return 0;
5106 if (*a != *b) return 0 + *a - *b;
5107 a++;
5108 b++;
5109 }
5110}
5111
5112
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005113THREADED_TEST(StringWrite) {
5114 v8::HandleScope scope;
5115 v8::Handle<String> str = v8_str("abcde");
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005116 // abc<Icelandic eth><Unicode snowman>.
5117 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
5118
5119 CHECK_EQ(5, str2->Length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005120
5121 char buf[100];
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005122 char utf8buf[100];
5123 uint16_t wbuf[100];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005124 int len;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005125 int charlen;
5126
5127 memset(utf8buf, 0x1, sizeof(utf8buf));
5128 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005129 CHECK_EQ(9, len);
5130 CHECK_EQ(5, charlen);
5131 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005132
5133 memset(utf8buf, 0x1, sizeof(utf8buf));
5134 len = str2->WriteUtf8(utf8buf, 8, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005135 CHECK_EQ(8, len);
5136 CHECK_EQ(5, charlen);
5137 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005138
5139 memset(utf8buf, 0x1, sizeof(utf8buf));
5140 len = str2->WriteUtf8(utf8buf, 7, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005141 CHECK_EQ(5, len);
5142 CHECK_EQ(4, charlen);
5143 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005144
5145 memset(utf8buf, 0x1, sizeof(utf8buf));
5146 len = str2->WriteUtf8(utf8buf, 6, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005147 CHECK_EQ(5, len);
5148 CHECK_EQ(4, charlen);
5149 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005150
5151 memset(utf8buf, 0x1, sizeof(utf8buf));
5152 len = str2->WriteUtf8(utf8buf, 5, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005153 CHECK_EQ(5, len);
5154 CHECK_EQ(4, charlen);
5155 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005156
5157 memset(utf8buf, 0x1, sizeof(utf8buf));
5158 len = str2->WriteUtf8(utf8buf, 4, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005159 CHECK_EQ(3, len);
5160 CHECK_EQ(3, charlen);
5161 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005162
5163 memset(utf8buf, 0x1, sizeof(utf8buf));
5164 len = str2->WriteUtf8(utf8buf, 3, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005165 CHECK_EQ(3, len);
5166 CHECK_EQ(3, charlen);
5167 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005168
5169 memset(utf8buf, 0x1, sizeof(utf8buf));
5170 len = str2->WriteUtf8(utf8buf, 2, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005171 CHECK_EQ(2, len);
5172 CHECK_EQ(2, charlen);
5173 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005174
5175 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005176 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005177 len = str->WriteAscii(buf);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005178 CHECK_EQ(5, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005179 len = str->Write(wbuf);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005180 CHECK_EQ(5, len);
5181 CHECK_EQ(0, strcmp("abcde", buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005182 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005183 CHECK_EQ(0, StrCmp16(answer1, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005184
5185 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005186 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005187 len = str->WriteAscii(buf, 0, 4);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005188 CHECK_EQ(4, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005189 len = str->Write(wbuf, 0, 4);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005190 CHECK_EQ(4, len);
5191 CHECK_EQ(0, strncmp("abcd\1", buf, 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005192 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005193 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005194
5195 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005196 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005197 len = str->WriteAscii(buf, 0, 5);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005198 CHECK_EQ(5, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005199 len = str->Write(wbuf, 0, 5);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005200 CHECK_EQ(5, len);
5201 CHECK_EQ(0, strncmp("abcde\1", buf, 6));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005202 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005203 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005204
5205 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005206 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005207 len = str->WriteAscii(buf, 0, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005208 CHECK_EQ(5, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005209 len = str->Write(wbuf, 0, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005210 CHECK_EQ(5, len);
5211 CHECK_EQ(0, strcmp("abcde", buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005212 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005213 CHECK_EQ(0, StrCmp16(answer4, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005214
5215 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005216 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005217 len = str->WriteAscii(buf, 4, -1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005218 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005219 len = str->Write(wbuf, 4, -1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005220 CHECK_EQ(1, len);
5221 CHECK_EQ(0, strcmp("e", buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005222 uint16_t answer5[] = {'e', '\0'};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005223 CHECK_EQ(0, StrCmp16(answer5, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005224
5225 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005226 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005227 len = str->WriteAscii(buf, 4, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005228 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005229 len = str->Write(wbuf, 4, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005230 CHECK_EQ(1, len);
5231 CHECK_EQ(0, strcmp("e", buf));
5232 CHECK_EQ(0, StrCmp16(answer5, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005233
5234 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005235 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005236 len = str->WriteAscii(buf, 4, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005237 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005238 len = str->Write(wbuf, 4, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005239 CHECK_EQ(1, len);
5240 CHECK_EQ(0, strncmp("e\1", buf, 2));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005241 uint16_t answer6[] = {'e', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005242 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005243
5244 memset(buf, 0x1, sizeof(buf));
5245 memset(wbuf, 0x1, sizeof(wbuf));
5246 len = str->WriteAscii(buf, 3, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005247 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005248 len = str->Write(wbuf, 3, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005249 CHECK_EQ(1, len);
5250 CHECK_EQ(0, strncmp("d\1", buf, 2));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005251 uint16_t answer7[] = {'d', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005252 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005253}
5254
5255
5256THREADED_TEST(ToArrayIndex) {
5257 v8::HandleScope scope;
5258 LocalContext context;
5259
5260 v8::Handle<String> str = v8_str("42");
5261 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
5262 CHECK(!index.IsEmpty());
5263 CHECK_EQ(42.0, index->Uint32Value());
5264 str = v8_str("42asdf");
5265 index = str->ToArrayIndex();
5266 CHECK(index.IsEmpty());
5267 str = v8_str("-42");
5268 index = str->ToArrayIndex();
5269 CHECK(index.IsEmpty());
5270 str = v8_str("4294967295");
5271 index = str->ToArrayIndex();
5272 CHECK(!index.IsEmpty());
5273 CHECK_EQ(4294967295.0, index->Uint32Value());
5274 v8::Handle<v8::Number> num = v8::Number::New(1);
5275 index = num->ToArrayIndex();
5276 CHECK(!index.IsEmpty());
5277 CHECK_EQ(1.0, index->Uint32Value());
5278 num = v8::Number::New(-1);
5279 index = num->ToArrayIndex();
5280 CHECK(index.IsEmpty());
5281 v8::Handle<v8::Object> obj = v8::Object::New();
5282 index = obj->ToArrayIndex();
5283 CHECK(index.IsEmpty());
5284}
5285
5286
5287THREADED_TEST(ErrorConstruction) {
5288 v8::HandleScope scope;
5289 LocalContext context;
5290
5291 v8::Handle<String> foo = v8_str("foo");
5292 v8::Handle<String> message = v8_str("message");
5293 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
5294 CHECK(range_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005295 v8::Handle<v8::Object> range_obj = range_error.As<v8::Object>();
5296 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005297 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
5298 CHECK(reference_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005299 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005300 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
5301 CHECK(syntax_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005302 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005303 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
5304 CHECK(type_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005305 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005306 v8::Handle<Value> error = v8::Exception::Error(foo);
5307 CHECK(error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005308 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005309}
5310
5311
5312static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
5313 ApiTestFuzzer::Fuzz();
5314 return v8_num(10);
5315}
5316
5317
5318static void YSetter(Local<String> name,
5319 Local<Value> value,
5320 const AccessorInfo& info) {
5321 if (info.This()->Has(name)) {
5322 info.This()->Delete(name);
5323 }
5324 info.This()->Set(name, value);
5325}
5326
5327
5328THREADED_TEST(DeleteAccessor) {
5329 v8::HandleScope scope;
5330 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5331 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
5332 LocalContext context;
5333 v8::Handle<v8::Object> holder = obj->NewInstance();
5334 context->Global()->Set(v8_str("holder"), holder);
5335 v8::Handle<Value> result = CompileRun(
5336 "holder.y = 11; holder.y = 12; holder.y");
5337 CHECK_EQ(12, result->Uint32Value());
5338}
5339
5340
5341THREADED_TEST(TypeSwitch) {
5342 v8::HandleScope scope;
5343 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
5344 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
5345 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
5346 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
5347 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
5348 LocalContext context;
5349 v8::Handle<v8::Object> obj0 = v8::Object::New();
5350 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
5351 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
5352 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
5353 for (int i = 0; i < 10; i++) {
5354 CHECK_EQ(0, type_switch->match(obj0));
5355 CHECK_EQ(1, type_switch->match(obj1));
5356 CHECK_EQ(2, type_switch->match(obj2));
5357 CHECK_EQ(3, type_switch->match(obj3));
5358 CHECK_EQ(3, type_switch->match(obj3));
5359 CHECK_EQ(2, type_switch->match(obj2));
5360 CHECK_EQ(1, type_switch->match(obj1));
5361 CHECK_EQ(0, type_switch->match(obj0));
5362 }
5363}
5364
5365
5366// For use within the TestSecurityHandler() test.
5367static bool g_security_callback_result = false;
5368static bool NamedSecurityTestCallback(Local<v8::Object> global,
5369 Local<Value> name,
5370 v8::AccessType type,
5371 Local<Value> data) {
5372 // Always allow read access.
5373 if (type == v8::ACCESS_GET)
5374 return true;
5375
5376 // Sometimes allow other access.
5377 return g_security_callback_result;
5378}
5379
5380
5381static bool IndexedSecurityTestCallback(Local<v8::Object> global,
5382 uint32_t key,
5383 v8::AccessType type,
5384 Local<Value> data) {
5385 // Always allow read access.
5386 if (type == v8::ACCESS_GET)
5387 return true;
5388
5389 // Sometimes allow other access.
5390 return g_security_callback_result;
5391}
5392
5393
5394static int trouble_nesting = 0;
5395static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
5396 ApiTestFuzzer::Fuzz();
5397 trouble_nesting++;
5398
5399 // Call a JS function that throws an uncaught exception.
5400 Local<v8::Object> arg_this = Context::GetCurrent()->Global();
5401 Local<Value> trouble_callee = (trouble_nesting == 3) ?
5402 arg_this->Get(v8_str("trouble_callee")) :
5403 arg_this->Get(v8_str("trouble_caller"));
5404 CHECK(trouble_callee->IsFunction());
5405 return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
5406}
5407
5408
5409static int report_count = 0;
5410static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
5411 v8::Handle<Value>) {
5412 report_count++;
5413}
5414
5415
5416// Counts uncaught exceptions, but other tests running in parallel
5417// also have uncaught exceptions.
5418TEST(ApiUncaughtException) {
ager@chromium.org8bb60582008-12-11 12:02:20 +00005419 report_count = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005420 v8::HandleScope scope;
5421 LocalContext env;
5422 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
5423
5424 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
5425 v8::Local<v8::Object> global = env->Global();
5426 global->Set(v8_str("trouble"), fun->GetFunction());
5427
5428 Script::Compile(v8_str("function trouble_callee() {"
5429 " var x = null;"
5430 " return x.foo;"
5431 "};"
5432 "function trouble_caller() {"
5433 " trouble();"
5434 "};"))->Run();
5435 Local<Value> trouble = global->Get(v8_str("trouble"));
5436 CHECK(trouble->IsFunction());
5437 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
5438 CHECK(trouble_callee->IsFunction());
5439 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
5440 CHECK(trouble_caller->IsFunction());
5441 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
5442 CHECK_EQ(1, report_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00005443 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
5444}
5445
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005446static const char* script_resource_name = "ExceptionInNativeScript.js";
5447static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
5448 v8::Handle<Value>) {
5449 v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
5450 CHECK(!name_val.IsEmpty() && name_val->IsString());
5451 v8::String::AsciiValue name(message->GetScriptResourceName());
5452 CHECK_EQ(script_resource_name, *name);
5453 CHECK_EQ(3, message->GetLineNumber());
5454 v8::String::AsciiValue source_line(message->GetSourceLine());
5455 CHECK_EQ(" new o.foo();", *source_line);
5456}
5457
5458TEST(ExceptionInNativeScript) {
5459 v8::HandleScope scope;
5460 LocalContext env;
5461 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
5462
5463 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
5464 v8::Local<v8::Object> global = env->Global();
5465 global->Set(v8_str("trouble"), fun->GetFunction());
5466
5467 Script::Compile(v8_str("function trouble() {\n"
5468 " var o = {};\n"
5469 " new o.foo();\n"
5470 "};"), v8::String::New(script_resource_name))->Run();
5471 Local<Value> trouble = global->Get(v8_str("trouble"));
5472 CHECK(trouble->IsFunction());
5473 Function::Cast(*trouble)->Call(global, 0, NULL);
5474 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
5475}
5476
ager@chromium.org8bb60582008-12-11 12:02:20 +00005477
5478TEST(CompilationErrorUsingTryCatchHandler) {
5479 v8::HandleScope scope;
5480 LocalContext env;
5481 v8::TryCatch try_catch;
5482 Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
5483 CHECK_NE(NULL, *try_catch.Exception());
5484 CHECK(try_catch.HasCaught());
5485}
5486
5487
5488TEST(TryCatchFinallyUsingTryCatchHandler) {
5489 v8::HandleScope scope;
5490 LocalContext env;
5491 v8::TryCatch try_catch;
5492 Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
5493 CHECK(!try_catch.HasCaught());
5494 Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
5495 CHECK(try_catch.HasCaught());
5496 try_catch.Reset();
5497 Script::Compile(v8_str("(function() {"
5498 "try { throw ''; } finally { return; }"
5499 "})()"))->Run();
5500 CHECK(!try_catch.HasCaught());
5501 Script::Compile(v8_str("(function()"
5502 " { try { throw ''; } finally { throw 0; }"
5503 "})()"))->Run();
5504 CHECK(try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005505}
5506
5507
5508// SecurityHandler can't be run twice
5509TEST(SecurityHandler) {
5510 v8::HandleScope scope0;
5511 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
5512 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
5513 IndexedSecurityTestCallback);
5514 // Create an environment
5515 v8::Persistent<Context> context0 =
5516 Context::New(NULL, global_template);
5517 context0->Enter();
5518
5519 v8::Handle<v8::Object> global0 = context0->Global();
5520 v8::Handle<Script> script0 = v8_compile("foo = 111");
5521 script0->Run();
5522 global0->Set(v8_str("0"), v8_num(999));
5523 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
5524 CHECK_EQ(111, foo0->Int32Value());
5525 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
5526 CHECK_EQ(999, z0->Int32Value());
5527
5528 // Create another environment, should fail security checks.
5529 v8::HandleScope scope1;
5530
5531 v8::Persistent<Context> context1 =
5532 Context::New(NULL, global_template);
5533 context1->Enter();
5534
5535 v8::Handle<v8::Object> global1 = context1->Global();
5536 global1->Set(v8_str("othercontext"), global0);
5537 // This set will fail the security check.
5538 v8::Handle<Script> script1 =
5539 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
5540 script1->Run();
5541 // This read will pass the security check.
5542 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
5543 CHECK_EQ(111, foo1->Int32Value());
5544 // This read will pass the security check.
5545 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
5546 CHECK_EQ(999, z1->Int32Value());
5547
5548 // Create another environment, should pass security checks.
5549 { g_security_callback_result = true; // allow security handler to pass.
5550 v8::HandleScope scope2;
5551 LocalContext context2;
5552 v8::Handle<v8::Object> global2 = context2->Global();
5553 global2->Set(v8_str("othercontext"), global0);
5554 v8::Handle<Script> script2 =
5555 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
5556 script2->Run();
5557 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
5558 CHECK_EQ(333, foo2->Int32Value());
5559 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
5560 CHECK_EQ(888, z2->Int32Value());
5561 }
5562
5563 context1->Exit();
5564 context1.Dispose();
5565
5566 context0->Exit();
5567 context0.Dispose();
5568}
5569
5570
5571THREADED_TEST(SecurityChecks) {
5572 v8::HandleScope handle_scope;
5573 LocalContext env1;
5574 v8::Persistent<Context> env2 = Context::New();
5575
5576 Local<Value> foo = v8_str("foo");
5577 Local<Value> bar = v8_str("bar");
5578
5579 // Set to the same domain.
5580 env1->SetSecurityToken(foo);
5581
5582 // Create a function in env1.
5583 Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
5584 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
5585 CHECK(spy->IsFunction());
5586
5587 // Create another function accessing global objects.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005588 Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005589 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
5590 CHECK(spy2->IsFunction());
5591
5592 // Switch to env2 in the same domain and invoke spy on env2.
5593 {
5594 env2->SetSecurityToken(foo);
5595 // Enter env2
5596 Context::Scope scope_env2(env2);
5597 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
5598 CHECK(result->IsFunction());
5599 }
5600
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005601 {
5602 env2->SetSecurityToken(bar);
5603 Context::Scope scope_env2(env2);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005604
5605 // Call cross_domain_call, it should throw an exception
5606 v8::TryCatch try_catch;
5607 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
5608 CHECK(try_catch.HasCaught());
5609 }
5610
5611 env2.Dispose();
5612}
5613
5614
5615// Regression test case for issue 1183439.
5616THREADED_TEST(SecurityChecksForPrototypeChain) {
5617 v8::HandleScope scope;
5618 LocalContext current;
5619 v8::Persistent<Context> other = Context::New();
5620
5621 // Change context to be able to get to the Object function in the
5622 // other context without hitting the security checks.
5623 v8::Local<Value> other_object;
5624 { Context::Scope scope(other);
5625 other_object = other->Global()->Get(v8_str("Object"));
5626 other->Global()->Set(v8_num(42), v8_num(87));
5627 }
5628
5629 current->Global()->Set(v8_str("other"), other->Global());
5630 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
5631
5632 // Make sure the security check fails here and we get an undefined
5633 // result instead of getting the Object function. Repeat in a loop
5634 // to make sure to exercise the IC code.
5635 v8::Local<Script> access_other0 = v8_compile("other.Object");
5636 v8::Local<Script> access_other1 = v8_compile("other[42]");
5637 for (int i = 0; i < 5; i++) {
5638 CHECK(!access_other0->Run()->Equals(other_object));
5639 CHECK(access_other0->Run()->IsUndefined());
5640 CHECK(!access_other1->Run()->Equals(v8_num(87)));
5641 CHECK(access_other1->Run()->IsUndefined());
5642 }
5643
5644 // Create an object that has 'other' in its prototype chain and make
5645 // sure we cannot access the Object function indirectly through
5646 // that. Repeat in a loop to make sure to exercise the IC code.
5647 v8_compile("function F() { };"
5648 "F.prototype = other;"
5649 "var f = new F();")->Run();
5650 v8::Local<Script> access_f0 = v8_compile("f.Object");
5651 v8::Local<Script> access_f1 = v8_compile("f[42]");
5652 for (int j = 0; j < 5; j++) {
5653 CHECK(!access_f0->Run()->Equals(other_object));
5654 CHECK(access_f0->Run()->IsUndefined());
5655 CHECK(!access_f1->Run()->Equals(v8_num(87)));
5656 CHECK(access_f1->Run()->IsUndefined());
5657 }
5658
5659 // Now it gets hairy: Set the prototype for the other global object
5660 // to be the current global object. The prototype chain for 'f' now
5661 // goes through 'other' but ends up in the current global object.
5662 { Context::Scope scope(other);
5663 other->Global()->Set(v8_str("__proto__"), current->Global());
5664 }
5665 // Set a named and an index property on the current global
5666 // object. To force the lookup to go through the other global object,
5667 // the properties must not exist in the other global object.
5668 current->Global()->Set(v8_str("foo"), v8_num(100));
5669 current->Global()->Set(v8_num(99), v8_num(101));
5670 // Try to read the properties from f and make sure that the access
5671 // gets stopped by the security checks on the other global object.
5672 Local<Script> access_f2 = v8_compile("f.foo");
5673 Local<Script> access_f3 = v8_compile("f[99]");
5674 for (int k = 0; k < 5; k++) {
5675 CHECK(!access_f2->Run()->Equals(v8_num(100)));
5676 CHECK(access_f2->Run()->IsUndefined());
5677 CHECK(!access_f3->Run()->Equals(v8_num(101)));
5678 CHECK(access_f3->Run()->IsUndefined());
5679 }
5680 other.Dispose();
5681}
5682
5683
5684THREADED_TEST(CrossDomainDelete) {
5685 v8::HandleScope handle_scope;
5686 LocalContext env1;
5687 v8::Persistent<Context> env2 = Context::New();
5688
5689 Local<Value> foo = v8_str("foo");
5690 Local<Value> bar = v8_str("bar");
5691
5692 // Set to the same domain.
5693 env1->SetSecurityToken(foo);
5694 env2->SetSecurityToken(foo);
5695
5696 env1->Global()->Set(v8_str("prop"), v8_num(3));
5697 env2->Global()->Set(v8_str("env1"), env1->Global());
5698
5699 // Change env2 to a different domain and delete env1.prop.
5700 env2->SetSecurityToken(bar);
5701 {
5702 Context::Scope scope_env2(env2);
5703 Local<Value> result =
5704 Script::Compile(v8_str("delete env1.prop"))->Run();
5705 CHECK(result->IsFalse());
5706 }
5707
5708 // Check that env1.prop still exists.
5709 Local<Value> v = env1->Global()->Get(v8_str("prop"));
5710 CHECK(v->IsNumber());
5711 CHECK_EQ(3, v->Int32Value());
5712
5713 env2.Dispose();
5714}
5715
5716
ager@chromium.org870a0b62008-11-04 11:43:05 +00005717THREADED_TEST(CrossDomainIsPropertyEnumerable) {
5718 v8::HandleScope handle_scope;
5719 LocalContext env1;
5720 v8::Persistent<Context> env2 = Context::New();
5721
5722 Local<Value> foo = v8_str("foo");
5723 Local<Value> bar = v8_str("bar");
5724
5725 // Set to the same domain.
5726 env1->SetSecurityToken(foo);
5727 env2->SetSecurityToken(foo);
5728
5729 env1->Global()->Set(v8_str("prop"), v8_num(3));
5730 env2->Global()->Set(v8_str("env1"), env1->Global());
5731
5732 // env1.prop is enumerable in env2.
5733 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
5734 {
5735 Context::Scope scope_env2(env2);
5736 Local<Value> result = Script::Compile(test)->Run();
5737 CHECK(result->IsTrue());
5738 }
5739
5740 // Change env2 to a different domain and test again.
5741 env2->SetSecurityToken(bar);
5742 {
5743 Context::Scope scope_env2(env2);
5744 Local<Value> result = Script::Compile(test)->Run();
5745 CHECK(result->IsFalse());
5746 }
5747
5748 env2.Dispose();
5749}
5750
5751
ager@chromium.org236ad962008-09-25 09:45:57 +00005752THREADED_TEST(CrossDomainForIn) {
5753 v8::HandleScope handle_scope;
5754 LocalContext env1;
5755 v8::Persistent<Context> env2 = Context::New();
5756
5757 Local<Value> foo = v8_str("foo");
5758 Local<Value> bar = v8_str("bar");
5759
5760 // Set to the same domain.
5761 env1->SetSecurityToken(foo);
5762 env2->SetSecurityToken(foo);
5763
5764 env1->Global()->Set(v8_str("prop"), v8_num(3));
5765 env2->Global()->Set(v8_str("env1"), env1->Global());
5766
5767 // Change env2 to a different domain and set env1's global object
5768 // as the __proto__ of an object in env2 and enumerate properties
5769 // in for-in. It shouldn't enumerate properties on env1's global
5770 // object.
5771 env2->SetSecurityToken(bar);
5772 {
5773 Context::Scope scope_env2(env2);
5774 Local<Value> result =
5775 CompileRun("(function(){var obj = {'__proto__':env1};"
5776 "for (var p in obj)"
5777 " if (p == 'prop') return false;"
5778 "return true;})()");
5779 CHECK(result->IsTrue());
5780 }
5781 env2.Dispose();
5782}
5783
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005784
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005785TEST(ContextDetachGlobal) {
5786 v8::HandleScope handle_scope;
5787 LocalContext env1;
5788 v8::Persistent<Context> env2 = Context::New();
5789
5790 Local<v8::Object> global1 = env1->Global();
5791
5792 Local<Value> foo = v8_str("foo");
5793
5794 // Set to the same domain.
5795 env1->SetSecurityToken(foo);
5796 env2->SetSecurityToken(foo);
5797
5798 // Enter env2
5799 env2->Enter();
5800
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00005801 // Create a function in env2 and add a reference to it in env1.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005802 Local<v8::Object> global2 = env2->Global();
5803 global2->Set(v8_str("prop"), v8::Integer::New(1));
5804 CompileRun("function getProp() {return prop;}");
5805
5806 env1->Global()->Set(v8_str("getProp"),
5807 global2->Get(v8_str("getProp")));
5808
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00005809 // Detach env2's global, and reuse the global object of env2
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005810 env2->Exit();
5811 env2->DetachGlobal();
5812 // env2 has a new global object.
5813 CHECK(!env2->Global()->Equals(global2));
5814
5815 v8::Persistent<Context> env3 =
5816 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
5817 env3->SetSecurityToken(v8_str("bar"));
5818 env3->Enter();
5819
5820 Local<v8::Object> global3 = env3->Global();
5821 CHECK_EQ(global2, global3);
5822 CHECK(global3->Get(v8_str("prop"))->IsUndefined());
5823 CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
5824 global3->Set(v8_str("prop"), v8::Integer::New(-1));
5825 global3->Set(v8_str("prop2"), v8::Integer::New(2));
5826 env3->Exit();
5827
5828 // Call getProp in env1, and it should return the value 1
5829 {
5830 Local<Value> get_prop = global1->Get(v8_str("getProp"));
5831 CHECK(get_prop->IsFunction());
5832 v8::TryCatch try_catch;
5833 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
5834 CHECK(!try_catch.HasCaught());
5835 CHECK_EQ(1, r->Int32Value());
5836 }
5837
5838 // Check that env3 is not accessible from env1
5839 {
5840 Local<Value> r = global3->Get(v8_str("prop2"));
5841 CHECK(r->IsUndefined());
5842 }
5843
5844 env2.Dispose();
5845 env3.Dispose();
5846}
5847
5848
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00005849TEST(DetachAndReattachGlobal) {
5850 v8::HandleScope scope;
5851 LocalContext env1;
5852
5853 // Create second environment.
5854 v8::Persistent<Context> env2 = Context::New();
5855
5856 Local<Value> foo = v8_str("foo");
5857
5858 // Set same security token for env1 and env2.
5859 env1->SetSecurityToken(foo);
5860 env2->SetSecurityToken(foo);
5861
5862 // Create a property on the global object in env2.
5863 {
5864 v8::Context::Scope scope(env2);
5865 env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
5866 }
5867
5868 // Create a reference to env2 global from env1 global.
5869 env1->Global()->Set(v8_str("other"), env2->Global());
5870
5871 // Check that we have access to other.p in env2 from env1.
5872 Local<Value> result = CompileRun("other.p");
5873 CHECK(result->IsInt32());
5874 CHECK_EQ(42, result->Int32Value());
5875
5876 // Hold on to global from env2 and detach global from env2.
5877 Local<v8::Object> global2 = env2->Global();
5878 env2->DetachGlobal();
5879
5880 // Check that the global has been detached. No other.p property can
5881 // be found.
5882 result = CompileRun("other.p");
5883 CHECK(result->IsUndefined());
5884
5885 // Reuse global2 for env3.
5886 v8::Persistent<Context> env3 =
5887 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
5888 CHECK_EQ(global2, env3->Global());
5889
5890 // Start by using the same security token for env3 as for env1 and env2.
5891 env3->SetSecurityToken(foo);
5892
5893 // Create a property on the global object in env3.
5894 {
5895 v8::Context::Scope scope(env3);
5896 env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
5897 }
5898
5899 // Check that other.p is now the property in env3 and that we have access.
5900 result = CompileRun("other.p");
5901 CHECK(result->IsInt32());
5902 CHECK_EQ(24, result->Int32Value());
5903
5904 // Change security token for env3 to something different from env1 and env2.
5905 env3->SetSecurityToken(v8_str("bar"));
5906
5907 // Check that we do not have access to other.p in env1. |other| is now
5908 // the global object for env3 which has a different security token,
5909 // so access should be blocked.
5910 result = CompileRun("other.p");
5911 CHECK(result->IsUndefined());
5912
5913 // Detach the global for env3 and reattach it to env2.
5914 env3->DetachGlobal();
5915 env2->ReattachGlobal(global2);
5916
5917 // Check that we have access to other.p again in env1. |other| is now
5918 // the global object for env2 which has the same security token as env1.
5919 result = CompileRun("other.p");
5920 CHECK(result->IsInt32());
5921 CHECK_EQ(42, result->Int32Value());
5922
5923 env2.Dispose();
5924 env3.Dispose();
5925}
5926
5927
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005928static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005929static bool NamedAccessBlocker(Local<v8::Object> global,
5930 Local<Value> name,
5931 v8::AccessType type,
5932 Local<Value> data) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005933 return Context::GetCurrent()->Global()->Equals(global) ||
5934 allowed_access_type[type];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005935}
5936
5937
5938static bool IndexedAccessBlocker(Local<v8::Object> global,
5939 uint32_t key,
5940 v8::AccessType type,
5941 Local<Value> data) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005942 return Context::GetCurrent()->Global()->Equals(global) ||
5943 allowed_access_type[type];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005944}
5945
5946
5947static int g_echo_value = -1;
5948static v8::Handle<Value> EchoGetter(Local<String> name,
5949 const AccessorInfo& info) {
5950 return v8_num(g_echo_value);
5951}
5952
5953
5954static void EchoSetter(Local<String> name,
5955 Local<Value> value,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005956 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005957 if (value->IsNumber())
5958 g_echo_value = value->Int32Value();
5959}
5960
5961
5962static v8::Handle<Value> UnreachableGetter(Local<String> name,
5963 const AccessorInfo& info) {
5964 CHECK(false); // This function should not be called..
5965 return v8::Undefined();
5966}
5967
5968
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005969static void UnreachableSetter(Local<String>, Local<Value>,
5970 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005971 CHECK(false); // This function should nto be called.
5972}
5973
5974
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005975TEST(AccessControl) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005976 v8::HandleScope handle_scope;
5977 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
5978
5979 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
5980 IndexedAccessBlocker);
5981
5982 // Add an accessor accessible by cross-domain JS code.
5983 global_template->SetAccessor(
5984 v8_str("accessible_prop"),
5985 EchoGetter, EchoSetter,
5986 v8::Handle<Value>(),
5987 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
5988
5989 // Add an accessor that is not accessible by cross-domain JS code.
ager@chromium.org870a0b62008-11-04 11:43:05 +00005990 global_template->SetAccessor(v8_str("blocked_prop"),
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005991 UnreachableGetter, UnreachableSetter,
5992 v8::Handle<Value>(),
5993 v8::DEFAULT);
5994
5995 // Create an environment
5996 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
5997 context0->Enter();
5998
5999 v8::Handle<v8::Object> global0 = context0->Global();
6000
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006001 // Define a property with JS getter and setter.
6002 CompileRun(
6003 "function getter() { return 'getter'; };\n"
6004 "function setter() { return 'setter'; }\n"
6005 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
6006
6007 Local<Value> getter = global0->Get(v8_str("getter"));
6008 Local<Value> setter = global0->Get(v8_str("setter"));
6009
6010 // And define normal element.
6011 global0->Set(239, v8_str("239"));
6012
6013 // Define an element with JS getter and setter.
6014 CompileRun(
6015 "function el_getter() { return 'el_getter'; };\n"
6016 "function el_setter() { return 'el_setter'; };\n"
6017 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
6018
6019 Local<Value> el_getter = global0->Get(v8_str("el_getter"));
6020 Local<Value> el_setter = global0->Get(v8_str("el_setter"));
6021
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006022 v8::HandleScope scope1;
6023
6024 v8::Persistent<Context> context1 = Context::New();
6025 context1->Enter();
6026
6027 v8::Handle<v8::Object> global1 = context1->Global();
6028 global1->Set(v8_str("other"), global0);
6029
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006030 // Access blocked property.
6031 CompileRun("other.blocked_prop = 1");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006032
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006033 ExpectUndefined("other.blocked_prop");
6034 ExpectUndefined(
6035 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
6036 ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006037
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006038 // Enable ACCESS_HAS
6039 allowed_access_type[v8::ACCESS_HAS] = true;
6040 ExpectUndefined("other.blocked_prop");
6041 // ... and now we can get the descriptor...
6042 ExpectUndefined(
antonm@chromium.orgdca01352011-01-31 17:15:05 +00006043 "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006044 // ... and enumerate the property.
6045 ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
6046 allowed_access_type[v8::ACCESS_HAS] = false;
antonm@chromium.orgdca01352011-01-31 17:15:05 +00006047
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006048 // Access blocked element.
6049 CompileRun("other[239] = 1");
6050
6051 ExpectUndefined("other[239]");
6052 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
6053 ExpectFalse("propertyIsEnumerable.call(other, '239')");
6054
6055 // Enable ACCESS_HAS
6056 allowed_access_type[v8::ACCESS_HAS] = true;
6057 ExpectUndefined("other[239]");
6058 // ... and now we can get the descriptor...
6059 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
6060 // ... and enumerate the property.
6061 ExpectTrue("propertyIsEnumerable.call(other, '239')");
6062 allowed_access_type[v8::ACCESS_HAS] = false;
6063
6064 // Access a property with JS accessor.
6065 CompileRun("other.js_accessor_p = 2");
6066
6067 ExpectUndefined("other.js_accessor_p");
6068 ExpectUndefined(
6069 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
6070
6071 // Enable ACCESS_HAS.
6072 allowed_access_type[v8::ACCESS_HAS] = true;
6073 ExpectUndefined("other.js_accessor_p");
6074 ExpectUndefined(
6075 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
6076 ExpectUndefined(
6077 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
6078 ExpectUndefined(
6079 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6080 allowed_access_type[v8::ACCESS_HAS] = false;
6081
6082 // Enable both ACCESS_HAS and ACCESS_GET.
6083 allowed_access_type[v8::ACCESS_HAS] = true;
6084 allowed_access_type[v8::ACCESS_GET] = true;
6085
6086 ExpectString("other.js_accessor_p", "getter");
6087 ExpectObject(
6088 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
6089 ExpectUndefined(
6090 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
6091 ExpectUndefined(
6092 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6093
6094 allowed_access_type[v8::ACCESS_GET] = false;
6095 allowed_access_type[v8::ACCESS_HAS] = false;
6096
6097 // Enable both ACCESS_HAS and ACCESS_SET.
6098 allowed_access_type[v8::ACCESS_HAS] = true;
6099 allowed_access_type[v8::ACCESS_SET] = true;
6100
6101 ExpectUndefined("other.js_accessor_p");
6102 ExpectUndefined(
6103 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
6104 ExpectObject(
6105 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
6106 ExpectUndefined(
6107 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6108
6109 allowed_access_type[v8::ACCESS_SET] = false;
6110 allowed_access_type[v8::ACCESS_HAS] = false;
6111
6112 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
6113 allowed_access_type[v8::ACCESS_HAS] = true;
6114 allowed_access_type[v8::ACCESS_GET] = true;
6115 allowed_access_type[v8::ACCESS_SET] = true;
6116
6117 ExpectString("other.js_accessor_p", "getter");
6118 ExpectObject(
6119 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
6120 ExpectObject(
6121 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
6122 ExpectUndefined(
6123 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6124
6125 allowed_access_type[v8::ACCESS_SET] = false;
6126 allowed_access_type[v8::ACCESS_GET] = false;
6127 allowed_access_type[v8::ACCESS_HAS] = false;
6128
6129 // Access an element with JS accessor.
6130 CompileRun("other[42] = 2");
6131
6132 ExpectUndefined("other[42]");
6133 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
6134
6135 // Enable ACCESS_HAS.
6136 allowed_access_type[v8::ACCESS_HAS] = true;
6137 ExpectUndefined("other[42]");
6138 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
6139 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
6140 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6141 allowed_access_type[v8::ACCESS_HAS] = false;
6142
6143 // Enable both ACCESS_HAS and ACCESS_GET.
6144 allowed_access_type[v8::ACCESS_HAS] = true;
6145 allowed_access_type[v8::ACCESS_GET] = true;
6146
6147 ExpectString("other[42]", "el_getter");
6148 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
6149 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
6150 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6151
6152 allowed_access_type[v8::ACCESS_GET] = false;
6153 allowed_access_type[v8::ACCESS_HAS] = false;
6154
6155 // Enable both ACCESS_HAS and ACCESS_SET.
6156 allowed_access_type[v8::ACCESS_HAS] = true;
6157 allowed_access_type[v8::ACCESS_SET] = true;
6158
6159 ExpectUndefined("other[42]");
6160 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
6161 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
6162 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6163
6164 allowed_access_type[v8::ACCESS_SET] = false;
6165 allowed_access_type[v8::ACCESS_HAS] = false;
6166
6167 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
6168 allowed_access_type[v8::ACCESS_HAS] = true;
6169 allowed_access_type[v8::ACCESS_GET] = true;
6170 allowed_access_type[v8::ACCESS_SET] = true;
6171
6172 ExpectString("other[42]", "el_getter");
6173 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
6174 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
6175 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6176
6177 allowed_access_type[v8::ACCESS_SET] = false;
6178 allowed_access_type[v8::ACCESS_GET] = false;
6179 allowed_access_type[v8::ACCESS_HAS] = false;
6180
6181 v8::Handle<Value> value;
ager@chromium.org870a0b62008-11-04 11:43:05 +00006182
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006183 // Access accessible property
antonm@chromium.orgdca01352011-01-31 17:15:05 +00006184 value = CompileRun("other.accessible_prop = 3");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006185 CHECK(value->IsNumber());
6186 CHECK_EQ(3, value->Int32Value());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006187 CHECK_EQ(3, g_echo_value);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006188
antonm@chromium.orgdca01352011-01-31 17:15:05 +00006189 value = CompileRun("other.accessible_prop");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006190 CHECK(value->IsNumber());
6191 CHECK_EQ(3, value->Int32Value());
6192
antonm@chromium.orgdca01352011-01-31 17:15:05 +00006193 value = CompileRun(
6194 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
6195 CHECK(value->IsNumber());
6196 CHECK_EQ(3, value->Int32Value());
6197
6198 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
ager@chromium.org870a0b62008-11-04 11:43:05 +00006199 CHECK(value->IsTrue());
6200
6201 // Enumeration doesn't enumerate accessors from inaccessible objects in
6202 // the prototype chain even if the accessors are in themselves accessible.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00006203 value =
ager@chromium.org870a0b62008-11-04 11:43:05 +00006204 CompileRun("(function(){var obj = {'__proto__':other};"
6205 "for (var p in obj)"
6206 " if (p == 'accessible_prop' || p == 'blocked_prop') {"
6207 " return false;"
6208 " }"
6209 "return true;})()");
antonm@chromium.orgdca01352011-01-31 17:15:05 +00006210 CHECK(value->IsTrue());
ager@chromium.org870a0b62008-11-04 11:43:05 +00006211
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006212 context1->Exit();
6213 context0->Exit();
6214 context1.Dispose();
6215 context0.Dispose();
6216}
6217
6218
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006219TEST(AccessControlES5) {
ricow@chromium.org65001782011-02-15 13:36:41 +00006220 v8::HandleScope handle_scope;
6221 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
6222
6223 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
6224 IndexedAccessBlocker);
6225
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00006226 // Add accessible accessor.
6227 global_template->SetAccessor(
6228 v8_str("accessible_prop"),
6229 EchoGetter, EchoSetter,
6230 v8::Handle<Value>(),
6231 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
6232
6233
ricow@chromium.org65001782011-02-15 13:36:41 +00006234 // Add an accessor that is not accessible by cross-domain JS code.
6235 global_template->SetAccessor(v8_str("blocked_prop"),
6236 UnreachableGetter, UnreachableSetter,
6237 v8::Handle<Value>(),
6238 v8::DEFAULT);
6239
6240 // Create an environment
6241 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6242 context0->Enter();
6243
6244 v8::Handle<v8::Object> global0 = context0->Global();
6245
6246 v8::Persistent<Context> context1 = Context::New();
6247 context1->Enter();
6248 v8::Handle<v8::Object> global1 = context1->Global();
6249 global1->Set(v8_str("other"), global0);
6250
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006251 // Regression test for issue 1154.
ricow@chromium.org65001782011-02-15 13:36:41 +00006252 ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006253
6254 ExpectUndefined("other.blocked_prop");
6255
6256 // Regression test for issue 1027.
6257 CompileRun("Object.defineProperty(\n"
6258 " other, 'blocked_prop', {configurable: false})");
6259 ExpectUndefined("other.blocked_prop");
6260 ExpectUndefined(
6261 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
6262
6263 // Regression test for issue 1171.
6264 ExpectTrue("Object.isExtensible(other)");
6265 CompileRun("Object.preventExtensions(other)");
6266 ExpectTrue("Object.isExtensible(other)");
6267
6268 // Object.seal and Object.freeze.
6269 CompileRun("Object.freeze(other)");
6270 ExpectTrue("Object.isExtensible(other)");
6271
6272 CompileRun("Object.seal(other)");
6273 ExpectTrue("Object.isExtensible(other)");
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00006274
6275 // Regression test for issue 1250.
6276 // Make sure that we can set the accessible accessors value using normal
6277 // assignment.
6278 CompileRun("other.accessible_prop = 42");
6279 CHECK_EQ(42, g_echo_value);
6280
6281 v8::Handle<Value> value;
6282 // We follow Safari in ignoring assignments to host object accessors.
6283 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
6284 value = CompileRun("other.accessible_prop == 42");
6285 CHECK(value->IsTrue());
ricow@chromium.org65001782011-02-15 13:36:41 +00006286}
6287
6288
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006289static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
6290 Local<Value> name,
6291 v8::AccessType type,
6292 Local<Value> data) {
6293 return false;
6294}
6295
6296
6297static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
6298 uint32_t key,
6299 v8::AccessType type,
6300 Local<Value> data) {
6301 return false;
6302}
6303
6304
6305THREADED_TEST(AccessControlGetOwnPropertyNames) {
6306 v8::HandleScope handle_scope;
6307 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
6308
6309 obj_template->Set(v8_str("x"), v8::Integer::New(42));
6310 obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
6311 GetOwnPropertyNamesIndexedBlocker);
6312
6313 // Create an environment
6314 v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
6315 context0->Enter();
6316
6317 v8::Handle<v8::Object> global0 = context0->Global();
6318
6319 v8::HandleScope scope1;
6320
6321 v8::Persistent<Context> context1 = Context::New();
6322 context1->Enter();
6323
6324 v8::Handle<v8::Object> global1 = context1->Global();
6325 global1->Set(v8_str("other"), global0);
6326 global1->Set(v8_str("object"), obj_template->NewInstance());
6327
6328 v8::Handle<Value> value;
6329
6330 // Attempt to get the property names of the other global object and
6331 // of an object that requires access checks. Accessing the other
6332 // global object should be blocked by access checks on the global
6333 // proxy object. Accessing the object that requires access checks
6334 // is blocked by the access checks on the object itself.
6335 value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
6336 CHECK(value->IsTrue());
6337
6338 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
6339 CHECK(value->IsTrue());
6340
6341 context1->Exit();
6342 context0->Exit();
6343 context1.Dispose();
6344 context0.Dispose();
6345}
6346
6347
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00006348static v8::Handle<v8::Array> NamedPropertyEnumerator(const AccessorInfo& info) {
6349 v8::Handle<v8::Array> result = v8::Array::New(1);
6350 result->Set(0, v8_str("x"));
6351 return result;
6352}
6353
6354
6355THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
6356 v8::HandleScope handle_scope;
6357 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
6358
6359 obj_template->Set(v8_str("x"), v8::Integer::New(42));
6360 obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
6361 NamedPropertyEnumerator);
6362
6363 LocalContext context;
6364 v8::Handle<v8::Object> global = context->Global();
6365 global->Set(v8_str("object"), obj_template->NewInstance());
6366
6367 v8::Handle<Value> value =
6368 CompileRun("Object.getOwnPropertyNames(object).join(',')");
6369 CHECK_EQ(v8_str("x"), value);
6370}
6371
6372
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006373static v8::Handle<Value> ConstTenGetter(Local<String> name,
6374 const AccessorInfo& info) {
6375 return v8_num(10);
6376}
6377
6378
6379THREADED_TEST(CrossDomainAccessors) {
6380 v8::HandleScope handle_scope;
6381
6382 v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
6383
6384 v8::Handle<v8::ObjectTemplate> global_template =
6385 func_template->InstanceTemplate();
6386
6387 v8::Handle<v8::ObjectTemplate> proto_template =
6388 func_template->PrototypeTemplate();
6389
6390 // Add an accessor to proto that's accessible by cross-domain JS code.
6391 proto_template->SetAccessor(v8_str("accessible"),
6392 ConstTenGetter, 0,
6393 v8::Handle<Value>(),
6394 v8::ALL_CAN_READ);
6395
6396 // Add an accessor that is not accessible by cross-domain JS code.
6397 global_template->SetAccessor(v8_str("unreachable"),
6398 UnreachableGetter, 0,
6399 v8::Handle<Value>(),
6400 v8::DEFAULT);
6401
6402 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6403 context0->Enter();
6404
6405 Local<v8::Object> global = context0->Global();
6406 // Add a normal property that shadows 'accessible'
6407 global->Set(v8_str("accessible"), v8_num(11));
6408
6409 // Enter a new context.
6410 v8::HandleScope scope1;
6411 v8::Persistent<Context> context1 = Context::New();
6412 context1->Enter();
6413
6414 v8::Handle<v8::Object> global1 = context1->Global();
6415 global1->Set(v8_str("other"), global);
6416
6417 // Should return 10, instead of 11
6418 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
6419 CHECK(value->IsNumber());
6420 CHECK_EQ(10, value->Int32Value());
6421
6422 value = v8_compile("other.unreachable")->Run();
6423 CHECK(value->IsUndefined());
6424
6425 context1->Exit();
6426 context0->Exit();
6427 context1.Dispose();
6428 context0.Dispose();
6429}
6430
6431
6432static int named_access_count = 0;
6433static int indexed_access_count = 0;
6434
6435static bool NamedAccessCounter(Local<v8::Object> global,
6436 Local<Value> name,
6437 v8::AccessType type,
6438 Local<Value> data) {
6439 named_access_count++;
6440 return true;
6441}
6442
6443
6444static bool IndexedAccessCounter(Local<v8::Object> global,
6445 uint32_t key,
6446 v8::AccessType type,
6447 Local<Value> data) {
6448 indexed_access_count++;
6449 return true;
6450}
6451
6452
6453// This one is too easily disturbed by other tests.
6454TEST(AccessControlIC) {
6455 named_access_count = 0;
6456 indexed_access_count = 0;
6457
6458 v8::HandleScope handle_scope;
6459
6460 // Create an environment.
6461 v8::Persistent<Context> context0 = Context::New();
6462 context0->Enter();
6463
6464 // Create an object that requires access-check functions to be
6465 // called for cross-domain access.
6466 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
6467 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
6468 IndexedAccessCounter);
6469 Local<v8::Object> object = object_template->NewInstance();
6470
6471 v8::HandleScope scope1;
6472
6473 // Create another environment.
6474 v8::Persistent<Context> context1 = Context::New();
6475 context1->Enter();
6476
6477 // Make easy access to the object from the other environment.
6478 v8::Handle<v8::Object> global1 = context1->Global();
6479 global1->Set(v8_str("obj"), object);
6480
6481 v8::Handle<Value> value;
6482
6483 // Check that the named access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00006484 CompileRun("function testProp(obj) {"
6485 " for (var i = 0; i < 10; i++) obj.prop = 1;"
6486 " for (var j = 0; j < 10; j++) obj.prop;"
6487 " return obj.prop"
6488 "}");
6489 value = CompileRun("testProp(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006490 CHECK(value->IsNumber());
6491 CHECK_EQ(1, value->Int32Value());
6492 CHECK_EQ(21, named_access_count);
6493
6494 // Check that the named access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00006495 CompileRun("var p = 'prop';"
6496 "function testKeyed(obj) {"
6497 " for (var i = 0; i < 10; i++) obj[p] = 1;"
6498 " for (var j = 0; j < 10; j++) obj[p];"
6499 " return obj[p];"
6500 "}");
6501 // Use obj which requires access checks. No inline caching is used
6502 // in that case.
6503 value = CompileRun("testKeyed(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006504 CHECK(value->IsNumber());
6505 CHECK_EQ(1, value->Int32Value());
6506 CHECK_EQ(42, named_access_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00006507 // Force the inline caches into generic state and try again.
6508 CompileRun("testKeyed({ a: 0 })");
6509 CompileRun("testKeyed({ b: 0 })");
6510 value = CompileRun("testKeyed(obj)");
6511 CHECK(value->IsNumber());
6512 CHECK_EQ(1, value->Int32Value());
6513 CHECK_EQ(63, named_access_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006514
6515 // Check that the indexed access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00006516 CompileRun("function testIndexed(obj) {"
6517 " for (var i = 0; i < 10; i++) obj[0] = 1;"
6518 " for (var j = 0; j < 10; j++) obj[0];"
6519 " return obj[0]"
6520 "}");
6521 value = CompileRun("testIndexed(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006522 CHECK(value->IsNumber());
6523 CHECK_EQ(1, value->Int32Value());
6524 CHECK_EQ(21, indexed_access_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00006525 // Force the inline caches into generic state.
6526 CompileRun("testIndexed(new Array(1))");
6527 // Test that the indexed access check is called.
6528 value = CompileRun("testIndexed(obj)");
6529 CHECK(value->IsNumber());
6530 CHECK_EQ(1, value->Int32Value());
6531 CHECK_EQ(42, indexed_access_count);
6532
6533 // Check that the named access check is called when invoking
6534 // functions on an object that requires access checks.
6535 CompileRun("obj.f = function() {}");
6536 CompileRun("function testCallNormal(obj) {"
6537 " for (var i = 0; i < 10; i++) obj.f();"
6538 "}");
6539 CompileRun("testCallNormal(obj)");
6540 CHECK_EQ(74, named_access_count);
6541
6542 // Force obj into slow case.
6543 value = CompileRun("delete obj.prop");
6544 CHECK(value->BooleanValue());
6545 // Force inline caches into dictionary probing mode.
6546 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
6547 // Test that the named access check is called.
6548 value = CompileRun("testProp(obj);");
6549 CHECK(value->IsNumber());
6550 CHECK_EQ(1, value->Int32Value());
6551 CHECK_EQ(96, named_access_count);
6552
6553 // Force the call inline cache into dictionary probing mode.
6554 CompileRun("o.f = function() {}; testCallNormal(o)");
6555 // Test that the named access check is still called for each
6556 // invocation of the function.
6557 value = CompileRun("testCallNormal(obj)");
6558 CHECK_EQ(106, named_access_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006559
6560 context1->Exit();
6561 context0->Exit();
6562 context1.Dispose();
6563 context0.Dispose();
6564}
6565
6566
6567static bool NamedAccessFlatten(Local<v8::Object> global,
6568 Local<Value> name,
6569 v8::AccessType type,
6570 Local<Value> data) {
6571 char buf[100];
6572 int len;
6573
6574 CHECK(name->IsString());
6575
6576 memset(buf, 0x1, sizeof(buf));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006577 len = name.As<String>()->WriteAscii(buf);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006578 CHECK_EQ(4, len);
6579
6580 uint16_t buf2[100];
6581
6582 memset(buf, 0x1, sizeof(buf));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006583 len = name.As<String>()->Write(buf2);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006584 CHECK_EQ(4, len);
6585
6586 return true;
6587}
6588
6589
6590static bool IndexedAccessFlatten(Local<v8::Object> global,
6591 uint32_t key,
6592 v8::AccessType type,
6593 Local<Value> data) {
6594 return true;
6595}
6596
6597
6598// Regression test. In access checks, operations that may cause
6599// garbage collection are not allowed. It used to be the case that
6600// using the Write operation on a string could cause a garbage
6601// collection due to flattening of the string. This is no longer the
6602// case.
6603THREADED_TEST(AccessControlFlatten) {
6604 named_access_count = 0;
6605 indexed_access_count = 0;
6606
6607 v8::HandleScope handle_scope;
6608
6609 // Create an environment.
6610 v8::Persistent<Context> context0 = Context::New();
6611 context0->Enter();
6612
6613 // Create an object that requires access-check functions to be
6614 // called for cross-domain access.
6615 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
6616 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
6617 IndexedAccessFlatten);
6618 Local<v8::Object> object = object_template->NewInstance();
6619
6620 v8::HandleScope scope1;
6621
6622 // Create another environment.
6623 v8::Persistent<Context> context1 = Context::New();
6624 context1->Enter();
6625
6626 // Make easy access to the object from the other environment.
6627 v8::Handle<v8::Object> global1 = context1->Global();
6628 global1->Set(v8_str("obj"), object);
6629
6630 v8::Handle<Value> value;
6631
6632 value = v8_compile("var p = 'as' + 'df';")->Run();
6633 value = v8_compile("obj[p];")->Run();
6634
6635 context1->Exit();
6636 context0->Exit();
6637 context1.Dispose();
6638 context0.Dispose();
6639}
6640
6641
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006642static v8::Handle<Value> AccessControlNamedGetter(
6643 Local<String>, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006644 return v8::Integer::New(42);
6645}
6646
6647
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006648static v8::Handle<Value> AccessControlNamedSetter(
6649 Local<String>, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006650 return value;
6651}
6652
6653
6654static v8::Handle<Value> AccessControlIndexedGetter(
6655 uint32_t index,
6656 const AccessorInfo& info) {
6657 return v8_num(42);
6658}
6659
6660
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006661static v8::Handle<Value> AccessControlIndexedSetter(
6662 uint32_t, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006663 return value;
6664}
6665
6666
6667THREADED_TEST(AccessControlInterceptorIC) {
6668 named_access_count = 0;
6669 indexed_access_count = 0;
6670
6671 v8::HandleScope handle_scope;
6672
6673 // Create an environment.
6674 v8::Persistent<Context> context0 = Context::New();
6675 context0->Enter();
6676
6677 // Create an object that requires access-check functions to be
6678 // called for cross-domain access. The object also has interceptors
6679 // interceptor.
6680 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
6681 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
6682 IndexedAccessCounter);
6683 object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
6684 AccessControlNamedSetter);
6685 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
6686 AccessControlIndexedSetter);
6687 Local<v8::Object> object = object_template->NewInstance();
6688
6689 v8::HandleScope scope1;
6690
6691 // Create another environment.
6692 v8::Persistent<Context> context1 = Context::New();
6693 context1->Enter();
6694
6695 // Make easy access to the object from the other environment.
6696 v8::Handle<v8::Object> global1 = context1->Global();
6697 global1->Set(v8_str("obj"), object);
6698
6699 v8::Handle<Value> value;
6700
6701 // Check that the named access-control function is called every time
6702 // eventhough there is an interceptor on the object.
6703 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
6704 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
6705 "obj.x")->Run();
6706 CHECK(value->IsNumber());
6707 CHECK_EQ(42, value->Int32Value());
6708 CHECK_EQ(21, named_access_count);
6709
6710 value = v8_compile("var p = 'x';")->Run();
6711 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
6712 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
6713 "obj[p]")->Run();
6714 CHECK(value->IsNumber());
6715 CHECK_EQ(42, value->Int32Value());
6716 CHECK_EQ(42, named_access_count);
6717
6718 // Check that the indexed access-control function is called every
6719 // time eventhough there is an interceptor on the object.
6720 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
6721 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
6722 "obj[0]")->Run();
6723 CHECK(value->IsNumber());
6724 CHECK_EQ(42, value->Int32Value());
6725 CHECK_EQ(21, indexed_access_count);
6726
6727 context1->Exit();
6728 context0->Exit();
6729 context1.Dispose();
6730 context0.Dispose();
6731}
6732
6733
6734THREADED_TEST(Version) {
6735 v8::V8::GetVersion();
6736}
6737
6738
6739static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
6740 ApiTestFuzzer::Fuzz();
6741 return v8_num(12);
6742}
6743
6744
6745THREADED_TEST(InstanceProperties) {
6746 v8::HandleScope handle_scope;
6747 LocalContext context;
6748
6749 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6750 Local<ObjectTemplate> instance = t->InstanceTemplate();
6751
6752 instance->Set(v8_str("x"), v8_num(42));
6753 instance->Set(v8_str("f"),
6754 v8::FunctionTemplate::New(InstanceFunctionCallback));
6755
6756 Local<Value> o = t->GetFunction()->NewInstance();
6757
6758 context->Global()->Set(v8_str("i"), o);
6759 Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
6760 CHECK_EQ(42, value->Int32Value());
6761
6762 value = Script::Compile(v8_str("i.f()"))->Run();
6763 CHECK_EQ(12, value->Int32Value());
6764}
6765
6766
6767static v8::Handle<Value>
6768GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
6769 ApiTestFuzzer::Fuzz();
6770 return v8::Handle<Value>();
6771}
6772
6773
6774THREADED_TEST(GlobalObjectInstanceProperties) {
6775 v8::HandleScope handle_scope;
6776
6777 Local<Value> global_object;
6778
6779 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6780 t->InstanceTemplate()->SetNamedPropertyHandler(
6781 GlobalObjectInstancePropertiesGet);
6782 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
6783 instance_template->Set(v8_str("x"), v8_num(42));
6784 instance_template->Set(v8_str("f"),
6785 v8::FunctionTemplate::New(InstanceFunctionCallback));
6786
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006787 // The script to check how Crankshaft compiles missing global function
6788 // invocations. function g is not defined and should throw on call.
6789 const char* script =
6790 "function wrapper(call) {"
6791 " var x = 0, y = 1;"
6792 " for (var i = 0; i < 1000; i++) {"
6793 " x += i * 100;"
6794 " y += i * 100;"
6795 " }"
6796 " if (call) g();"
6797 "}"
6798 "for (var i = 0; i < 17; i++) wrapper(false);"
6799 "var thrown = 0;"
6800 "try { wrapper(true); } catch (e) { thrown = 1; };"
6801 "thrown";
6802
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006803 {
6804 LocalContext env(NULL, instance_template);
6805 // Hold on to the global object so it can be used again in another
6806 // environment initialization.
6807 global_object = env->Global();
6808
6809 Local<Value> value = Script::Compile(v8_str("x"))->Run();
6810 CHECK_EQ(42, value->Int32Value());
6811 value = Script::Compile(v8_str("f()"))->Run();
6812 CHECK_EQ(12, value->Int32Value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006813 value = Script::Compile(v8_str(script))->Run();
6814 CHECK_EQ(1, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006815 }
6816
6817 {
6818 // Create new environment reusing the global object.
6819 LocalContext env(NULL, instance_template, global_object);
6820 Local<Value> value = Script::Compile(v8_str("x"))->Run();
6821 CHECK_EQ(42, value->Int32Value());
6822 value = Script::Compile(v8_str("f()"))->Run();
6823 CHECK_EQ(12, value->Int32Value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006824 value = Script::Compile(v8_str(script))->Run();
6825 CHECK_EQ(1, value->Int32Value());
6826 }
6827}
6828
6829
6830THREADED_TEST(CallKnownGlobalReceiver) {
6831 v8::HandleScope handle_scope;
6832
6833 Local<Value> global_object;
6834
6835 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6836 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
6837
6838 // The script to check that we leave global object not
6839 // global object proxy on stack when we deoptimize from inside
6840 // arguments evaluation.
6841 // To provoke error we need to both force deoptimization
6842 // from arguments evaluation and to force CallIC to take
6843 // CallIC_Miss code path that can't cope with global proxy.
6844 const char* script =
6845 "function bar(x, y) { try { } finally { } }"
6846 "function baz(x) { try { } finally { } }"
6847 "function bom(x) { try { } finally { } }"
6848 "function foo(x) { bar([x], bom(2)); }"
6849 "for (var i = 0; i < 10000; i++) foo(1);"
6850 "foo";
6851
6852 Local<Value> foo;
6853 {
6854 LocalContext env(NULL, instance_template);
6855 // Hold on to the global object so it can be used again in another
6856 // environment initialization.
6857 global_object = env->Global();
6858 foo = Script::Compile(v8_str(script))->Run();
6859 }
6860
6861 {
6862 // Create new environment reusing the global object.
6863 LocalContext env(NULL, instance_template, global_object);
6864 env->Global()->Set(v8_str("foo"), foo);
6865 Local<Value> value = Script::Compile(v8_str("foo()"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006866 }
6867}
6868
6869
6870static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
6871 ApiTestFuzzer::Fuzz();
6872 return v8_num(42);
6873}
6874
6875
6876static int shadow_y;
6877static int shadow_y_setter_call_count;
6878static int shadow_y_getter_call_count;
6879
6880
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006881static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006882 shadow_y_setter_call_count++;
6883 shadow_y = 42;
6884}
6885
6886
6887static v8::Handle<Value> ShadowYGetter(Local<String> name,
6888 const AccessorInfo& info) {
6889 ApiTestFuzzer::Fuzz();
6890 shadow_y_getter_call_count++;
6891 return v8_num(shadow_y);
6892}
6893
6894
6895static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
6896 const AccessorInfo& info) {
6897 return v8::Handle<Value>();
6898}
6899
6900
6901static v8::Handle<Value> ShadowNamedGet(Local<String> key,
6902 const AccessorInfo&) {
6903 return v8::Handle<Value>();
6904}
6905
6906
6907THREADED_TEST(ShadowObject) {
6908 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
6909 v8::HandleScope handle_scope;
6910
6911 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
6912 LocalContext context(NULL, global_template);
6913
6914 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6915 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
6916 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
6917 Local<ObjectTemplate> proto = t->PrototypeTemplate();
6918 Local<ObjectTemplate> instance = t->InstanceTemplate();
6919
6920 // Only allow calls of f on instances of t.
6921 Local<v8::Signature> signature = v8::Signature::New(t);
6922 proto->Set(v8_str("f"),
6923 v8::FunctionTemplate::New(ShadowFunctionCallback,
6924 Local<Value>(),
6925 signature));
6926 proto->Set(v8_str("x"), v8_num(12));
6927
6928 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
6929
6930 Local<Value> o = t->GetFunction()->NewInstance();
6931 context->Global()->Set(v8_str("__proto__"), o);
6932
6933 Local<Value> value =
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00006934 Script::Compile(v8_str("this.propertyIsEnumerable(0)"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006935 CHECK(value->IsBoolean());
6936 CHECK(!value->BooleanValue());
6937
6938 value = Script::Compile(v8_str("x"))->Run();
6939 CHECK_EQ(12, value->Int32Value());
6940
6941 value = Script::Compile(v8_str("f()"))->Run();
6942 CHECK_EQ(42, value->Int32Value());
6943
6944 Script::Compile(v8_str("y = 42"))->Run();
6945 CHECK_EQ(1, shadow_y_setter_call_count);
6946 value = Script::Compile(v8_str("y"))->Run();
6947 CHECK_EQ(1, shadow_y_getter_call_count);
6948 CHECK_EQ(42, value->Int32Value());
6949}
6950
6951
6952THREADED_TEST(HiddenPrototype) {
6953 v8::HandleScope handle_scope;
6954 LocalContext context;
6955
6956 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
6957 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
6958 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
6959 t1->SetHiddenPrototype(true);
6960 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
6961 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
6962 t2->SetHiddenPrototype(true);
6963 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
6964 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
6965 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
6966
6967 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
6968 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
6969 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
6970 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
6971
6972 // Setting the prototype on an object skips hidden prototypes.
6973 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6974 o0->Set(v8_str("__proto__"), o1);
6975 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6976 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6977 o0->Set(v8_str("__proto__"), o2);
6978 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6979 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6980 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6981 o0->Set(v8_str("__proto__"), o3);
6982 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6983 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6984 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6985 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
6986
6987 // Getting the prototype of o0 should get the first visible one
6988 // which is o3. Therefore, z should not be defined on the prototype
6989 // object.
6990 Local<Value> proto = o0->Get(v8_str("__proto__"));
6991 CHECK(proto->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006992 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006993}
6994
6995
ager@chromium.org5c838252010-02-19 08:53:10 +00006996THREADED_TEST(SetPrototype) {
6997 v8::HandleScope handle_scope;
6998 LocalContext context;
6999
7000 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
7001 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
7002 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
7003 t1->SetHiddenPrototype(true);
7004 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
7005 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
7006 t2->SetHiddenPrototype(true);
7007 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
7008 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
7009 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
7010
7011 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
7012 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
7013 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
7014 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
7015
7016 // Setting the prototype on an object does not skip hidden prototypes.
7017 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7018 CHECK(o0->SetPrototype(o1));
7019 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7020 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7021 CHECK(o1->SetPrototype(o2));
7022 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7023 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7024 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7025 CHECK(o2->SetPrototype(o3));
7026 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7027 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7028 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7029 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
7030
7031 // Getting the prototype of o0 should get the first visible one
7032 // which is o3. Therefore, z should not be defined on the prototype
7033 // object.
7034 Local<Value> proto = o0->Get(v8_str("__proto__"));
7035 CHECK(proto->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007036 CHECK_EQ(proto.As<v8::Object>(), o3);
ager@chromium.org5c838252010-02-19 08:53:10 +00007037
7038 // However, Object::GetPrototype ignores hidden prototype.
7039 Local<Value> proto0 = o0->GetPrototype();
7040 CHECK(proto0->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007041 CHECK_EQ(proto0.As<v8::Object>(), o1);
ager@chromium.org5c838252010-02-19 08:53:10 +00007042
7043 Local<Value> proto1 = o1->GetPrototype();
7044 CHECK(proto1->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007045 CHECK_EQ(proto1.As<v8::Object>(), o2);
ager@chromium.org5c838252010-02-19 08:53:10 +00007046
7047 Local<Value> proto2 = o2->GetPrototype();
7048 CHECK(proto2->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007049 CHECK_EQ(proto2.As<v8::Object>(), o3);
ager@chromium.org5c838252010-02-19 08:53:10 +00007050}
7051
7052
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007053THREADED_TEST(FunctionReadOnlyPrototype) {
ager@chromium.org04921a82011-06-27 13:21:41 +00007054 v8::HandleScope handle_scope;
7055 LocalContext context;
7056
7057 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007058 t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
7059 t1->ReadOnlyPrototype();
ager@chromium.org04921a82011-06-27 13:21:41 +00007060 context->Global()->Set(v8_str("func1"), t1->GetFunction());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007061 // Configured value of ReadOnly flag.
ager@chromium.org04921a82011-06-27 13:21:41 +00007062 CHECK(CompileRun(
7063 "(function() {"
7064 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007065 " return (descriptor['writable'] == false);"
ager@chromium.org04921a82011-06-27 13:21:41 +00007066 "})()")->BooleanValue());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007067 CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
7068 CHECK_EQ(42,
7069 CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
ager@chromium.org04921a82011-06-27 13:21:41 +00007070
7071 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007072 t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
ager@chromium.org04921a82011-06-27 13:21:41 +00007073 context->Global()->Set(v8_str("func2"), t2->GetFunction());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007074 // Default value of ReadOnly flag.
ager@chromium.org04921a82011-06-27 13:21:41 +00007075 CHECK(CompileRun(
7076 "(function() {"
7077 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007078 " return (descriptor['writable'] == true);"
ager@chromium.org04921a82011-06-27 13:21:41 +00007079 "})()")->BooleanValue());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007080 CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
ager@chromium.org04921a82011-06-27 13:21:41 +00007081}
7082
7083
ager@chromium.org5c838252010-02-19 08:53:10 +00007084THREADED_TEST(SetPrototypeThrows) {
7085 v8::HandleScope handle_scope;
7086 LocalContext context;
7087
7088 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7089
7090 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
7091 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
7092
7093 CHECK(o0->SetPrototype(o1));
7094 // If setting the prototype leads to the cycle, SetPrototype should
7095 // return false and keep VM in sane state.
7096 v8::TryCatch try_catch;
7097 CHECK(!o1->SetPrototype(o0));
7098 CHECK(!try_catch.HasCaught());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007099 ASSERT(!i::Isolate::Current()->has_pending_exception());
ager@chromium.org5c838252010-02-19 08:53:10 +00007100
7101 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
7102}
7103
7104
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007105THREADED_TEST(GetterSetterExceptions) {
7106 v8::HandleScope handle_scope;
7107 LocalContext context;
7108 CompileRun(
7109 "function Foo() { };"
7110 "function Throw() { throw 5; };"
7111 "var x = { };"
7112 "x.__defineSetter__('set', Throw);"
7113 "x.__defineGetter__('get', Throw);");
7114 Local<v8::Object> x =
7115 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
7116 v8::TryCatch try_catch;
7117 x->Set(v8_str("set"), v8::Integer::New(8));
7118 x->Get(v8_str("get"));
7119 x->Set(v8_str("set"), v8::Integer::New(8));
7120 x->Get(v8_str("get"));
7121 x->Set(v8_str("set"), v8::Integer::New(8));
7122 x->Get(v8_str("get"));
7123 x->Set(v8_str("set"), v8::Integer::New(8));
7124 x->Get(v8_str("get"));
7125}
7126
7127
7128THREADED_TEST(Constructor) {
7129 v8::HandleScope handle_scope;
7130 LocalContext context;
7131 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7132 templ->SetClassName(v8_str("Fun"));
7133 Local<Function> cons = templ->GetFunction();
7134 context->Global()->Set(v8_str("Fun"), cons);
7135 Local<v8::Object> inst = cons->NewInstance();
7136 i::Handle<i::JSObject> obj = v8::Utils::OpenHandle(*inst);
7137 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
7138 CHECK(value->BooleanValue());
7139}
7140
lrn@chromium.org1c092762011-05-09 09:42:16 +00007141
7142static Handle<Value> ConstructorCallback(const Arguments& args) {
7143 ApiTestFuzzer::Fuzz();
7144 Local<Object> This;
7145
7146 if (args.IsConstructCall()) {
7147 Local<Object> Holder = args.Holder();
7148 This = Object::New();
7149 Local<Value> proto = Holder->GetPrototype();
7150 if (proto->IsObject()) {
7151 This->SetPrototype(proto);
7152 }
7153 } else {
7154 This = args.This();
7155 }
7156
7157 This->Set(v8_str("a"), args[0]);
7158 return This;
7159}
7160
7161
7162static Handle<Value> FakeConstructorCallback(const Arguments& args) {
7163 ApiTestFuzzer::Fuzz();
7164 return args[0];
7165}
7166
7167
7168THREADED_TEST(ConstructorForObject) {
7169 v8::HandleScope handle_scope;
7170 LocalContext context;
7171
7172 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7173 instance_template->SetCallAsFunctionHandler(ConstructorCallback);
7174 Local<Object> instance = instance_template->NewInstance();
7175 context->Global()->Set(v8_str("obj"), instance);
7176 v8::TryCatch try_catch;
7177 Local<Value> value;
7178 CHECK(!try_catch.HasCaught());
7179
7180 // Call the Object's constructor with a 32-bit signed integer.
7181 value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
7182 CHECK(!try_catch.HasCaught());
7183 CHECK(value->IsInt32());
7184 CHECK_EQ(28, value->Int32Value());
7185
7186 Local<Value> args1[] = { v8_num(28) };
7187 Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
7188 CHECK(value_obj1->IsObject());
7189 Local<Object> object1 = Local<Object>::Cast(value_obj1);
7190 value = object1->Get(v8_str("a"));
7191 CHECK(value->IsInt32());
7192 CHECK(!try_catch.HasCaught());
7193 CHECK_EQ(28, value->Int32Value());
7194
7195 // Call the Object's constructor with a String.
7196 value = CompileRun(
7197 "(function() { var o = new obj('tipli'); return o.a; })()");
7198 CHECK(!try_catch.HasCaught());
7199 CHECK(value->IsString());
7200 String::AsciiValue string_value1(value->ToString());
7201 CHECK_EQ("tipli", *string_value1);
7202
7203 Local<Value> args2[] = { v8_str("tipli") };
7204 Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
7205 CHECK(value_obj2->IsObject());
7206 Local<Object> object2 = Local<Object>::Cast(value_obj2);
7207 value = object2->Get(v8_str("a"));
7208 CHECK(!try_catch.HasCaught());
7209 CHECK(value->IsString());
7210 String::AsciiValue string_value2(value->ToString());
7211 CHECK_EQ("tipli", *string_value2);
7212
7213 // Call the Object's constructor with a Boolean.
7214 value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
7215 CHECK(!try_catch.HasCaught());
7216 CHECK(value->IsBoolean());
7217 CHECK_EQ(true, value->BooleanValue());
7218
7219 Handle<Value> args3[] = { v8::Boolean::New(true) };
7220 Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
7221 CHECK(value_obj3->IsObject());
7222 Local<Object> object3 = Local<Object>::Cast(value_obj3);
7223 value = object3->Get(v8_str("a"));
7224 CHECK(!try_catch.HasCaught());
7225 CHECK(value->IsBoolean());
7226 CHECK_EQ(true, value->BooleanValue());
7227
7228 // Call the Object's constructor with undefined.
7229 Handle<Value> args4[] = { v8::Undefined() };
7230 Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
7231 CHECK(value_obj4->IsObject());
7232 Local<Object> object4 = Local<Object>::Cast(value_obj4);
7233 value = object4->Get(v8_str("a"));
7234 CHECK(!try_catch.HasCaught());
7235 CHECK(value->IsUndefined());
7236
7237 // Call the Object's constructor with null.
7238 Handle<Value> args5[] = { v8::Null() };
7239 Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
7240 CHECK(value_obj5->IsObject());
7241 Local<Object> object5 = Local<Object>::Cast(value_obj5);
7242 value = object5->Get(v8_str("a"));
7243 CHECK(!try_catch.HasCaught());
7244 CHECK(value->IsNull());
7245 }
7246
7247 // Check exception handling when there is no constructor set for the Object.
7248 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7249 Local<Object> instance = instance_template->NewInstance();
7250 context->Global()->Set(v8_str("obj2"), instance);
7251 v8::TryCatch try_catch;
7252 Local<Value> value;
7253 CHECK(!try_catch.HasCaught());
7254
7255 value = CompileRun("new obj2(28)");
7256 CHECK(try_catch.HasCaught());
7257 String::AsciiValue exception_value1(try_catch.Exception());
7258 CHECK_EQ("TypeError: object is not a function", *exception_value1);
7259 try_catch.Reset();
7260
7261 Local<Value> args[] = { v8_num(29) };
7262 value = instance->CallAsConstructor(1, args);
7263 CHECK(try_catch.HasCaught());
7264 String::AsciiValue exception_value2(try_catch.Exception());
7265 CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
7266 try_catch.Reset();
7267 }
7268
7269 // Check the case when constructor throws exception.
7270 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7271 instance_template->SetCallAsFunctionHandler(ThrowValue);
7272 Local<Object> instance = instance_template->NewInstance();
7273 context->Global()->Set(v8_str("obj3"), instance);
7274 v8::TryCatch try_catch;
7275 Local<Value> value;
7276 CHECK(!try_catch.HasCaught());
7277
7278 value = CompileRun("new obj3(22)");
7279 CHECK(try_catch.HasCaught());
7280 String::AsciiValue exception_value1(try_catch.Exception());
7281 CHECK_EQ("22", *exception_value1);
7282 try_catch.Reset();
7283
7284 Local<Value> args[] = { v8_num(23) };
7285 value = instance->CallAsConstructor(1, args);
7286 CHECK(try_catch.HasCaught());
7287 String::AsciiValue exception_value2(try_catch.Exception());
7288 CHECK_EQ("23", *exception_value2);
7289 try_catch.Reset();
7290 }
7291
7292 // Check whether constructor returns with an object or non-object.
7293 { Local<FunctionTemplate> function_template =
7294 FunctionTemplate::New(FakeConstructorCallback);
7295 Local<Function> function = function_template->GetFunction();
7296 Local<Object> instance1 = function;
7297 context->Global()->Set(v8_str("obj4"), instance1);
7298 v8::TryCatch try_catch;
7299 Local<Value> value;
7300 CHECK(!try_catch.HasCaught());
7301
7302 CHECK(instance1->IsObject());
7303 CHECK(instance1->IsFunction());
7304
7305 value = CompileRun("new obj4(28)");
7306 CHECK(!try_catch.HasCaught());
7307 CHECK(value->IsObject());
7308
7309 Local<Value> args1[] = { v8_num(28) };
7310 value = instance1->CallAsConstructor(1, args1);
7311 CHECK(!try_catch.HasCaught());
7312 CHECK(value->IsObject());
7313
7314 Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7315 instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
7316 Local<Object> instance2 = instance_template->NewInstance();
7317 context->Global()->Set(v8_str("obj5"), instance2);
7318 CHECK(!try_catch.HasCaught());
7319
7320 CHECK(instance2->IsObject());
7321 CHECK(!instance2->IsFunction());
7322
7323 value = CompileRun("new obj5(28)");
7324 CHECK(!try_catch.HasCaught());
7325 CHECK(!value->IsObject());
7326
7327 Local<Value> args2[] = { v8_num(28) };
7328 value = instance2->CallAsConstructor(1, args2);
7329 CHECK(!try_catch.HasCaught());
7330 CHECK(!value->IsObject());
7331 }
7332}
7333
7334
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007335THREADED_TEST(FunctionDescriptorException) {
7336 v8::HandleScope handle_scope;
7337 LocalContext context;
7338 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7339 templ->SetClassName(v8_str("Fun"));
7340 Local<Function> cons = templ->GetFunction();
7341 context->Global()->Set(v8_str("Fun"), cons);
7342 Local<Value> value = CompileRun(
7343 "function test() {"
7344 " try {"
7345 " (new Fun()).blah()"
7346 " } catch (e) {"
7347 " var str = String(e);"
7348 " if (str.indexOf('TypeError') == -1) return 1;"
7349 " if (str.indexOf('[object Fun]') != -1) return 2;"
whesse@chromium.org7a392b32011-01-31 11:30:36 +00007350 " if (str.indexOf('#<Fun>') == -1) return 3;"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007351 " return 0;"
7352 " }"
7353 " return 4;"
7354 "}"
7355 "test();");
7356 CHECK_EQ(0, value->Int32Value());
7357}
7358
7359
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007360THREADED_TEST(EvalAliasedDynamic) {
7361 v8::HandleScope scope;
7362 LocalContext current;
7363
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007364 // Tests where aliased eval can only be resolved dynamically.
7365 Local<Script> script =
7366 Script::Compile(v8_str("function f(x) { "
7367 " var foo = 2;"
7368 " with (x) { return eval('foo'); }"
7369 "}"
7370 "foo = 0;"
7371 "result1 = f(new Object());"
ager@chromium.orge2902be2009-06-08 12:21:35 +00007372 "result2 = f(this);"
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007373 "var x = new Object();"
7374 "x.eval = function(x) { return 1; };"
7375 "result3 = f(x);"));
7376 script->Run();
7377 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
7378 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
7379 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
7380
7381 v8::TryCatch try_catch;
7382 script =
7383 Script::Compile(v8_str("function f(x) { "
7384 " var bar = 2;"
7385 " with (x) { return eval('bar'); }"
7386 "}"
ager@chromium.orge2902be2009-06-08 12:21:35 +00007387 "f(this)"));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007388 script->Run();
7389 CHECK(try_catch.HasCaught());
7390 try_catch.Reset();
7391}
7392
7393
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007394THREADED_TEST(CrossEval) {
7395 v8::HandleScope scope;
7396 LocalContext other;
7397 LocalContext current;
7398
7399 Local<String> token = v8_str("<security token>");
7400 other->SetSecurityToken(token);
7401 current->SetSecurityToken(token);
7402
7403 // Setup reference from current to other.
7404 current->Global()->Set(v8_str("other"), other->Global());
7405
7406 // Check that new variables are introduced in other context.
7407 Local<Script> script =
7408 Script::Compile(v8_str("other.eval('var foo = 1234')"));
7409 script->Run();
7410 Local<Value> foo = other->Global()->Get(v8_str("foo"));
7411 CHECK_EQ(1234, foo->Int32Value());
7412 CHECK(!current->Global()->Has(v8_str("foo")));
7413
7414 // Check that writing to non-existing properties introduces them in
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007415 // the other context.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007416 script =
7417 Script::Compile(v8_str("other.eval('na = 1234')"));
7418 script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007419 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
7420 CHECK(!current->Global()->Has(v8_str("na")));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007421
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007422 // Check that global variables in current context are not visible in other
7423 // context.
7424 v8::TryCatch try_catch;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007425 script =
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007426 Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007427 Local<Value> result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007428 CHECK(try_catch.HasCaught());
7429 try_catch.Reset();
7430
7431 // Check that local variables in current context are not visible in other
7432 // context.
7433 script =
7434 Script::Compile(v8_str("(function() { "
7435 " var baz = 87;"
7436 " return other.eval('baz');"
7437 "})();"));
7438 result = script->Run();
7439 CHECK(try_catch.HasCaught());
7440 try_catch.Reset();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007441
7442 // Check that global variables in the other environment are visible
7443 // when evaluting code.
7444 other->Global()->Set(v8_str("bis"), v8_num(1234));
7445 script = Script::Compile(v8_str("other.eval('bis')"));
7446 CHECK_EQ(1234, script->Run()->Int32Value());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007447 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007448
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007449 // Check that the 'this' pointer points to the global object evaluating
7450 // code.
7451 other->Global()->Set(v8_str("t"), other->Global());
7452 script = Script::Compile(v8_str("other.eval('this == t')"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007453 result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007454 CHECK(result->IsTrue());
7455 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007456
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007457 // Check that variables introduced in with-statement are not visible in
7458 // other context.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007459 script =
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007460 Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007461 result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007462 CHECK(try_catch.HasCaught());
7463 try_catch.Reset();
ager@chromium.org3bf7b912008-11-17 09:09:45 +00007464
7465 // Check that you cannot use 'eval.call' with another object than the
7466 // current global object.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00007467 script =
7468 Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
7469 result = script->Run();
7470 CHECK(try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007471}
7472
7473
ager@chromium.orge2902be2009-06-08 12:21:35 +00007474// Test that calling eval in a context which has been detached from
7475// its global throws an exception. This behavior is consistent with
7476// other JavaScript implementations.
7477THREADED_TEST(EvalInDetachedGlobal) {
7478 v8::HandleScope scope;
7479
7480 v8::Persistent<Context> context0 = Context::New();
7481 v8::Persistent<Context> context1 = Context::New();
7482
7483 // Setup function in context0 that uses eval from context0.
7484 context0->Enter();
7485 v8::Handle<v8::Value> fun =
7486 CompileRun("var x = 42;"
7487 "(function() {"
7488 " var e = eval;"
7489 " return function(s) { return e(s); }"
7490 "})()");
7491 context0->Exit();
7492
7493 // Put the function into context1 and call it before and after
7494 // detaching the global. Before detaching, the call succeeds and
7495 // after detaching and exception is thrown.
7496 context1->Enter();
7497 context1->Global()->Set(v8_str("fun"), fun);
7498 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
7499 CHECK_EQ(42, x_value->Int32Value());
7500 context0->DetachGlobal();
7501 v8::TryCatch catcher;
7502 x_value = CompileRun("fun('x')");
7503 CHECK(x_value.IsEmpty());
7504 CHECK(catcher.HasCaught());
7505 context1->Exit();
7506
7507 context1.Dispose();
7508 context0.Dispose();
7509}
7510
7511
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007512THREADED_TEST(CrossLazyLoad) {
7513 v8::HandleScope scope;
7514 LocalContext other;
7515 LocalContext current;
7516
7517 Local<String> token = v8_str("<security token>");
7518 other->SetSecurityToken(token);
7519 current->SetSecurityToken(token);
7520
7521 // Setup reference from current to other.
7522 current->Global()->Set(v8_str("other"), other->Global());
7523
7524 // Trigger lazy loading in other context.
7525 Local<Script> script =
7526 Script::Compile(v8_str("other.eval('new Date(42)')"));
7527 Local<Value> value = script->Run();
7528 CHECK_EQ(42.0, value->NumberValue());
7529}
7530
7531
7532static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
7533 ApiTestFuzzer::Fuzz();
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00007534 if (args.IsConstructCall()) {
7535 if (args[0]->IsInt32()) {
7536 return v8_num(-args[0]->Int32Value());
7537 }
7538 }
7539
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007540 return args[0];
7541}
7542
7543
7544// Test that a call handler can be set for objects which will allow
7545// non-function objects created through the API to be called as
7546// functions.
7547THREADED_TEST(CallAsFunction) {
7548 v8::HandleScope scope;
7549 LocalContext context;
7550
lrn@chromium.org1c092762011-05-09 09:42:16 +00007551 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7552 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7553 instance_template->SetCallAsFunctionHandler(call_as_function);
7554 Local<v8::Object> instance = t->GetFunction()->NewInstance();
7555 context->Global()->Set(v8_str("obj"), instance);
7556 v8::TryCatch try_catch;
7557 Local<Value> value;
7558 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007559
lrn@chromium.org1c092762011-05-09 09:42:16 +00007560 value = CompileRun("obj(42)");
7561 CHECK(!try_catch.HasCaught());
7562 CHECK_EQ(42, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007563
lrn@chromium.org1c092762011-05-09 09:42:16 +00007564 value = CompileRun("(function(o){return o(49)})(obj)");
7565 CHECK(!try_catch.HasCaught());
7566 CHECK_EQ(49, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007567
lrn@chromium.org1c092762011-05-09 09:42:16 +00007568 // test special case of call as function
7569 value = CompileRun("[obj]['0'](45)");
7570 CHECK(!try_catch.HasCaught());
7571 CHECK_EQ(45, value->Int32Value());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007572
lrn@chromium.org1c092762011-05-09 09:42:16 +00007573 value = CompileRun("obj.call = Function.prototype.call;"
7574 "obj.call(null, 87)");
7575 CHECK(!try_catch.HasCaught());
7576 CHECK_EQ(87, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007577
lrn@chromium.org1c092762011-05-09 09:42:16 +00007578 // Regression tests for bug #1116356: Calling call through call/apply
7579 // must work for non-function receivers.
7580 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
7581 value = CompileRun(apply_99);
7582 CHECK(!try_catch.HasCaught());
7583 CHECK_EQ(99, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007584
lrn@chromium.org1c092762011-05-09 09:42:16 +00007585 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
7586 value = CompileRun(call_17);
7587 CHECK(!try_catch.HasCaught());
7588 CHECK_EQ(17, value->Int32Value());
ager@chromium.org9085a012009-05-11 19:22:57 +00007589
lrn@chromium.org1c092762011-05-09 09:42:16 +00007590 // Check that the call-as-function handler can be called through
7591 // new.
7592 value = CompileRun("new obj(43)");
7593 CHECK(!try_catch.HasCaught());
7594 CHECK_EQ(-43, value->Int32Value());
7595
7596 // Check that the call-as-function handler can be called through
7597 // the API.
7598 v8::Handle<Value> args[] = { v8_num(28) };
7599 value = instance->CallAsFunction(instance, 1, args);
7600 CHECK(!try_catch.HasCaught());
7601 CHECK_EQ(28, value->Int32Value());
7602 }
7603
7604 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7605 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7606 Local<v8::Object> instance = t->GetFunction()->NewInstance();
7607 context->Global()->Set(v8_str("obj2"), instance);
7608 v8::TryCatch try_catch;
7609 Local<Value> value;
7610 CHECK(!try_catch.HasCaught());
7611
7612 // Call an object without call-as-function handler through the JS
7613 value = CompileRun("obj2(28)");
7614 CHECK(value.IsEmpty());
7615 CHECK(try_catch.HasCaught());
7616 String::AsciiValue exception_value1(try_catch.Exception());
7617 CHECK_EQ("TypeError: Property 'obj2' of object #<Object> is not a function",
7618 *exception_value1);
7619 try_catch.Reset();
7620
7621 // Call an object without call-as-function handler through the API
7622 value = CompileRun("obj2(28)");
7623 v8::Handle<Value> args[] = { v8_num(28) };
7624 value = instance->CallAsFunction(instance, 1, args);
7625 CHECK(value.IsEmpty());
7626 CHECK(try_catch.HasCaught());
7627 String::AsciiValue exception_value2(try_catch.Exception());
7628 CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
7629 try_catch.Reset();
7630 }
7631
7632 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7633 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7634 instance_template->SetCallAsFunctionHandler(ThrowValue);
7635 Local<v8::Object> instance = t->GetFunction()->NewInstance();
7636 context->Global()->Set(v8_str("obj3"), instance);
7637 v8::TryCatch try_catch;
7638 Local<Value> value;
7639 CHECK(!try_catch.HasCaught());
7640
7641 // Catch the exception which is thrown by call-as-function handler
7642 value = CompileRun("obj3(22)");
7643 CHECK(try_catch.HasCaught());
7644 String::AsciiValue exception_value1(try_catch.Exception());
7645 CHECK_EQ("22", *exception_value1);
7646 try_catch.Reset();
7647
7648 v8::Handle<Value> args[] = { v8_num(23) };
7649 value = instance->CallAsFunction(instance, 1, args);
7650 CHECK(try_catch.HasCaught());
7651 String::AsciiValue exception_value2(try_catch.Exception());
7652 CHECK_EQ("23", *exception_value2);
7653 try_catch.Reset();
7654 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007655}
7656
7657
karlklose@chromium.org83a47282011-05-11 11:54:09 +00007658// Check whether a non-function object is callable.
7659THREADED_TEST(CallableObject) {
7660 v8::HandleScope scope;
7661 LocalContext context;
7662
7663 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7664 instance_template->SetCallAsFunctionHandler(call_as_function);
7665 Local<Object> instance = instance_template->NewInstance();
7666 v8::TryCatch try_catch;
7667
7668 CHECK(instance->IsCallable());
7669 CHECK(!try_catch.HasCaught());
7670 }
7671
7672 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7673 Local<Object> instance = instance_template->NewInstance();
7674 v8::TryCatch try_catch;
7675
7676 CHECK(!instance->IsCallable());
7677 CHECK(!try_catch.HasCaught());
7678 }
7679
7680 { Local<FunctionTemplate> function_template =
7681 FunctionTemplate::New(call_as_function);
7682 Local<Function> function = function_template->GetFunction();
7683 Local<Object> instance = function;
7684 v8::TryCatch try_catch;
7685
7686 CHECK(instance->IsCallable());
7687 CHECK(!try_catch.HasCaught());
7688 }
7689
7690 { Local<FunctionTemplate> function_template = FunctionTemplate::New();
7691 Local<Function> function = function_template->GetFunction();
7692 Local<Object> instance = function;
7693 v8::TryCatch try_catch;
7694
7695 CHECK(instance->IsCallable());
7696 CHECK(!try_catch.HasCaught());
7697 }
7698}
7699
7700
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007701static int CountHandles() {
7702 return v8::HandleScope::NumberOfHandles();
7703}
7704
7705
7706static int Recurse(int depth, int iterations) {
7707 v8::HandleScope scope;
7708 if (depth == 0) return CountHandles();
7709 for (int i = 0; i < iterations; i++) {
7710 Local<v8::Number> n = v8::Integer::New(42);
7711 }
7712 return Recurse(depth - 1, iterations);
7713}
7714
7715
7716THREADED_TEST(HandleIteration) {
7717 static const int kIterations = 500;
7718 static const int kNesting = 200;
7719 CHECK_EQ(0, CountHandles());
7720 {
7721 v8::HandleScope scope1;
7722 CHECK_EQ(0, CountHandles());
7723 for (int i = 0; i < kIterations; i++) {
7724 Local<v8::Number> n = v8::Integer::New(42);
7725 CHECK_EQ(i + 1, CountHandles());
7726 }
7727
7728 CHECK_EQ(kIterations, CountHandles());
7729 {
7730 v8::HandleScope scope2;
7731 for (int j = 0; j < kIterations; j++) {
7732 Local<v8::Number> n = v8::Integer::New(42);
7733 CHECK_EQ(j + 1 + kIterations, CountHandles());
7734 }
7735 }
7736 CHECK_EQ(kIterations, CountHandles());
7737 }
7738 CHECK_EQ(0, CountHandles());
7739 CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
7740}
7741
7742
7743static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
7744 Local<String> name,
7745 const AccessorInfo& info) {
7746 ApiTestFuzzer::Fuzz();
7747 return v8::Handle<Value>();
7748}
7749
7750
7751THREADED_TEST(InterceptorHasOwnProperty) {
7752 v8::HandleScope scope;
7753 LocalContext context;
7754 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7755 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
7756 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
7757 Local<Function> function = fun_templ->GetFunction();
7758 context->Global()->Set(v8_str("constructor"), function);
7759 v8::Handle<Value> value = CompileRun(
7760 "var o = new constructor();"
7761 "o.hasOwnProperty('ostehaps');");
7762 CHECK_EQ(false, value->BooleanValue());
7763 value = CompileRun(
7764 "o.ostehaps = 42;"
7765 "o.hasOwnProperty('ostehaps');");
7766 CHECK_EQ(true, value->BooleanValue());
7767 value = CompileRun(
7768 "var p = new constructor();"
7769 "p.hasOwnProperty('ostehaps');");
7770 CHECK_EQ(false, value->BooleanValue());
7771}
7772
7773
ager@chromium.org9085a012009-05-11 19:22:57 +00007774static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
7775 Local<String> name,
7776 const AccessorInfo& info) {
7777 ApiTestFuzzer::Fuzz();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007778 HEAP->CollectAllGarbage(false);
ager@chromium.org9085a012009-05-11 19:22:57 +00007779 return v8::Handle<Value>();
7780}
7781
7782
7783THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
7784 v8::HandleScope scope;
7785 LocalContext context;
7786 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7787 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
7788 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
7789 Local<Function> function = fun_templ->GetFunction();
7790 context->Global()->Set(v8_str("constructor"), function);
7791 // Let's first make some stuff so we can be sure to get a good GC.
7792 CompileRun(
7793 "function makestr(size) {"
7794 " switch (size) {"
7795 " case 1: return 'f';"
7796 " case 2: return 'fo';"
7797 " case 3: return 'foo';"
7798 " }"
7799 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
7800 "}"
7801 "var x = makestr(12345);"
7802 "x = makestr(31415);"
7803 "x = makestr(23456);");
7804 v8::Handle<Value> value = CompileRun(
7805 "var o = new constructor();"
7806 "o.__proto__ = new String(x);"
7807 "o.hasOwnProperty('ostehaps');");
7808 CHECK_EQ(false, value->BooleanValue());
7809}
7810
7811
ager@chromium.orge2902be2009-06-08 12:21:35 +00007812typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
7813 const AccessorInfo& info);
7814
7815
7816static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
7817 const char* source,
7818 int expected) {
7819 v8::HandleScope scope;
7820 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007821 templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
ager@chromium.orge2902be2009-06-08 12:21:35 +00007822 LocalContext context;
7823 context->Global()->Set(v8_str("o"), templ->NewInstance());
7824 v8::Handle<Value> value = CompileRun(source);
7825 CHECK_EQ(expected, value->Int32Value());
7826}
7827
7828
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007829static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
7830 const AccessorInfo& info) {
7831 ApiTestFuzzer::Fuzz();
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007832 CHECK_EQ(v8_str("data"), info.Data());
7833 CHECK_EQ(v8_str("x"), name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007834 return v8::Integer::New(42);
7835}
7836
7837
7838// This test should hit the load IC for the interceptor case.
7839THREADED_TEST(InterceptorLoadIC) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00007840 CheckInterceptorLoadIC(InterceptorLoadICGetter,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007841 "var result = 0;"
7842 "for (var i = 0; i < 1000; i++) {"
7843 " result = o.x;"
ager@chromium.orge2902be2009-06-08 12:21:35 +00007844 "}",
7845 42);
7846}
7847
7848
7849// Below go several tests which verify that JITing for various
7850// configurations of interceptor and explicit fields works fine
7851// (those cases are special cased to get better performance).
7852
7853static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
7854 const AccessorInfo& info) {
7855 ApiTestFuzzer::Fuzz();
7856 return v8_str("x")->Equals(name)
7857 ? v8::Integer::New(42) : v8::Handle<v8::Value>();
7858}
7859
7860
7861THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
7862 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7863 "var result = 0;"
7864 "o.y = 239;"
7865 "for (var i = 0; i < 1000; i++) {"
7866 " result = o.y;"
7867 "}",
7868 239);
7869}
7870
7871
7872THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
7873 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7874 "var result = 0;"
7875 "o.__proto__ = { 'y': 239 };"
7876 "for (var i = 0; i < 1000; i++) {"
7877 " result = o.y + o.x;"
7878 "}",
7879 239 + 42);
7880}
7881
7882
7883THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
7884 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7885 "var result = 0;"
7886 "o.__proto__.y = 239;"
7887 "for (var i = 0; i < 1000; i++) {"
7888 " result = o.y + o.x;"
7889 "}",
7890 239 + 42);
7891}
7892
7893
7894THREADED_TEST(InterceptorLoadICUndefined) {
7895 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7896 "var result = 0;"
7897 "for (var i = 0; i < 1000; i++) {"
7898 " result = (o.y == undefined) ? 239 : 42;"
7899 "}",
7900 239);
7901}
7902
7903
7904THREADED_TEST(InterceptorLoadICWithOverride) {
7905 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7906 "fst = new Object(); fst.__proto__ = o;"
7907 "snd = new Object(); snd.__proto__ = fst;"
7908 "var result1 = 0;"
7909 "for (var i = 0; i < 1000; i++) {"
7910 " result1 = snd.x;"
7911 "}"
7912 "fst.x = 239;"
7913 "var result = 0;"
7914 "for (var i = 0; i < 1000; i++) {"
7915 " result = snd.x;"
7916 "}"
7917 "result + result1",
7918 239 + 42);
7919}
7920
7921
kasperl@chromium.orge959c182009-07-27 08:59:04 +00007922// Test the case when we stored field into
7923// a stub, but interceptor produced value on its own.
7924THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
7925 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7926 "proto = new Object();"
7927 "o.__proto__ = proto;"
7928 "proto.x = 239;"
7929 "for (var i = 0; i < 1000; i++) {"
7930 " o.x;"
7931 // Now it should be ICed and keep a reference to x defined on proto
7932 "}"
7933 "var result = 0;"
7934 "for (var i = 0; i < 1000; i++) {"
7935 " result += o.x;"
7936 "}"
7937 "result;",
7938 42 * 1000);
7939}
7940
7941
7942// Test the case when we stored field into
7943// a stub, but it got invalidated later on.
7944THREADED_TEST(InterceptorLoadICInvalidatedField) {
7945 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7946 "proto1 = new Object();"
7947 "proto2 = new Object();"
7948 "o.__proto__ = proto1;"
7949 "proto1.__proto__ = proto2;"
7950 "proto2.y = 239;"
7951 "for (var i = 0; i < 1000; i++) {"
7952 " o.y;"
7953 // Now it should be ICed and keep a reference to y defined on proto2
7954 "}"
7955 "proto1.y = 42;"
7956 "var result = 0;"
7957 "for (var i = 0; i < 1000; i++) {"
7958 " result += o.y;"
7959 "}"
7960 "result;",
7961 42 * 1000);
7962}
7963
7964
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00007965static int interceptor_load_not_handled_calls = 0;
7966static v8::Handle<Value> InterceptorLoadNotHandled(Local<String> name,
7967 const AccessorInfo& info) {
7968 ++interceptor_load_not_handled_calls;
7969 return v8::Handle<v8::Value>();
7970}
7971
7972
7973// Test how post-interceptor lookups are done in the non-cacheable
7974// case: the interceptor should not be invoked during this lookup.
7975THREADED_TEST(InterceptorLoadICPostInterceptor) {
7976 interceptor_load_not_handled_calls = 0;
7977 CheckInterceptorLoadIC(InterceptorLoadNotHandled,
7978 "receiver = new Object();"
7979 "receiver.__proto__ = o;"
7980 "proto = new Object();"
7981 "/* Make proto a slow-case object. */"
7982 "for (var i = 0; i < 1000; i++) {"
7983 " proto[\"xxxxxxxx\" + i] = [];"
7984 "}"
7985 "proto.x = 17;"
7986 "o.__proto__ = proto;"
7987 "var result = 0;"
7988 "for (var i = 0; i < 1000; i++) {"
7989 " result += receiver.x;"
7990 "}"
7991 "result;",
7992 17 * 1000);
7993 CHECK_EQ(1000, interceptor_load_not_handled_calls);
7994}
7995
7996
kasperl@chromium.orge959c182009-07-27 08:59:04 +00007997// Test the case when we stored field into
7998// a stub, but it got invalidated later on due to override on
7999// global object which is between interceptor and fields' holders.
8000THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
8001 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8002 "o.__proto__ = this;" // set a global to be a proto of o.
8003 "this.__proto__.y = 239;"
8004 "for (var i = 0; i < 10; i++) {"
8005 " if (o.y != 239) throw 'oops: ' + o.y;"
8006 // Now it should be ICed and keep a reference to y defined on field_holder.
8007 "}"
8008 "this.y = 42;" // Assign on a global.
8009 "var result = 0;"
8010 "for (var i = 0; i < 10; i++) {"
8011 " result += o.y;"
8012 "}"
8013 "result;",
8014 42 * 10);
8015}
8016
8017
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008018static void SetOnThis(Local<String> name,
8019 Local<Value> value,
8020 const AccessorInfo& info) {
8021 info.This()->ForceSet(name, value);
8022}
8023
8024
8025THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
8026 v8::HandleScope scope;
8027 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8028 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8029 templ->SetAccessor(v8_str("y"), Return239);
8030 LocalContext context;
8031 context->Global()->Set(v8_str("o"), templ->NewInstance());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008032
8033 // Check the case when receiver and interceptor's holder
8034 // are the same objects.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008035 v8::Handle<Value> value = CompileRun(
8036 "var result = 0;"
8037 "for (var i = 0; i < 7; i++) {"
8038 " result = o.y;"
8039 "}");
8040 CHECK_EQ(239, value->Int32Value());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008041
8042 // Check the case when interceptor's holder is in proto chain
8043 // of receiver.
8044 value = CompileRun(
8045 "r = { __proto__: o };"
8046 "var result = 0;"
8047 "for (var i = 0; i < 7; i++) {"
8048 " result = r.y;"
8049 "}");
8050 CHECK_EQ(239, value->Int32Value());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008051}
8052
8053
8054THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
8055 v8::HandleScope scope;
8056 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8057 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8058 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8059 templ_p->SetAccessor(v8_str("y"), Return239);
8060
8061 LocalContext context;
8062 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8063 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8064
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008065 // Check the case when receiver and interceptor's holder
8066 // are the same objects.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008067 v8::Handle<Value> value = CompileRun(
8068 "o.__proto__ = p;"
8069 "var result = 0;"
8070 "for (var i = 0; i < 7; i++) {"
8071 " result = o.x + o.y;"
8072 "}");
8073 CHECK_EQ(239 + 42, value->Int32Value());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008074
8075 // Check the case when interceptor's holder is in proto chain
8076 // of receiver.
8077 value = CompileRun(
8078 "r = { __proto__: o };"
8079 "var result = 0;"
8080 "for (var i = 0; i < 7; i++) {"
8081 " result = r.x + r.y;"
8082 "}");
8083 CHECK_EQ(239 + 42, value->Int32Value());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008084}
8085
8086
8087THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
8088 v8::HandleScope scope;
8089 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8090 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8091 templ->SetAccessor(v8_str("y"), Return239);
8092
8093 LocalContext context;
8094 context->Global()->Set(v8_str("o"), templ->NewInstance());
8095
8096 v8::Handle<Value> value = CompileRun(
8097 "fst = new Object(); fst.__proto__ = o;"
8098 "snd = new Object(); snd.__proto__ = fst;"
8099 "var result1 = 0;"
8100 "for (var i = 0; i < 7; i++) {"
8101 " result1 = snd.x;"
8102 "}"
8103 "fst.x = 239;"
8104 "var result = 0;"
8105 "for (var i = 0; i < 7; i++) {"
8106 " result = snd.x;"
8107 "}"
8108 "result + result1");
8109 CHECK_EQ(239 + 42, value->Int32Value());
8110}
8111
8112
8113// Test the case when we stored callback into
8114// a stub, but interceptor produced value on its own.
8115THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
8116 v8::HandleScope scope;
8117 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8118 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8119 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8120 templ_p->SetAccessor(v8_str("y"), Return239);
8121
8122 LocalContext context;
8123 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8124 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8125
8126 v8::Handle<Value> value = CompileRun(
8127 "o.__proto__ = p;"
8128 "for (var i = 0; i < 7; i++) {"
8129 " o.x;"
8130 // Now it should be ICed and keep a reference to x defined on p
8131 "}"
8132 "var result = 0;"
8133 "for (var i = 0; i < 7; i++) {"
8134 " result += o.x;"
8135 "}"
8136 "result");
8137 CHECK_EQ(42 * 7, value->Int32Value());
8138}
8139
8140
8141// Test the case when we stored callback into
8142// a stub, but it got invalidated later on.
8143THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
8144 v8::HandleScope scope;
8145 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8146 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8147 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8148 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
8149
8150 LocalContext context;
8151 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8152 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8153
8154 v8::Handle<Value> value = CompileRun(
8155 "inbetween = new Object();"
8156 "o.__proto__ = inbetween;"
8157 "inbetween.__proto__ = p;"
8158 "for (var i = 0; i < 10; i++) {"
8159 " o.y;"
8160 // Now it should be ICed and keep a reference to y defined on p
8161 "}"
8162 "inbetween.y = 42;"
8163 "var result = 0;"
8164 "for (var i = 0; i < 10; i++) {"
8165 " result += o.y;"
8166 "}"
8167 "result");
8168 CHECK_EQ(42 * 10, value->Int32Value());
8169}
8170
8171
8172// Test the case when we stored callback into
8173// a stub, but it got invalidated later on due to override on
8174// global object which is between interceptor and callbacks' holders.
8175THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
8176 v8::HandleScope scope;
8177 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8178 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8179 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8180 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
8181
8182 LocalContext context;
8183 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8184 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8185
8186 v8::Handle<Value> value = CompileRun(
8187 "o.__proto__ = this;"
8188 "this.__proto__ = p;"
8189 "for (var i = 0; i < 10; i++) {"
8190 " if (o.y != 239) throw 'oops: ' + o.y;"
8191 // Now it should be ICed and keep a reference to y defined on p
8192 "}"
8193 "this.y = 42;"
8194 "var result = 0;"
8195 "for (var i = 0; i < 10; i++) {"
8196 " result += o.y;"
8197 "}"
8198 "result");
8199 CHECK_EQ(42 * 10, value->Int32Value());
8200}
8201
8202
ager@chromium.orge2902be2009-06-08 12:21:35 +00008203static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
8204 const AccessorInfo& info) {
8205 ApiTestFuzzer::Fuzz();
8206 CHECK(v8_str("x")->Equals(name));
8207 return v8::Integer::New(0);
8208}
8209
8210
8211THREADED_TEST(InterceptorReturningZero) {
8212 CheckInterceptorLoadIC(InterceptorLoadICGetter0,
8213 "o.x == undefined ? 1 : 0",
8214 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008215}
8216
8217
8218static v8::Handle<Value> InterceptorStoreICSetter(
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008219 Local<String> key, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008220 CHECK(v8_str("x")->Equals(key));
8221 CHECK_EQ(42, value->Int32Value());
8222 return value;
8223}
8224
8225
8226// This test should hit the store IC for the interceptor case.
8227THREADED_TEST(InterceptorStoreIC) {
8228 v8::HandleScope scope;
8229 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8230 templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008231 InterceptorStoreICSetter,
8232 0, 0, 0, v8_str("data"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008233 LocalContext context;
8234 context->Global()->Set(v8_str("o"), templ->NewInstance());
8235 v8::Handle<Value> value = CompileRun(
8236 "for (var i = 0; i < 1000; i++) {"
8237 " o.x = 42;"
8238 "}");
8239}
8240
8241
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008242THREADED_TEST(InterceptorStoreICWithNoSetter) {
8243 v8::HandleScope scope;
8244 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8245 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8246 LocalContext context;
8247 context->Global()->Set(v8_str("o"), templ->NewInstance());
8248 v8::Handle<Value> value = CompileRun(
8249 "for (var i = 0; i < 1000; i++) {"
8250 " o.y = 239;"
8251 "}"
8252 "42 + o.y");
8253 CHECK_EQ(239 + 42, value->Int32Value());
8254}
8255
8256
8257
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008258
8259v8::Handle<Value> call_ic_function;
8260v8::Handle<Value> call_ic_function2;
8261v8::Handle<Value> call_ic_function3;
8262
8263static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
8264 const AccessorInfo& info) {
8265 ApiTestFuzzer::Fuzz();
8266 CHECK(v8_str("x")->Equals(name));
8267 return call_ic_function;
8268}
8269
8270
8271// This test should hit the call IC for the interceptor case.
8272THREADED_TEST(InterceptorCallIC) {
8273 v8::HandleScope scope;
8274 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8275 templ->SetNamedPropertyHandler(InterceptorCallICGetter);
8276 LocalContext context;
8277 context->Global()->Set(v8_str("o"), templ->NewInstance());
8278 call_ic_function =
8279 v8_compile("function f(x) { return x + 1; }; f")->Run();
8280 v8::Handle<Value> value = CompileRun(
8281 "var result = 0;"
8282 "for (var i = 0; i < 1000; i++) {"
8283 " result = o.x(41);"
8284 "}");
8285 CHECK_EQ(42, value->Int32Value());
8286}
8287
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008288
8289// This test checks that if interceptor doesn't provide
8290// a value, we can fetch regular value.
8291THREADED_TEST(InterceptorCallICSeesOthers) {
8292 v8::HandleScope scope;
8293 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8294 templ->SetNamedPropertyHandler(NoBlockGetterX);
8295 LocalContext context;
8296 context->Global()->Set(v8_str("o"), templ->NewInstance());
8297 v8::Handle<Value> value = CompileRun(
8298 "o.x = function f(x) { return x + 1; };"
8299 "var result = 0;"
8300 "for (var i = 0; i < 7; i++) {"
8301 " result = o.x(41);"
8302 "}");
8303 CHECK_EQ(42, value->Int32Value());
8304}
8305
8306
8307static v8::Handle<Value> call_ic_function4;
8308static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
8309 const AccessorInfo& info) {
8310 ApiTestFuzzer::Fuzz();
8311 CHECK(v8_str("x")->Equals(name));
8312 return call_ic_function4;
8313}
8314
8315
8316// This test checks that if interceptor provides a function,
8317// even if we cached shadowed variant, interceptor's function
8318// is invoked
8319THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
8320 v8::HandleScope scope;
8321 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8322 templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
8323 LocalContext context;
8324 context->Global()->Set(v8_str("o"), templ->NewInstance());
8325 call_ic_function4 =
8326 v8_compile("function f(x) { return x - 1; }; f")->Run();
8327 v8::Handle<Value> value = CompileRun(
8328 "o.__proto__.x = function(x) { return x + 1; };"
8329 "var result = 0;"
8330 "for (var i = 0; i < 1000; i++) {"
8331 " result = o.x(42);"
8332 "}");
8333 CHECK_EQ(41, value->Int32Value());
8334}
8335
8336
8337// Test the case when we stored cacheable lookup into
8338// a stub, but it got invalidated later on
8339THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
8340 v8::HandleScope scope;
8341 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8342 templ->SetNamedPropertyHandler(NoBlockGetterX);
8343 LocalContext context;
8344 context->Global()->Set(v8_str("o"), templ->NewInstance());
8345 v8::Handle<Value> value = CompileRun(
8346 "proto1 = new Object();"
8347 "proto2 = new Object();"
8348 "o.__proto__ = proto1;"
8349 "proto1.__proto__ = proto2;"
8350 "proto2.y = function(x) { return x + 1; };"
8351 // Invoke it many times to compile a stub
8352 "for (var i = 0; i < 7; i++) {"
8353 " o.y(42);"
8354 "}"
8355 "proto1.y = function(x) { return x - 1; };"
8356 "var result = 0;"
8357 "for (var i = 0; i < 7; i++) {"
8358 " result += o.y(42);"
8359 "}");
8360 CHECK_EQ(41 * 7, value->Int32Value());
8361}
8362
8363
8364static v8::Handle<Value> call_ic_function5;
8365static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
8366 const AccessorInfo& info) {
8367 ApiTestFuzzer::Fuzz();
8368 if (v8_str("x")->Equals(name))
8369 return call_ic_function5;
8370 else
8371 return Local<Value>();
8372}
8373
8374
8375// This test checks that if interceptor doesn't provide a function,
8376// cached constant function is used
8377THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
8378 v8::HandleScope scope;
8379 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8380 templ->SetNamedPropertyHandler(NoBlockGetterX);
8381 LocalContext context;
8382 context->Global()->Set(v8_str("o"), templ->NewInstance());
8383 v8::Handle<Value> value = CompileRun(
8384 "function inc(x) { return x + 1; };"
8385 "inc(1);"
8386 "o.x = inc;"
8387 "var result = 0;"
8388 "for (var i = 0; i < 1000; i++) {"
8389 " result = o.x(42);"
8390 "}");
8391 CHECK_EQ(43, value->Int32Value());
8392}
8393
8394
8395// This test checks that if interceptor provides a function,
8396// even if we cached constant function, interceptor's function
8397// is invoked
8398THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
8399 v8::HandleScope scope;
8400 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8401 templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
8402 LocalContext context;
8403 context->Global()->Set(v8_str("o"), templ->NewInstance());
8404 call_ic_function5 =
8405 v8_compile("function f(x) { return x - 1; }; f")->Run();
8406 v8::Handle<Value> value = CompileRun(
8407 "function inc(x) { return x + 1; };"
8408 "inc(1);"
8409 "o.x = inc;"
8410 "var result = 0;"
8411 "for (var i = 0; i < 1000; i++) {"
8412 " result = o.x(42);"
8413 "}");
8414 CHECK_EQ(41, value->Int32Value());
8415}
8416
8417
8418// Test the case when we stored constant function into
8419// a stub, but it got invalidated later on
8420THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
8421 v8::HandleScope scope;
8422 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8423 templ->SetNamedPropertyHandler(NoBlockGetterX);
8424 LocalContext context;
8425 context->Global()->Set(v8_str("o"), templ->NewInstance());
8426 v8::Handle<Value> value = CompileRun(
8427 "function inc(x) { return x + 1; };"
8428 "inc(1);"
8429 "proto1 = new Object();"
8430 "proto2 = new Object();"
8431 "o.__proto__ = proto1;"
8432 "proto1.__proto__ = proto2;"
8433 "proto2.y = inc;"
8434 // Invoke it many times to compile a stub
8435 "for (var i = 0; i < 7; i++) {"
8436 " o.y(42);"
8437 "}"
8438 "proto1.y = function(x) { return x - 1; };"
8439 "var result = 0;"
8440 "for (var i = 0; i < 7; i++) {"
8441 " result += o.y(42);"
8442 "}");
8443 CHECK_EQ(41 * 7, value->Int32Value());
8444}
8445
8446
8447// Test the case when we stored constant function into
8448// a stub, but it got invalidated later on due to override on
8449// global object which is between interceptor and constant function' holders.
8450THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
8451 v8::HandleScope scope;
8452 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8453 templ->SetNamedPropertyHandler(NoBlockGetterX);
8454 LocalContext context;
8455 context->Global()->Set(v8_str("o"), templ->NewInstance());
8456 v8::Handle<Value> value = CompileRun(
8457 "function inc(x) { return x + 1; };"
8458 "inc(1);"
8459 "o.__proto__ = this;"
8460 "this.__proto__.y = inc;"
8461 // Invoke it many times to compile a stub
8462 "for (var i = 0; i < 7; i++) {"
8463 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
8464 "}"
8465 "this.y = function(x) { return x - 1; };"
8466 "var result = 0;"
8467 "for (var i = 0; i < 7; i++) {"
8468 " result += o.y(42);"
8469 "}");
8470 CHECK_EQ(41 * 7, value->Int32Value());
8471}
8472
8473
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008474// Test the case when actual function to call sits on global object.
8475THREADED_TEST(InterceptorCallICCachedFromGlobal) {
8476 v8::HandleScope scope;
8477 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8478 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
8479
8480 LocalContext context;
8481 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8482
8483 v8::Handle<Value> value = CompileRun(
8484 "try {"
8485 " o.__proto__ = this;"
8486 " for (var i = 0; i < 10; i++) {"
8487 " var v = o.parseFloat('239');"
8488 " if (v != 239) throw v;"
8489 // Now it should be ICed and keep a reference to parseFloat.
8490 " }"
8491 " var result = 0;"
8492 " for (var i = 0; i < 10; i++) {"
8493 " result += o.parseFloat('239');"
8494 " }"
8495 " result"
8496 "} catch(e) {"
8497 " e"
8498 "};");
8499 CHECK_EQ(239 * 10, value->Int32Value());
8500}
8501
ager@chromium.org5c838252010-02-19 08:53:10 +00008502static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
8503 const AccessorInfo& info) {
8504 ApiTestFuzzer::Fuzz();
8505 int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data()));
8506 ++(*call_count);
8507 if ((*call_count) % 20 == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008508 HEAP->CollectAllGarbage(true);
ager@chromium.org5c838252010-02-19 08:53:10 +00008509 }
8510 return v8::Handle<Value>();
8511}
8512
8513static v8::Handle<Value> FastApiCallback_TrivialSignature(
8514 const v8::Arguments& args) {
8515 ApiTestFuzzer::Fuzz();
8516 CHECK_EQ(args.This(), args.Holder());
8517 CHECK(args.Data()->Equals(v8_str("method_data")));
8518 return v8::Integer::New(args[0]->Int32Value() + 1);
8519}
8520
8521static v8::Handle<Value> FastApiCallback_SimpleSignature(
8522 const v8::Arguments& args) {
8523 ApiTestFuzzer::Fuzz();
8524 CHECK_EQ(args.This()->GetPrototype(), args.Holder());
8525 CHECK(args.Data()->Equals(v8_str("method_data")));
8526 // Note, we're using HasRealNamedProperty instead of Has to avoid
8527 // invoking the interceptor again.
8528 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
8529 return v8::Integer::New(args[0]->Int32Value() + 1);
8530}
8531
8532// Helper to maximize the odds of object moving.
8533static void GenerateSomeGarbage() {
8534 CompileRun(
8535 "var garbage;"
8536 "for (var i = 0; i < 1000; i++) {"
8537 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
8538 "}"
8539 "garbage = undefined;");
8540}
8541
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008542
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008543v8::Handle<v8::Value> DirectApiCallback(const v8::Arguments& args) {
8544 static int count = 0;
8545 if (count++ % 3 == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008546 HEAP-> CollectAllGarbage(true); // This should move the stub
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008547 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
8548 }
8549 return v8::Handle<v8::Value>();
8550}
8551
8552
8553THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
8554 v8::HandleScope scope;
8555 LocalContext context;
8556 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
8557 nativeobject_templ->Set("callback",
8558 v8::FunctionTemplate::New(DirectApiCallback));
8559 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
8560 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
8561 // call the api function multiple times to ensure direct call stub creation.
8562 CompileRun(
8563 "function f() {"
8564 " for (var i = 1; i <= 30; i++) {"
8565 " nativeobject.callback();"
8566 " }"
8567 "}"
8568 "f();");
8569}
8570
8571
8572v8::Handle<v8::Value> ThrowingDirectApiCallback(const v8::Arguments& args) {
8573 return v8::ThrowException(v8_str("g"));
8574}
8575
8576
8577THREADED_TEST(CallICFastApi_DirectCall_Throw) {
8578 v8::HandleScope scope;
8579 LocalContext context;
8580 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
8581 nativeobject_templ->Set("callback",
8582 v8::FunctionTemplate::New(ThrowingDirectApiCallback));
8583 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
8584 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
8585 // call the api function multiple times to ensure direct call stub creation.
8586 v8::Handle<Value> result = CompileRun(
8587 "var result = '';"
8588 "function f() {"
8589 " for (var i = 1; i <= 5; i++) {"
8590 " try { nativeobject.callback(); } catch (e) { result += e; }"
8591 " }"
8592 "}"
8593 "f(); result;");
8594 CHECK_EQ(v8_str("ggggg"), result);
8595}
8596
8597
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008598v8::Handle<v8::Value> DirectGetterCallback(Local<String> name,
8599 const v8::AccessorInfo& info) {
8600 if (++p_getter_count % 3 == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008601 HEAP->CollectAllGarbage(true);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008602 GenerateSomeGarbage();
8603 }
8604 return v8::Handle<v8::Value>();
8605}
8606
8607
8608THREADED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
8609 v8::HandleScope scope;
8610 LocalContext context;
8611 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
8612 obj->SetAccessor(v8_str("p1"), DirectGetterCallback);
8613 context->Global()->Set(v8_str("o1"), obj->NewInstance());
8614 p_getter_count = 0;
8615 CompileRun(
8616 "function f() {"
8617 " for (var i = 0; i < 30; i++) o1.p1;"
8618 "}"
8619 "f();");
8620 CHECK_EQ(30, p_getter_count);
8621}
8622
8623
8624v8::Handle<v8::Value> ThrowingDirectGetterCallback(
8625 Local<String> name, const v8::AccessorInfo& info) {
8626 return v8::ThrowException(v8_str("g"));
8627}
8628
8629
8630THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
8631 v8::HandleScope scope;
8632 LocalContext context;
8633 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
8634 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
8635 context->Global()->Set(v8_str("o1"), obj->NewInstance());
8636 v8::Handle<Value> result = CompileRun(
8637 "var result = '';"
8638 "for (var i = 0; i < 5; i++) {"
8639 " try { o1.p1; } catch (e) { result += e; }"
8640 "}"
8641 "result;");
8642 CHECK_EQ(v8_str("ggggg"), result);
8643}
8644
8645
ager@chromium.org5c838252010-02-19 08:53:10 +00008646THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
8647 int interceptor_call_count = 0;
8648 v8::HandleScope scope;
8649 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8650 v8::Handle<v8::FunctionTemplate> method_templ =
8651 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
8652 v8_str("method_data"),
8653 v8::Handle<v8::Signature>());
8654 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8655 proto_templ->Set(v8_str("method"), method_templ);
8656 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8657 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8658 NULL, NULL, NULL, NULL,
8659 v8::External::Wrap(&interceptor_call_count));
8660 LocalContext context;
8661 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8662 GenerateSomeGarbage();
8663 context->Global()->Set(v8_str("o"), fun->NewInstance());
8664 v8::Handle<Value> value = CompileRun(
8665 "var result = 0;"
8666 "for (var i = 0; i < 100; i++) {"
8667 " result = o.method(41);"
8668 "}");
8669 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
8670 CHECK_EQ(100, interceptor_call_count);
8671}
8672
8673THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
8674 int interceptor_call_count = 0;
8675 v8::HandleScope scope;
8676 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8677 v8::Handle<v8::FunctionTemplate> method_templ =
8678 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8679 v8_str("method_data"),
8680 v8::Signature::New(fun_templ));
8681 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8682 proto_templ->Set(v8_str("method"), method_templ);
8683 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8684 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8685 NULL, NULL, NULL, NULL,
8686 v8::External::Wrap(&interceptor_call_count));
8687 LocalContext context;
8688 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8689 GenerateSomeGarbage();
8690 context->Global()->Set(v8_str("o"), fun->NewInstance());
8691 v8::Handle<Value> value = CompileRun(
8692 "o.foo = 17;"
8693 "var receiver = {};"
8694 "receiver.__proto__ = o;"
8695 "var result = 0;"
8696 "for (var i = 0; i < 100; i++) {"
8697 " result = receiver.method(41);"
8698 "}");
8699 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
8700 CHECK_EQ(100, interceptor_call_count);
8701}
8702
8703THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
8704 int interceptor_call_count = 0;
8705 v8::HandleScope scope;
8706 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8707 v8::Handle<v8::FunctionTemplate> method_templ =
8708 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8709 v8_str("method_data"),
8710 v8::Signature::New(fun_templ));
8711 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8712 proto_templ->Set(v8_str("method"), method_templ);
8713 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8714 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8715 NULL, NULL, NULL, NULL,
8716 v8::External::Wrap(&interceptor_call_count));
8717 LocalContext context;
8718 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8719 GenerateSomeGarbage();
8720 context->Global()->Set(v8_str("o"), fun->NewInstance());
8721 v8::Handle<Value> value = CompileRun(
8722 "o.foo = 17;"
8723 "var receiver = {};"
8724 "receiver.__proto__ = o;"
8725 "var result = 0;"
8726 "var saved_result = 0;"
8727 "for (var i = 0; i < 100; i++) {"
8728 " result = receiver.method(41);"
8729 " if (i == 50) {"
8730 " saved_result = result;"
8731 " receiver = {method: function(x) { return x - 1 }};"
8732 " }"
8733 "}");
8734 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
8735 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8736 CHECK_GE(interceptor_call_count, 50);
8737}
8738
8739THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
8740 int interceptor_call_count = 0;
8741 v8::HandleScope scope;
8742 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8743 v8::Handle<v8::FunctionTemplate> method_templ =
8744 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8745 v8_str("method_data"),
8746 v8::Signature::New(fun_templ));
8747 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8748 proto_templ->Set(v8_str("method"), method_templ);
8749 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8750 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8751 NULL, NULL, NULL, NULL,
8752 v8::External::Wrap(&interceptor_call_count));
8753 LocalContext context;
8754 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8755 GenerateSomeGarbage();
8756 context->Global()->Set(v8_str("o"), fun->NewInstance());
8757 v8::Handle<Value> value = CompileRun(
8758 "o.foo = 17;"
8759 "var receiver = {};"
8760 "receiver.__proto__ = o;"
8761 "var result = 0;"
8762 "var saved_result = 0;"
8763 "for (var i = 0; i < 100; i++) {"
8764 " result = receiver.method(41);"
8765 " if (i == 50) {"
8766 " saved_result = result;"
8767 " o.method = function(x) { return x - 1 };"
8768 " }"
8769 "}");
8770 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
8771 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8772 CHECK_GE(interceptor_call_count, 50);
8773}
8774
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00008775THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
8776 int interceptor_call_count = 0;
8777 v8::HandleScope scope;
8778 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8779 v8::Handle<v8::FunctionTemplate> method_templ =
8780 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8781 v8_str("method_data"),
8782 v8::Signature::New(fun_templ));
8783 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8784 proto_templ->Set(v8_str("method"), method_templ);
8785 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8786 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8787 NULL, NULL, NULL, NULL,
8788 v8::External::Wrap(&interceptor_call_count));
8789 LocalContext context;
8790 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8791 GenerateSomeGarbage();
8792 context->Global()->Set(v8_str("o"), fun->NewInstance());
8793 v8::TryCatch try_catch;
8794 v8::Handle<Value> value = CompileRun(
8795 "o.foo = 17;"
8796 "var receiver = {};"
8797 "receiver.__proto__ = o;"
8798 "var result = 0;"
8799 "var saved_result = 0;"
8800 "for (var i = 0; i < 100; i++) {"
8801 " result = receiver.method(41);"
8802 " if (i == 50) {"
8803 " saved_result = result;"
8804 " receiver = 333;"
8805 " }"
8806 "}");
8807 CHECK(try_catch.HasCaught());
8808 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
8809 try_catch.Exception()->ToString());
8810 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8811 CHECK_GE(interceptor_call_count, 50);
8812}
8813
ager@chromium.org5c838252010-02-19 08:53:10 +00008814THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
8815 int interceptor_call_count = 0;
8816 v8::HandleScope scope;
8817 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8818 v8::Handle<v8::FunctionTemplate> method_templ =
8819 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8820 v8_str("method_data"),
8821 v8::Signature::New(fun_templ));
8822 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8823 proto_templ->Set(v8_str("method"), method_templ);
8824 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8825 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8826 NULL, NULL, NULL, NULL,
8827 v8::External::Wrap(&interceptor_call_count));
8828 LocalContext context;
8829 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8830 GenerateSomeGarbage();
8831 context->Global()->Set(v8_str("o"), fun->NewInstance());
8832 v8::TryCatch try_catch;
8833 v8::Handle<Value> value = CompileRun(
8834 "o.foo = 17;"
8835 "var receiver = {};"
8836 "receiver.__proto__ = o;"
8837 "var result = 0;"
8838 "var saved_result = 0;"
8839 "for (var i = 0; i < 100; i++) {"
8840 " result = receiver.method(41);"
8841 " if (i == 50) {"
8842 " saved_result = result;"
8843 " receiver = {method: receiver.method};"
8844 " }"
8845 "}");
8846 CHECK(try_catch.HasCaught());
8847 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
8848 try_catch.Exception()->ToString());
8849 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8850 CHECK_GE(interceptor_call_count, 50);
8851}
8852
8853THREADED_TEST(CallICFastApi_TrivialSignature) {
8854 v8::HandleScope scope;
8855 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8856 v8::Handle<v8::FunctionTemplate> method_templ =
8857 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
8858 v8_str("method_data"),
8859 v8::Handle<v8::Signature>());
8860 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8861 proto_templ->Set(v8_str("method"), method_templ);
8862 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8863 LocalContext context;
8864 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8865 GenerateSomeGarbage();
8866 context->Global()->Set(v8_str("o"), fun->NewInstance());
8867 v8::Handle<Value> value = CompileRun(
8868 "var result = 0;"
8869 "for (var i = 0; i < 100; i++) {"
8870 " result = o.method(41);"
8871 "}");
8872
8873 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
8874}
8875
8876THREADED_TEST(CallICFastApi_SimpleSignature) {
8877 v8::HandleScope scope;
8878 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8879 v8::Handle<v8::FunctionTemplate> method_templ =
8880 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8881 v8_str("method_data"),
8882 v8::Signature::New(fun_templ));
8883 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8884 proto_templ->Set(v8_str("method"), method_templ);
8885 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8886 LocalContext context;
8887 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8888 GenerateSomeGarbage();
8889 context->Global()->Set(v8_str("o"), fun->NewInstance());
8890 v8::Handle<Value> value = CompileRun(
8891 "o.foo = 17;"
8892 "var receiver = {};"
8893 "receiver.__proto__ = o;"
8894 "var result = 0;"
8895 "for (var i = 0; i < 100; i++) {"
8896 " result = receiver.method(41);"
8897 "}");
8898
8899 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
8900}
8901
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00008902THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) {
ager@chromium.org5c838252010-02-19 08:53:10 +00008903 v8::HandleScope scope;
8904 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8905 v8::Handle<v8::FunctionTemplate> method_templ =
8906 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8907 v8_str("method_data"),
8908 v8::Signature::New(fun_templ));
8909 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8910 proto_templ->Set(v8_str("method"), method_templ);
8911 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8912 LocalContext context;
8913 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8914 GenerateSomeGarbage();
8915 context->Global()->Set(v8_str("o"), fun->NewInstance());
8916 v8::Handle<Value> value = CompileRun(
8917 "o.foo = 17;"
8918 "var receiver = {};"
8919 "receiver.__proto__ = o;"
8920 "var result = 0;"
8921 "var saved_result = 0;"
8922 "for (var i = 0; i < 100; i++) {"
8923 " result = receiver.method(41);"
8924 " if (i == 50) {"
8925 " saved_result = result;"
8926 " receiver = {method: function(x) { return x - 1 }};"
8927 " }"
8928 "}");
8929 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
8930 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8931}
8932
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00008933THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) {
8934 v8::HandleScope scope;
8935 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8936 v8::Handle<v8::FunctionTemplate> method_templ =
8937 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8938 v8_str("method_data"),
8939 v8::Signature::New(fun_templ));
8940 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8941 proto_templ->Set(v8_str("method"), method_templ);
8942 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8943 LocalContext context;
8944 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8945 GenerateSomeGarbage();
8946 context->Global()->Set(v8_str("o"), fun->NewInstance());
8947 v8::TryCatch try_catch;
8948 v8::Handle<Value> value = CompileRun(
8949 "o.foo = 17;"
8950 "var receiver = {};"
8951 "receiver.__proto__ = o;"
8952 "var result = 0;"
8953 "var saved_result = 0;"
8954 "for (var i = 0; i < 100; i++) {"
8955 " result = receiver.method(41);"
8956 " if (i == 50) {"
8957 " saved_result = result;"
8958 " receiver = 333;"
8959 " }"
8960 "}");
8961 CHECK(try_catch.HasCaught());
8962 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
8963 try_catch.Exception()->ToString());
8964 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8965}
8966
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008967
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008968v8::Handle<Value> keyed_call_ic_function;
8969
8970static v8::Handle<Value> InterceptorKeyedCallICGetter(
8971 Local<String> name, const AccessorInfo& info) {
8972 ApiTestFuzzer::Fuzz();
8973 if (v8_str("x")->Equals(name)) {
8974 return keyed_call_ic_function;
8975 }
8976 return v8::Handle<Value>();
8977}
8978
8979
8980// Test the case when we stored cacheable lookup into
8981// a stub, but the function name changed (to another cacheable function).
8982THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
8983 v8::HandleScope scope;
8984 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8985 templ->SetNamedPropertyHandler(NoBlockGetterX);
8986 LocalContext context;
8987 context->Global()->Set(v8_str("o"), templ->NewInstance());
8988 v8::Handle<Value> value = CompileRun(
8989 "proto = new Object();"
8990 "proto.y = function(x) { return x + 1; };"
8991 "proto.z = function(x) { return x - 1; };"
8992 "o.__proto__ = proto;"
8993 "var result = 0;"
8994 "var method = 'y';"
8995 "for (var i = 0; i < 10; i++) {"
8996 " if (i == 5) { method = 'z'; };"
8997 " result += o[method](41);"
8998 "}");
8999 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9000}
9001
9002
9003// Test the case when we stored cacheable lookup into
9004// a stub, but the function name changed (and the new function is present
9005// both before and after the interceptor in the prototype chain).
9006THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
9007 v8::HandleScope scope;
9008 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9009 templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
9010 LocalContext context;
9011 context->Global()->Set(v8_str("proto1"), templ->NewInstance());
9012 keyed_call_ic_function =
9013 v8_compile("function f(x) { return x - 1; }; f")->Run();
9014 v8::Handle<Value> value = CompileRun(
9015 "o = new Object();"
9016 "proto2 = new Object();"
9017 "o.y = function(x) { return x + 1; };"
9018 "proto2.y = function(x) { return x + 2; };"
9019 "o.__proto__ = proto1;"
9020 "proto1.__proto__ = proto2;"
9021 "var result = 0;"
9022 "var method = 'x';"
9023 "for (var i = 0; i < 10; i++) {"
9024 " if (i == 5) { method = 'y'; };"
9025 " result += o[method](41);"
9026 "}");
9027 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9028}
9029
9030
9031// Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
9032// on the global object.
9033THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
9034 v8::HandleScope scope;
9035 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9036 templ->SetNamedPropertyHandler(NoBlockGetterX);
9037 LocalContext context;
9038 context->Global()->Set(v8_str("o"), templ->NewInstance());
9039 v8::Handle<Value> value = CompileRun(
9040 "function inc(x) { return x + 1; };"
9041 "inc(1);"
9042 "function dec(x) { return x - 1; };"
9043 "dec(1);"
9044 "o.__proto__ = this;"
9045 "this.__proto__.x = inc;"
9046 "this.__proto__.y = dec;"
9047 "var result = 0;"
9048 "var method = 'x';"
9049 "for (var i = 0; i < 10; i++) {"
9050 " if (i == 5) { method = 'y'; };"
9051 " result += o[method](41);"
9052 "}");
9053 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9054}
9055
9056
9057// Test the case when actual function to call sits on global object.
9058THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
9059 v8::HandleScope scope;
9060 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9061 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9062 LocalContext context;
9063 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9064
9065 v8::Handle<Value> value = CompileRun(
9066 "function len(x) { return x.length; };"
9067 "o.__proto__ = this;"
9068 "var m = 'parseFloat';"
9069 "var result = 0;"
9070 "for (var i = 0; i < 10; i++) {"
9071 " if (i == 5) {"
9072 " m = 'len';"
9073 " saved_result = result;"
9074 " };"
9075 " result = o[m]('239');"
9076 "}");
9077 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
9078 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9079}
9080
9081// Test the map transition before the interceptor.
9082THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
9083 v8::HandleScope scope;
9084 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9085 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9086 LocalContext context;
9087 context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
9088
9089 v8::Handle<Value> value = CompileRun(
9090 "var o = new Object();"
9091 "o.__proto__ = proto;"
9092 "o.method = function(x) { return x + 1; };"
9093 "var m = 'method';"
9094 "var result = 0;"
9095 "for (var i = 0; i < 10; i++) {"
9096 " if (i == 5) { o.method = function(x) { return x - 1; }; };"
9097 " result += o[m](41);"
9098 "}");
9099 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9100}
9101
9102
9103// Test the map transition after the interceptor.
9104THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
9105 v8::HandleScope scope;
9106 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9107 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9108 LocalContext context;
9109 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9110
9111 v8::Handle<Value> value = CompileRun(
9112 "var proto = new Object();"
9113 "o.__proto__ = proto;"
9114 "proto.method = function(x) { return x + 1; };"
9115 "var m = 'method';"
9116 "var result = 0;"
9117 "for (var i = 0; i < 10; i++) {"
9118 " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
9119 " result += o[m](41);"
9120 "}");
9121 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9122}
9123
9124
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009125static int interceptor_call_count = 0;
9126
9127static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
9128 const AccessorInfo& info) {
9129 ApiTestFuzzer::Fuzz();
9130 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
9131 return call_ic_function2;
9132 }
9133 return v8::Handle<Value>();
9134}
9135
9136
9137// This test should hit load and call ICs for the interceptor case.
9138// Once in a while, the interceptor will reply that a property was not
9139// found in which case we should get a reference error.
9140THREADED_TEST(InterceptorICReferenceErrors) {
9141 v8::HandleScope scope;
9142 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9143 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
9144 LocalContext context(0, templ, v8::Handle<Value>());
9145 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
9146 v8::Handle<Value> value = CompileRun(
9147 "function f() {"
9148 " for (var i = 0; i < 1000; i++) {"
9149 " try { x; } catch(e) { return true; }"
9150 " }"
9151 " return false;"
9152 "};"
9153 "f();");
9154 CHECK_EQ(true, value->BooleanValue());
9155 interceptor_call_count = 0;
9156 value = CompileRun(
9157 "function g() {"
9158 " for (var i = 0; i < 1000; i++) {"
9159 " try { x(42); } catch(e) { return true; }"
9160 " }"
9161 " return false;"
9162 "};"
9163 "g();");
9164 CHECK_EQ(true, value->BooleanValue());
9165}
9166
9167
9168static int interceptor_ic_exception_get_count = 0;
9169
9170static v8::Handle<Value> InterceptorICExceptionGetter(
9171 Local<String> name,
9172 const AccessorInfo& info) {
9173 ApiTestFuzzer::Fuzz();
9174 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
9175 return call_ic_function3;
9176 }
9177 if (interceptor_ic_exception_get_count == 20) {
9178 return v8::ThrowException(v8_num(42));
9179 }
9180 // Do not handle get for properties other than x.
9181 return v8::Handle<Value>();
9182}
9183
9184// Test interceptor load/call IC where the interceptor throws an
9185// exception once in a while.
9186THREADED_TEST(InterceptorICGetterExceptions) {
9187 interceptor_ic_exception_get_count = 0;
9188 v8::HandleScope scope;
9189 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9190 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
9191 LocalContext context(0, templ, v8::Handle<Value>());
9192 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
9193 v8::Handle<Value> value = CompileRun(
9194 "function f() {"
9195 " for (var i = 0; i < 100; i++) {"
9196 " try { x; } catch(e) { return true; }"
9197 " }"
9198 " return false;"
9199 "};"
9200 "f();");
9201 CHECK_EQ(true, value->BooleanValue());
9202 interceptor_ic_exception_get_count = 0;
9203 value = CompileRun(
9204 "function f() {"
9205 " for (var i = 0; i < 100; i++) {"
9206 " try { x(42); } catch(e) { return true; }"
9207 " }"
9208 " return false;"
9209 "};"
9210 "f();");
9211 CHECK_EQ(true, value->BooleanValue());
9212}
9213
9214
9215static int interceptor_ic_exception_set_count = 0;
9216
9217static v8::Handle<Value> InterceptorICExceptionSetter(
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009218 Local<String> key, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009219 ApiTestFuzzer::Fuzz();
9220 if (++interceptor_ic_exception_set_count > 20) {
9221 return v8::ThrowException(v8_num(42));
9222 }
9223 // Do not actually handle setting.
9224 return v8::Handle<Value>();
9225}
9226
9227// Test interceptor store IC where the interceptor throws an exception
9228// once in a while.
9229THREADED_TEST(InterceptorICSetterExceptions) {
9230 interceptor_ic_exception_set_count = 0;
9231 v8::HandleScope scope;
9232 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9233 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
9234 LocalContext context(0, templ, v8::Handle<Value>());
9235 v8::Handle<Value> value = CompileRun(
9236 "function f() {"
9237 " for (var i = 0; i < 100; i++) {"
9238 " try { x = 42; } catch(e) { return true; }"
9239 " }"
9240 " return false;"
9241 "};"
9242 "f();");
9243 CHECK_EQ(true, value->BooleanValue());
9244}
9245
9246
9247// Test that we ignore null interceptors.
9248THREADED_TEST(NullNamedInterceptor) {
9249 v8::HandleScope scope;
9250 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9251 templ->SetNamedPropertyHandler(0);
9252 LocalContext context;
9253 templ->Set("x", v8_num(42));
9254 v8::Handle<v8::Object> obj = templ->NewInstance();
9255 context->Global()->Set(v8_str("obj"), obj);
9256 v8::Handle<Value> value = CompileRun("obj.x");
9257 CHECK(value->IsInt32());
9258 CHECK_EQ(42, value->Int32Value());
9259}
9260
9261
9262// Test that we ignore null interceptors.
9263THREADED_TEST(NullIndexedInterceptor) {
9264 v8::HandleScope scope;
9265 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9266 templ->SetIndexedPropertyHandler(0);
9267 LocalContext context;
9268 templ->Set("42", v8_num(42));
9269 v8::Handle<v8::Object> obj = templ->NewInstance();
9270 context->Global()->Set(v8_str("obj"), obj);
9271 v8::Handle<Value> value = CompileRun("obj[42]");
9272 CHECK(value->IsInt32());
9273 CHECK_EQ(42, value->Int32Value());
9274}
9275
9276
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009277THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
9278 v8::HandleScope scope;
9279 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9280 templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9281 LocalContext env;
9282 env->Global()->Set(v8_str("obj"),
9283 templ->GetFunction()->NewInstance());
9284 ExpectTrue("obj.x === 42");
9285 ExpectTrue("!obj.propertyIsEnumerable('x')");
9286}
9287
9288
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009289static Handle<Value> ThrowingGetter(Local<String> name,
9290 const AccessorInfo& info) {
9291 ApiTestFuzzer::Fuzz();
9292 ThrowException(Handle<Value>());
9293 return Undefined();
9294}
9295
9296
9297THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
9298 HandleScope scope;
9299 LocalContext context;
9300
9301 Local<FunctionTemplate> templ = FunctionTemplate::New();
9302 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
9303 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
9304
9305 Local<Object> instance = templ->GetFunction()->NewInstance();
9306
9307 Local<Object> another = Object::New();
9308 another->SetPrototype(instance);
9309
9310 Local<Object> with_js_getter = CompileRun(
9311 "o = {};\n"
9312 "o.__defineGetter__('f', function() { throw undefined; });\n"
9313 "o\n").As<Object>();
9314 CHECK(!with_js_getter.IsEmpty());
9315
9316 TryCatch try_catch;
9317
9318 Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
9319 CHECK(try_catch.HasCaught());
9320 try_catch.Reset();
9321 CHECK(result.IsEmpty());
9322
9323 result = another->GetRealNamedProperty(v8_str("f"));
9324 CHECK(try_catch.HasCaught());
9325 try_catch.Reset();
9326 CHECK(result.IsEmpty());
9327
9328 result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
9329 CHECK(try_catch.HasCaught());
9330 try_catch.Reset();
9331 CHECK(result.IsEmpty());
9332
9333 result = another->Get(v8_str("f"));
9334 CHECK(try_catch.HasCaught());
9335 try_catch.Reset();
9336 CHECK(result.IsEmpty());
9337
9338 result = with_js_getter->GetRealNamedProperty(v8_str("f"));
9339 CHECK(try_catch.HasCaught());
9340 try_catch.Reset();
9341 CHECK(result.IsEmpty());
9342
9343 result = with_js_getter->Get(v8_str("f"));
9344 CHECK(try_catch.HasCaught());
9345 try_catch.Reset();
9346 CHECK(result.IsEmpty());
9347}
9348
9349
9350static Handle<Value> ThrowingCallbackWithTryCatch(const Arguments& args) {
9351 TryCatch try_catch;
9352 // Verboseness is important: it triggers message delivery which can call into
9353 // external code.
9354 try_catch.SetVerbose(true);
9355 CompileRun("throw 'from JS';");
9356 CHECK(try_catch.HasCaught());
9357 CHECK(!i::Isolate::Current()->has_pending_exception());
9358 CHECK(!i::Isolate::Current()->has_scheduled_exception());
9359 return Undefined();
9360}
9361
9362
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009363static int call_depth;
9364
9365
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009366static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
9367 TryCatch try_catch;
9368}
9369
9370
9371static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009372 if (--call_depth) CompileRun("throw 'ThrowInJS';");
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009373}
9374
9375
9376static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009377 if (--call_depth) ThrowException(v8_str("ThrowViaApi"));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009378}
9379
9380
9381static void WebKitLike(Handle<Message> message, Handle<Value> data) {
9382 Handle<String> errorMessageString = message->Get();
9383 CHECK(!errorMessageString.IsEmpty());
9384 message->GetStackTrace();
9385 message->GetScriptResourceName();
9386}
9387
9388THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
9389 HandleScope scope;
9390 LocalContext context;
9391
9392 Local<Function> func =
9393 FunctionTemplate::New(ThrowingCallbackWithTryCatch)->GetFunction();
9394 context->Global()->Set(v8_str("func"), func);
9395
9396 MessageCallback callbacks[] =
9397 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
9398 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
9399 MessageCallback callback = callbacks[i];
9400 if (callback != NULL) {
9401 V8::AddMessageListener(callback);
9402 }
ricow@chromium.orgdcebac02011-04-20 09:44:50 +00009403 // Some small number to control number of times message handler should
9404 // throw an exception.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009405 call_depth = 5;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009406 ExpectFalse(
9407 "var thrown = false;\n"
9408 "try { func(); } catch(e) { thrown = true; }\n"
9409 "thrown\n");
9410 if (callback != NULL) {
9411 V8::RemoveMessageListeners(callback);
9412 }
9413 }
9414}
9415
9416
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009417static v8::Handle<Value> ParentGetter(Local<String> name,
9418 const AccessorInfo& info) {
9419 ApiTestFuzzer::Fuzz();
9420 return v8_num(1);
9421}
9422
9423
9424static v8::Handle<Value> ChildGetter(Local<String> name,
9425 const AccessorInfo& info) {
9426 ApiTestFuzzer::Fuzz();
9427 return v8_num(42);
9428}
9429
9430
9431THREADED_TEST(Overriding) {
9432 v8::HandleScope scope;
9433 LocalContext context;
9434
9435 // Parent template.
9436 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
9437 Local<ObjectTemplate> parent_instance_templ =
9438 parent_templ->InstanceTemplate();
9439 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
9440
9441 // Template that inherits from the parent template.
9442 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
9443 Local<ObjectTemplate> child_instance_templ =
9444 child_templ->InstanceTemplate();
9445 child_templ->Inherit(parent_templ);
9446 // Override 'f'. The child version of 'f' should get called for child
9447 // instances.
9448 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
9449 // Add 'g' twice. The 'g' added last should get called for instances.
9450 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
9451 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
9452
9453 // Add 'h' as an accessor to the proto template with ReadOnly attributes
9454 // so 'h' can be shadowed on the instance object.
9455 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
9456 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
9457 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
9458
9459 // Add 'i' as an accessor to the instance template with ReadOnly attributes
9460 // but the attribute does not have effect because it is duplicated with
9461 // NULL setter.
9462 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
9463 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
9464
9465
9466
9467 // Instantiate the child template.
9468 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
9469
9470 // Check that the child function overrides the parent one.
9471 context->Global()->Set(v8_str("o"), instance);
9472 Local<Value> value = v8_compile("o.f")->Run();
9473 // Check that the 'g' that was added last is hit.
9474 CHECK_EQ(42, value->Int32Value());
9475 value = v8_compile("o.g")->Run();
9476 CHECK_EQ(42, value->Int32Value());
9477
9478 // Check 'h' can be shadowed.
9479 value = v8_compile("o.h = 3; o.h")->Run();
9480 CHECK_EQ(3, value->Int32Value());
9481
9482 // Check 'i' is cannot be shadowed or changed.
9483 value = v8_compile("o.i = 3; o.i")->Run();
9484 CHECK_EQ(42, value->Int32Value());
9485}
9486
9487
9488static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
9489 ApiTestFuzzer::Fuzz();
9490 if (args.IsConstructCall()) {
9491 return v8::Boolean::New(true);
9492 }
9493 return v8::Boolean::New(false);
9494}
9495
9496
9497THREADED_TEST(IsConstructCall) {
9498 v8::HandleScope scope;
9499
9500 // Function template with call handler.
9501 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9502 templ->SetCallHandler(IsConstructHandler);
9503
9504 LocalContext context;
9505
9506 context->Global()->Set(v8_str("f"), templ->GetFunction());
9507 Local<Value> value = v8_compile("f()")->Run();
9508 CHECK(!value->BooleanValue());
9509 value = v8_compile("new f()")->Run();
9510 CHECK(value->BooleanValue());
9511}
9512
9513
9514THREADED_TEST(ObjectProtoToString) {
9515 v8::HandleScope scope;
9516 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9517 templ->SetClassName(v8_str("MyClass"));
9518
9519 LocalContext context;
9520
9521 Local<String> customized_tostring = v8_str("customized toString");
9522
9523 // Replace Object.prototype.toString
9524 v8_compile("Object.prototype.toString = function() {"
9525 " return 'customized toString';"
9526 "}")->Run();
9527
9528 // Normal ToString call should call replaced Object.prototype.toString
9529 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
9530 Local<String> value = instance->ToString();
9531 CHECK(value->IsString() && value->Equals(customized_tostring));
9532
9533 // ObjectProtoToString should not call replace toString function.
9534 value = instance->ObjectProtoToString();
9535 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
9536
9537 // Check global
9538 value = context->Global()->ObjectProtoToString();
9539 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
9540
9541 // Check ordinary object
9542 Local<Value> object = v8_compile("new Object()")->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009543 value = object.As<v8::Object>()->ObjectProtoToString();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009544 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
9545}
9546
9547
ager@chromium.orgbeb25712010-11-29 08:02:25 +00009548THREADED_TEST(ObjectGetConstructorName) {
9549 v8::HandleScope scope;
9550 LocalContext context;
9551 v8_compile("function Parent() {};"
9552 "function Child() {};"
9553 "Child.prototype = new Parent();"
9554 "var outer = { inner: function() { } };"
9555 "var p = new Parent();"
9556 "var c = new Child();"
9557 "var x = new outer.inner();")->Run();
9558
9559 Local<v8::Value> p = context->Global()->Get(v8_str("p"));
9560 CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
9561 v8_str("Parent")));
9562
9563 Local<v8::Value> c = context->Global()->Get(v8_str("c"));
9564 CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
9565 v8_str("Child")));
9566
9567 Local<v8::Value> x = context->Global()->Get(v8_str("x"));
9568 CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
9569 v8_str("outer.inner")));
9570}
9571
9572
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009573bool ApiTestFuzzer::fuzzing_ = false;
lrn@chromium.org32d961d2010-06-30 09:09:34 +00009574i::Semaphore* ApiTestFuzzer::all_tests_done_=
9575 i::OS::CreateSemaphore(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009576int ApiTestFuzzer::active_tests_;
9577int ApiTestFuzzer::tests_being_run_;
9578int ApiTestFuzzer::current_;
9579
9580
9581// We are in a callback and want to switch to another thread (if we
9582// are currently running the thread fuzzing test).
9583void ApiTestFuzzer::Fuzz() {
9584 if (!fuzzing_) return;
9585 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
9586 test->ContextSwitch();
9587}
9588
9589
9590// Let the next thread go. Since it is also waiting on the V8 lock it may
9591// not start immediately.
9592bool ApiTestFuzzer::NextThread() {
9593 int test_position = GetNextTestNumber();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009594 const char* test_name = RegisterThreadedTest::nth(current_)->name();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009595 if (test_position == current_) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009596 if (kLogThreading)
9597 printf("Stay with %s\n", test_name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009598 return false;
9599 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009600 if (kLogThreading) {
9601 printf("Switch from %s to %s\n",
9602 test_name,
9603 RegisterThreadedTest::nth(test_position)->name());
9604 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009605 current_ = test_position;
9606 RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
9607 return true;
9608}
9609
9610
9611void ApiTestFuzzer::Run() {
9612 // When it is our turn...
9613 gate_->Wait();
9614 {
9615 // ... get the V8 lock and start running the test.
9616 v8::Locker locker;
9617 CallTest();
9618 }
9619 // This test finished.
9620 active_ = false;
9621 active_tests_--;
9622 // If it was the last then signal that fact.
9623 if (active_tests_ == 0) {
9624 all_tests_done_->Signal();
9625 } else {
9626 // Otherwise select a new test and start that.
9627 NextThread();
9628 }
9629}
9630
9631
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009632static unsigned linear_congruential_generator;
9633
9634
9635void ApiTestFuzzer::Setup(PartOfTest part) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00009636 linear_congruential_generator = i::FLAG_testing_prng_seed;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009637 fuzzing_ = true;
lrn@chromium.org1c092762011-05-09 09:42:16 +00009638 int count = RegisterThreadedTest::count();
9639 int start = count * part / (LAST_PART + 1);
9640 int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
9641 active_tests_ = tests_being_run_ = end - start + 1;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009642 for (int i = 0; i < tests_being_run_; i++) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009643 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009644 }
9645 for (int i = 0; i < active_tests_; i++) {
9646 RegisterThreadedTest::nth(i)->fuzzer_->Start();
9647 }
9648}
9649
9650
9651static void CallTestNumber(int test_number) {
9652 (RegisterThreadedTest::nth(test_number)->callback())();
9653}
9654
9655
9656void ApiTestFuzzer::RunAllTests() {
9657 // Set off the first test.
9658 current_ = -1;
9659 NextThread();
9660 // Wait till they are all done.
9661 all_tests_done_->Wait();
9662}
9663
9664
9665int ApiTestFuzzer::GetNextTestNumber() {
9666 int next_test;
9667 do {
9668 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
9669 linear_congruential_generator *= 1664525u;
9670 linear_congruential_generator += 1013904223u;
9671 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
9672 return next_test;
9673}
9674
9675
9676void ApiTestFuzzer::ContextSwitch() {
9677 // If the new thread is the same as the current thread there is nothing to do.
9678 if (NextThread()) {
9679 // Now it can start.
9680 v8::Unlocker unlocker;
9681 // Wait till someone starts us again.
9682 gate_->Wait();
9683 // And we're off.
9684 }
9685}
9686
9687
9688void ApiTestFuzzer::TearDown() {
9689 fuzzing_ = false;
ager@chromium.org41826e72009-03-30 13:30:57 +00009690 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
9691 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
9692 if (fuzzer != NULL) fuzzer->Join();
9693 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009694}
9695
9696
9697// Lets not be needlessly self-referential.
9698TEST(Threading) {
9699 ApiTestFuzzer::Setup(ApiTestFuzzer::FIRST_PART);
9700 ApiTestFuzzer::RunAllTests();
9701 ApiTestFuzzer::TearDown();
9702}
9703
9704TEST(Threading2) {
9705 ApiTestFuzzer::Setup(ApiTestFuzzer::SECOND_PART);
9706 ApiTestFuzzer::RunAllTests();
9707 ApiTestFuzzer::TearDown();
9708}
9709
lrn@chromium.org1c092762011-05-09 09:42:16 +00009710TEST(Threading3) {
9711 ApiTestFuzzer::Setup(ApiTestFuzzer::THIRD_PART);
9712 ApiTestFuzzer::RunAllTests();
9713 ApiTestFuzzer::TearDown();
9714}
9715
9716TEST(Threading4) {
9717 ApiTestFuzzer::Setup(ApiTestFuzzer::FOURTH_PART);
9718 ApiTestFuzzer::RunAllTests();
9719 ApiTestFuzzer::TearDown();
9720}
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009721
9722void ApiTestFuzzer::CallTest() {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009723 if (kLogThreading)
9724 printf("Start test %d\n", test_number_);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009725 CallTestNumber(test_number_);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009726 if (kLogThreading)
9727 printf("End test %d\n", test_number_);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009728}
9729
9730
9731static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009732 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009733 ApiTestFuzzer::Fuzz();
9734 v8::Unlocker unlocker;
9735 const char* code = "throw 7;";
9736 {
9737 v8::Locker nested_locker;
9738 v8::HandleScope scope;
9739 v8::Handle<Value> exception;
9740 { v8::TryCatch try_catch;
9741 v8::Handle<Value> value = CompileRun(code);
9742 CHECK(value.IsEmpty());
9743 CHECK(try_catch.HasCaught());
9744 // Make sure to wrap the exception in a new handle because
9745 // the handle returned from the TryCatch is destroyed
9746 // when the TryCatch is destroyed.
9747 exception = Local<Value>::New(try_catch.Exception());
9748 }
9749 return v8::ThrowException(exception);
9750 }
9751}
9752
9753
9754static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009755 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009756 ApiTestFuzzer::Fuzz();
9757 v8::Unlocker unlocker;
9758 const char* code = "throw 7;";
9759 {
9760 v8::Locker nested_locker;
9761 v8::HandleScope scope;
9762 v8::Handle<Value> value = CompileRun(code);
9763 CHECK(value.IsEmpty());
9764 return v8_str("foo");
9765 }
9766}
9767
9768
9769// These are locking tests that don't need to be run again
9770// as part of the locking aggregation tests.
9771TEST(NestedLockers) {
9772 v8::Locker locker;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009773 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009774 v8::HandleScope scope;
9775 LocalContext env;
9776 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
9777 Local<Function> fun = fun_templ->GetFunction();
9778 env->Global()->Set(v8_str("throw_in_js"), fun);
9779 Local<Script> script = v8_compile("(function () {"
9780 " try {"
9781 " throw_in_js();"
9782 " return 42;"
9783 " } catch (e) {"
9784 " return e * 13;"
9785 " }"
9786 "})();");
9787 CHECK_EQ(91, script->Run()->Int32Value());
9788}
9789
9790
9791// These are locking tests that don't need to be run again
9792// as part of the locking aggregation tests.
9793TEST(NestedLockersNoTryCatch) {
9794 v8::Locker locker;
9795 v8::HandleScope scope;
9796 LocalContext env;
9797 Local<v8::FunctionTemplate> fun_templ =
9798 v8::FunctionTemplate::New(ThrowInJSNoCatch);
9799 Local<Function> fun = fun_templ->GetFunction();
9800 env->Global()->Set(v8_str("throw_in_js"), fun);
9801 Local<Script> script = v8_compile("(function () {"
9802 " try {"
9803 " throw_in_js();"
9804 " return 42;"
9805 " } catch (e) {"
9806 " return e * 13;"
9807 " }"
9808 "})();");
9809 CHECK_EQ(91, script->Run()->Int32Value());
9810}
9811
9812
9813THREADED_TEST(RecursiveLocking) {
9814 v8::Locker locker;
9815 {
9816 v8::Locker locker2;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009817 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009818 }
9819}
9820
9821
9822static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
9823 ApiTestFuzzer::Fuzz();
9824 v8::Unlocker unlocker;
9825 return v8::Undefined();
9826}
9827
9828
9829THREADED_TEST(LockUnlockLock) {
9830 {
9831 v8::Locker locker;
9832 v8::HandleScope scope;
9833 LocalContext env;
9834 Local<v8::FunctionTemplate> fun_templ =
9835 v8::FunctionTemplate::New(UnlockForAMoment);
9836 Local<Function> fun = fun_templ->GetFunction();
9837 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
9838 Local<Script> script = v8_compile("(function () {"
9839 " unlock_for_a_moment();"
9840 " return 42;"
9841 "})();");
9842 CHECK_EQ(42, script->Run()->Int32Value());
9843 }
9844 {
9845 v8::Locker locker;
9846 v8::HandleScope scope;
9847 LocalContext env;
9848 Local<v8::FunctionTemplate> fun_templ =
9849 v8::FunctionTemplate::New(UnlockForAMoment);
9850 Local<Function> fun = fun_templ->GetFunction();
9851 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
9852 Local<Script> script = v8_compile("(function () {"
9853 " unlock_for_a_moment();"
9854 " return 42;"
9855 "})();");
9856 CHECK_EQ(42, script->Run()->Int32Value());
9857 }
9858}
9859
9860
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009861static int GetGlobalObjectsCount() {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009862 int count = 0;
lrn@chromium.org32d961d2010-06-30 09:09:34 +00009863 i::HeapIterator it;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009864 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
9865 if (object->IsJSGlobalObject()) count++;
9866 return count;
9867}
9868
9869
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00009870static void CheckSurvivingGlobalObjectsCount(int expected) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00009871 // We need to collect all garbage twice to be sure that everything
9872 // has been collected. This is because inline caches are cleared in
9873 // the first garbage collection but some of the maps have already
9874 // been marked at that point. Therefore some of the maps are not
9875 // collected until the second garbage collection.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009876 HEAP->global_context_map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009877 HEAP->CollectAllGarbage(false);
9878 HEAP->CollectAllGarbage(false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009879 int count = GetGlobalObjectsCount();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009880#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009881 if (count != expected) HEAP->TracePathToGlobal();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009882#endif
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00009883 CHECK_EQ(expected, count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009884}
9885
9886
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009887TEST(DontLeakGlobalObjects) {
9888 // Regression test for issues 1139850 and 1174891.
9889
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00009890 v8::V8::Initialize();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009891
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009892 for (int i = 0; i < 5; i++) {
9893 { v8::HandleScope scope;
9894 LocalContext context;
9895 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00009896 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009897
9898 { v8::HandleScope scope;
9899 LocalContext context;
9900 v8_compile("Date")->Run();
9901 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00009902 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009903
9904 { v8::HandleScope scope;
9905 LocalContext context;
9906 v8_compile("/aaa/")->Run();
9907 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00009908 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009909
9910 { v8::HandleScope scope;
9911 const char* extension_list[] = { "v8/gc" };
9912 v8::ExtensionConfiguration extensions(1, extension_list);
9913 LocalContext context(&extensions);
9914 v8_compile("gc();")->Run();
9915 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00009916 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009917 }
9918}
9919
9920
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009921v8::Persistent<v8::Object> some_object;
9922v8::Persistent<v8::Object> bad_handle;
9923
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00009924void NewPersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) {
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009925 v8::HandleScope scope;
9926 bad_handle = v8::Persistent<v8::Object>::New(some_object);
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00009927 handle.Dispose();
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009928}
9929
9930
9931THREADED_TEST(NewPersistentHandleFromWeakCallback) {
9932 LocalContext context;
9933
9934 v8::Persistent<v8::Object> handle1, handle2;
9935 {
9936 v8::HandleScope scope;
9937 some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
9938 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
9939 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
9940 }
9941 // Note: order is implementation dependent alas: currently
9942 // global handle nodes are processed by PostGarbageCollectionProcessing
9943 // in reverse allocation order, so if second allocated handle is deleted,
9944 // weak callback of the first handle would be able to 'reallocate' it.
9945 handle1.MakeWeak(NULL, NewPersistentHandleCallback);
9946 handle2.Dispose();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009947 HEAP->CollectAllGarbage(false);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009948}
9949
9950
9951v8::Persistent<v8::Object> to_be_disposed;
9952
9953void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
9954 to_be_disposed.Dispose();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009955 HEAP->CollectAllGarbage(false);
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00009956 handle.Dispose();
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009957}
9958
9959
9960THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
9961 LocalContext context;
9962
9963 v8::Persistent<v8::Object> handle1, handle2;
9964 {
9965 v8::HandleScope scope;
9966 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
9967 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
9968 }
9969 handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
9970 to_be_disposed = handle2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009971 HEAP->CollectAllGarbage(false);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009972}
9973
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009974void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
9975 handle.Dispose();
9976}
9977
9978void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
9979 v8::HandleScope scope;
9980 v8::Persistent<v8::Object>::New(v8::Object::New());
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00009981 handle.Dispose();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009982}
9983
9984
9985THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
9986 LocalContext context;
9987
9988 v8::Persistent<v8::Object> handle1, handle2, handle3;
9989 {
9990 v8::HandleScope scope;
9991 handle3 = v8::Persistent<v8::Object>::New(v8::Object::New());
9992 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
9993 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
9994 }
9995 handle2.MakeWeak(NULL, DisposingCallback);
9996 handle3.MakeWeak(NULL, HandleCreatingCallback);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009997 HEAP->CollectAllGarbage(false);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009998}
9999
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000010000
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010001THREADED_TEST(CheckForCrossContextObjectLiterals) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000010002 v8::V8::Initialize();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010003
10004 const int nof = 2;
10005 const char* sources[nof] = {
10006 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
10007 "Object()"
10008 };
10009
10010 for (int i = 0; i < nof; i++) {
10011 const char* source = sources[i];
10012 { v8::HandleScope scope;
10013 LocalContext context;
10014 CompileRun(source);
10015 }
10016 { v8::HandleScope scope;
10017 LocalContext context;
10018 CompileRun(source);
10019 }
10020 }
10021}
10022
10023
10024static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
10025 v8::HandleScope inner;
10026 env->Enter();
10027 v8::Handle<Value> three = v8_num(3);
10028 v8::Handle<Value> value = inner.Close(three);
10029 env->Exit();
10030 return value;
10031}
10032
10033
10034THREADED_TEST(NestedHandleScopeAndContexts) {
10035 v8::HandleScope outer;
10036 v8::Persistent<Context> env = Context::New();
10037 env->Enter();
10038 v8::Handle<Value> value = NestedScope(env);
10039 v8::Handle<String> str = value->ToString();
10040 env->Exit();
10041 env.Dispose();
10042}
10043
10044
10045THREADED_TEST(ExternalAllocatedMemory) {
10046 v8::HandleScope outer;
kasperl@chromium.orge959c182009-07-27 08:59:04 +000010047 v8::Persistent<Context> env = Context::New();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010048 const int kSize = 1024*1024;
10049 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
10050 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
10051}
10052
10053
10054THREADED_TEST(DisposeEnteredContext) {
10055 v8::HandleScope scope;
10056 LocalContext outer;
10057 { v8::Persistent<v8::Context> inner = v8::Context::New();
10058 inner->Enter();
10059 inner.Dispose();
10060 inner.Clear();
10061 inner->Exit();
10062 }
10063}
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010064
10065
10066// Regression test for issue 54, object templates with internal fields
10067// but no accessors or interceptors did not get their internal field
10068// count set on instances.
10069THREADED_TEST(Regress54) {
10070 v8::HandleScope outer;
10071 LocalContext context;
10072 static v8::Persistent<v8::ObjectTemplate> templ;
10073 if (templ.IsEmpty()) {
10074 v8::HandleScope inner;
10075 v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
10076 local->SetInternalFieldCount(1);
10077 templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
10078 }
10079 v8::Handle<v8::Object> result = templ->NewInstance();
10080 CHECK_EQ(1, result->InternalFieldCount());
10081}
10082
10083
10084// If part of the threaded tests, this test makes ThreadingTest fail
10085// on mac.
10086TEST(CatchStackOverflow) {
10087 v8::HandleScope scope;
10088 LocalContext context;
10089 v8::TryCatch try_catch;
10090 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
10091 "function f() {"
10092 " return f();"
10093 "}"
10094 ""
10095 "f();"));
10096 v8::Handle<v8::Value> result = script->Run();
10097 CHECK(result.IsEmpty());
10098}
10099
10100
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000010101static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
10102 const char* resource_name,
10103 int line_offset) {
10104 v8::HandleScope scope;
10105 v8::TryCatch try_catch;
10106 v8::Handle<v8::Value> result = script->Run();
10107 CHECK(result.IsEmpty());
10108 CHECK(try_catch.HasCaught());
10109 v8::Handle<v8::Message> message = try_catch.Message();
10110 CHECK(!message.IsEmpty());
10111 CHECK_EQ(10 + line_offset, message->GetLineNumber());
10112 CHECK_EQ(91, message->GetStartPosition());
10113 CHECK_EQ(92, message->GetEndPosition());
10114 CHECK_EQ(2, message->GetStartColumn());
10115 CHECK_EQ(3, message->GetEndColumn());
10116 v8::String::AsciiValue line(message->GetSourceLine());
10117 CHECK_EQ(" throw 'nirk';", *line);
10118 v8::String::AsciiValue name(message->GetScriptResourceName());
10119 CHECK_EQ(resource_name, *name);
10120}
10121
10122
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010123THREADED_TEST(TryCatchSourceInfo) {
10124 v8::HandleScope scope;
10125 LocalContext context;
10126 v8::Handle<v8::String> source = v8::String::New(
10127 "function Foo() {\n"
10128 " return Bar();\n"
10129 "}\n"
10130 "\n"
10131 "function Bar() {\n"
10132 " return Baz();\n"
10133 "}\n"
10134 "\n"
10135 "function Baz() {\n"
10136 " throw 'nirk';\n"
10137 "}\n"
10138 "\n"
10139 "Foo();\n");
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000010140
10141 const char* resource_name;
10142 v8::Handle<v8::Script> script;
10143 resource_name = "test.js";
10144 script = v8::Script::Compile(source, v8::String::New(resource_name));
10145 CheckTryCatchSourceInfo(script, resource_name, 0);
10146
10147 resource_name = "test1.js";
10148 v8::ScriptOrigin origin1(v8::String::New(resource_name));
10149 script = v8::Script::Compile(source, &origin1);
10150 CheckTryCatchSourceInfo(script, resource_name, 0);
10151
10152 resource_name = "test2.js";
10153 v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
10154 script = v8::Script::Compile(source, &origin2);
10155 CheckTryCatchSourceInfo(script, resource_name, 7);
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010156}
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000010157
10158
10159THREADED_TEST(CompilationCache) {
10160 v8::HandleScope scope;
10161 LocalContext context;
10162 v8::Handle<v8::String> source0 = v8::String::New("1234");
10163 v8::Handle<v8::String> source1 = v8::String::New("1234");
10164 v8::Handle<v8::Script> script0 =
10165 v8::Script::Compile(source0, v8::String::New("test.js"));
10166 v8::Handle<v8::Script> script1 =
10167 v8::Script::Compile(source1, v8::String::New("test.js"));
10168 v8::Handle<v8::Script> script2 =
10169 v8::Script::Compile(source0); // different origin
10170 CHECK_EQ(1234, script0->Run()->Int32Value());
10171 CHECK_EQ(1234, script1->Run()->Int32Value());
10172 CHECK_EQ(1234, script2->Run()->Int32Value());
10173}
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000010174
10175
10176static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
10177 ApiTestFuzzer::Fuzz();
10178 return v8_num(42);
10179}
10180
10181
10182THREADED_TEST(CallbackFunctionName) {
10183 v8::HandleScope scope;
10184 LocalContext context;
10185 Local<ObjectTemplate> t = ObjectTemplate::New();
10186 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
10187 context->Global()->Set(v8_str("obj"), t->NewInstance());
10188 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
10189 CHECK(value->IsString());
10190 v8::String::AsciiValue name(value);
10191 CHECK_EQ("asdf", *name);
10192}
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010193
10194
10195THREADED_TEST(DateAccess) {
10196 v8::HandleScope scope;
10197 LocalContext context;
10198 v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
10199 CHECK(date->IsDate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010200 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010201}
10202
10203
10204void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010205 v8::Handle<v8::Object> obj = val.As<v8::Object>();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010206 v8::Handle<v8::Array> props = obj->GetPropertyNames();
10207 CHECK_EQ(elmc, props->Length());
10208 for (int i = 0; i < elmc; i++) {
10209 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
10210 CHECK_EQ(elmv[i], *elm);
10211 }
10212}
10213
10214
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010215void CheckOwnProperties(v8::Handle<v8::Value> val,
10216 int elmc,
10217 const char* elmv[]) {
10218 v8::Handle<v8::Object> obj = val.As<v8::Object>();
10219 v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
10220 CHECK_EQ(elmc, props->Length());
10221 for (int i = 0; i < elmc; i++) {
10222 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
10223 CHECK_EQ(elmv[i], *elm);
10224 }
10225}
10226
10227
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010228THREADED_TEST(PropertyEnumeration) {
10229 v8::HandleScope scope;
10230 LocalContext context;
10231 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
10232 "var result = [];"
10233 "result[0] = {};"
10234 "result[1] = {a: 1, b: 2};"
10235 "result[2] = [1, 2, 3];"
10236 "var proto = {x: 1, y: 2, z: 3};"
10237 "var x = { __proto__: proto, w: 0, z: 1 };"
10238 "result[3] = x;"
10239 "result;"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010240 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010241 CHECK_EQ(4, elms->Length());
10242 int elmc0 = 0;
10243 const char** elmv0 = NULL;
10244 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010245 CheckOwnProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010246 int elmc1 = 2;
10247 const char* elmv1[] = {"a", "b"};
10248 CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010249 CheckOwnProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010250 int elmc2 = 3;
10251 const char* elmv2[] = {"0", "1", "2"};
10252 CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010253 CheckOwnProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010254 int elmc3 = 4;
10255 const char* elmv3[] = {"w", "z", "x", "y"};
10256 CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010257 int elmc4 = 2;
10258 const char* elmv4[] = {"w", "z"};
10259 CheckOwnProperties(elms->Get(v8::Integer::New(3)), elmc4, elmv4);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010260}
ager@chromium.org870a0b62008-11-04 11:43:05 +000010261
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010262THREADED_TEST(PropertyEnumeration2) {
10263 v8::HandleScope scope;
10264 LocalContext context;
10265 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
10266 "var result = [];"
10267 "result[0] = {};"
10268 "result[1] = {a: 1, b: 2};"
10269 "result[2] = [1, 2, 3];"
10270 "var proto = {x: 1, y: 2, z: 3};"
10271 "var x = { __proto__: proto, w: 0, z: 1 };"
10272 "result[3] = x;"
10273 "result;"))->Run();
10274 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
10275 CHECK_EQ(4, elms->Length());
10276 int elmc0 = 0;
10277 const char** elmv0 = NULL;
10278 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
10279
10280 v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(0));
10281 v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
10282 CHECK_EQ(0, props->Length());
10283 for (uint32_t i = 0; i < props->Length(); i++) {
10284 printf("p[%d]\n", i);
10285 }
10286}
ager@chromium.org870a0b62008-11-04 11:43:05 +000010287
ager@chromium.org870a0b62008-11-04 11:43:05 +000010288static bool NamedSetAccessBlocker(Local<v8::Object> obj,
10289 Local<Value> name,
10290 v8::AccessType type,
10291 Local<Value> data) {
10292 return type != v8::ACCESS_SET;
10293}
10294
10295
10296static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
10297 uint32_t key,
10298 v8::AccessType type,
10299 Local<Value> data) {
10300 return type != v8::ACCESS_SET;
10301}
10302
10303
10304THREADED_TEST(DisableAccessChecksWhileConfiguring) {
10305 v8::HandleScope scope;
10306 LocalContext context;
10307 Local<ObjectTemplate> templ = ObjectTemplate::New();
10308 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
10309 IndexedSetAccessBlocker);
10310 templ->Set(v8_str("x"), v8::True());
10311 Local<v8::Object> instance = templ->NewInstance();
10312 context->Global()->Set(v8_str("obj"), instance);
10313 Local<Value> value = CompileRun("obj.x");
10314 CHECK(value->BooleanValue());
10315}
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010316
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010317
ager@chromium.org32912102009-01-16 10:38:43 +000010318static bool NamedGetAccessBlocker(Local<v8::Object> obj,
10319 Local<Value> name,
10320 v8::AccessType type,
10321 Local<Value> data) {
10322 return false;
10323}
10324
10325
10326static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
10327 uint32_t key,
10328 v8::AccessType type,
10329 Local<Value> data) {
10330 return false;
10331}
10332
10333
10334
10335THREADED_TEST(AccessChecksReenabledCorrectly) {
10336 v8::HandleScope scope;
10337 LocalContext context;
10338 Local<ObjectTemplate> templ = ObjectTemplate::New();
10339 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
10340 IndexedGetAccessBlocker);
10341 templ->Set(v8_str("a"), v8_str("a"));
10342 // Add more than 8 (see kMaxFastProperties) properties
10343 // so that the constructor will force copying map.
10344 // Cannot sprintf, gcc complains unsafety.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010345 char buf[4];
ager@chromium.org32912102009-01-16 10:38:43 +000010346 for (char i = '0'; i <= '9' ; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010347 buf[0] = i;
ager@chromium.org32912102009-01-16 10:38:43 +000010348 for (char j = '0'; j <= '9'; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010349 buf[1] = j;
ager@chromium.org32912102009-01-16 10:38:43 +000010350 for (char k = '0'; k <= '9'; k++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010351 buf[2] = k;
10352 buf[3] = 0;
ager@chromium.org32912102009-01-16 10:38:43 +000010353 templ->Set(v8_str(buf), v8::Number::New(k));
10354 }
10355 }
10356 }
10357
10358 Local<v8::Object> instance_1 = templ->NewInstance();
10359 context->Global()->Set(v8_str("obj_1"), instance_1);
10360
10361 Local<Value> value_1 = CompileRun("obj_1.a");
10362 CHECK(value_1->IsUndefined());
10363
10364 Local<v8::Object> instance_2 = templ->NewInstance();
10365 context->Global()->Set(v8_str("obj_2"), instance_2);
10366
10367 Local<Value> value_2 = CompileRun("obj_2.a");
10368 CHECK(value_2->IsUndefined());
10369}
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010370
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010371
ager@chromium.org8bb60582008-12-11 12:02:20 +000010372// This tests that access check information remains on the global
10373// object template when creating contexts.
10374THREADED_TEST(AccessControlRepeatedContextCreation) {
10375 v8::HandleScope handle_scope;
10376 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
10377 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
10378 IndexedSetAccessBlocker);
10379 i::Handle<i::ObjectTemplateInfo> internal_template =
10380 v8::Utils::OpenHandle(*global_template);
10381 CHECK(!internal_template->constructor()->IsUndefined());
10382 i::Handle<i::FunctionTemplateInfo> constructor(
10383 i::FunctionTemplateInfo::cast(internal_template->constructor()));
10384 CHECK(!constructor->access_check_info()->IsUndefined());
10385 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
10386 CHECK(!constructor->access_check_info()->IsUndefined());
10387}
10388
10389
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010390THREADED_TEST(TurnOnAccessCheck) {
10391 v8::HandleScope handle_scope;
10392
10393 // Create an environment with access check to the global object disabled by
10394 // default.
10395 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
10396 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
10397 IndexedGetAccessBlocker,
10398 v8::Handle<v8::Value>(),
10399 false);
10400 v8::Persistent<Context> context = Context::New(NULL, global_template);
10401 Context::Scope context_scope(context);
10402
10403 // Set up a property and a number of functions.
10404 context->Global()->Set(v8_str("a"), v8_num(1));
10405 CompileRun("function f1() {return a;}"
10406 "function f2() {return a;}"
10407 "function g1() {return h();}"
10408 "function g2() {return h();}"
10409 "function h() {return 1;}");
10410 Local<Function> f1 =
10411 Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
10412 Local<Function> f2 =
10413 Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
10414 Local<Function> g1 =
10415 Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
10416 Local<Function> g2 =
10417 Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
10418 Local<Function> h =
10419 Local<Function>::Cast(context->Global()->Get(v8_str("h")));
10420
10421 // Get the global object.
10422 v8::Handle<v8::Object> global = context->Global();
10423
10424 // Call f1 one time and f2 a number of times. This will ensure that f1 still
10425 // uses the runtime system to retreive property a whereas f2 uses global load
10426 // inline cache.
10427 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
10428 for (int i = 0; i < 4; i++) {
10429 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
10430 }
10431
10432 // Same for g1 and g2.
10433 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
10434 for (int i = 0; i < 4; i++) {
10435 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
10436 }
10437
10438 // Detach the global and turn on access check.
10439 context->DetachGlobal();
10440 context->Global()->TurnOnAccessCheck();
10441
10442 // Failing access check to property get results in undefined.
10443 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
10444 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
10445
10446 // Failing access check to function call results in exception.
10447 CHECK(g1->Call(global, 0, NULL).IsEmpty());
10448 CHECK(g2->Call(global, 0, NULL).IsEmpty());
10449
10450 // No failing access check when just returning a constant.
10451 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
10452}
10453
10454
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010455v8::Handle<v8::String> a;
10456v8::Handle<v8::String> h;
10457
10458static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
10459 Local<Value> name,
10460 v8::AccessType type,
10461 Local<Value> data) {
10462 return !(name->Equals(a) || name->Equals(h));
10463}
10464
10465
10466THREADED_TEST(TurnOnAccessCheckAndRecompile) {
10467 v8::HandleScope handle_scope;
10468
10469 // Create an environment with access check to the global object disabled by
10470 // default. When the registered access checker will block access to properties
10471 // a and h
10472 a = v8_str("a");
10473 h = v8_str("h");
10474 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
10475 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
10476 IndexedGetAccessBlocker,
10477 v8::Handle<v8::Value>(),
10478 false);
10479 v8::Persistent<Context> context = Context::New(NULL, global_template);
10480 Context::Scope context_scope(context);
10481
10482 // Set up a property and a number of functions.
10483 context->Global()->Set(v8_str("a"), v8_num(1));
10484 static const char* source = "function f1() {return a;}"
10485 "function f2() {return a;}"
10486 "function g1() {return h();}"
10487 "function g2() {return h();}"
10488 "function h() {return 1;}";
10489
10490 CompileRun(source);
10491 Local<Function> f1;
10492 Local<Function> f2;
10493 Local<Function> g1;
10494 Local<Function> g2;
10495 Local<Function> h;
10496 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
10497 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
10498 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
10499 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
10500 h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
10501
10502 // Get the global object.
10503 v8::Handle<v8::Object> global = context->Global();
10504
10505 // Call f1 one time and f2 a number of times. This will ensure that f1 still
10506 // uses the runtime system to retreive property a whereas f2 uses global load
10507 // inline cache.
10508 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
10509 for (int i = 0; i < 4; i++) {
10510 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
10511 }
10512
10513 // Same for g1 and g2.
10514 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
10515 for (int i = 0; i < 4; i++) {
10516 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
10517 }
10518
10519 // Detach the global and turn on access check now blocking access to property
10520 // a and function h.
10521 context->DetachGlobal();
10522 context->Global()->TurnOnAccessCheck();
10523
10524 // Failing access check to property get results in undefined.
10525 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
10526 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
10527
10528 // Failing access check to function call results in exception.
10529 CHECK(g1->Call(global, 0, NULL).IsEmpty());
10530 CHECK(g2->Call(global, 0, NULL).IsEmpty());
10531
10532 // No failing access check when just returning a constant.
10533 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
10534
10535 // Now compile the source again. And get the newly compiled functions, except
10536 // for h for which access is blocked.
10537 CompileRun(source);
10538 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
10539 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
10540 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
10541 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
10542 CHECK(context->Global()->Get(v8_str("h"))->IsUndefined());
10543
10544 // Failing access check to property get results in undefined.
10545 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
10546 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
10547
10548 // Failing access check to function call results in exception.
10549 CHECK(g1->Call(global, 0, NULL).IsEmpty());
10550 CHECK(g2->Call(global, 0, NULL).IsEmpty());
10551}
10552
10553
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010554// This test verifies that pre-compilation (aka preparsing) can be called
10555// without initializing the whole VM. Thus we cannot run this test in a
10556// multi-threaded setup.
10557TEST(PreCompile) {
10558 // TODO(155): This test would break without the initialization of V8. This is
10559 // a workaround for now to make this test not fail.
10560 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000010561 const char* script = "function foo(a) { return a+1; }";
10562 v8::ScriptData* sd =
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010563 v8::ScriptData::PreCompile(script, i::StrLength(script));
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010564 CHECK_NE(sd->Length(), 0);
10565 CHECK_NE(sd->Data(), NULL);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000010566 CHECK(!sd->HasError());
10567 delete sd;
10568}
10569
10570
10571TEST(PreCompileWithError) {
10572 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000010573 const char* script = "function foo(a) { return 1 * * 2; }";
10574 v8::ScriptData* sd =
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000010575 v8::ScriptData::PreCompile(script, i::StrLength(script));
10576 CHECK(sd->HasError());
10577 delete sd;
10578}
10579
10580
10581TEST(Regress31661) {
10582 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000010583 const char* script = " The Definintive Guide";
10584 v8::ScriptData* sd =
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000010585 v8::ScriptData::PreCompile(script, i::StrLength(script));
10586 CHECK(sd->HasError());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010587 delete sd;
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010588}
10589
10590
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000010591// Tests that ScriptData can be serialized and deserialized.
10592TEST(PreCompileSerialization) {
10593 v8::V8::Initialize();
10594 const char* script = "function foo(a) { return a+1; }";
10595 v8::ScriptData* sd =
10596 v8::ScriptData::PreCompile(script, i::StrLength(script));
10597
10598 // Serialize.
10599 int serialized_data_length = sd->Length();
10600 char* serialized_data = i::NewArray<char>(serialized_data_length);
10601 memcpy(serialized_data, sd->Data(), serialized_data_length);
10602
10603 // Deserialize.
10604 v8::ScriptData* deserialized_sd =
10605 v8::ScriptData::New(serialized_data, serialized_data_length);
10606
10607 // Verify that the original is the same as the deserialized.
10608 CHECK_EQ(sd->Length(), deserialized_sd->Length());
10609 CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
10610 CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
10611
10612 delete sd;
10613 delete deserialized_sd;
10614}
10615
10616
10617// Attempts to deserialize bad data.
10618TEST(PreCompileDeserializationError) {
10619 v8::V8::Initialize();
10620 const char* data = "DONT CARE";
10621 int invalid_size = 3;
10622 v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
10623
10624 CHECK_EQ(0, sd->Length());
10625
10626 delete sd;
10627}
10628
10629
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000010630// Attempts to deserialize bad data.
10631TEST(PreCompileInvalidPreparseDataError) {
10632 v8::V8::Initialize();
10633 v8::HandleScope scope;
10634 LocalContext context;
10635
10636 const char* script = "function foo(){ return 5;}\n"
10637 "function bar(){ return 6 + 7;} foo();";
10638 v8::ScriptData* sd =
10639 v8::ScriptData::PreCompile(script, i::StrLength(script));
10640 CHECK(!sd->HasError());
10641 // ScriptDataImpl private implementation details
ager@chromium.orgbeb25712010-11-29 08:02:25 +000010642 const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
ager@chromium.org5b2fbee2010-09-08 06:38:15 +000010643 const int kFunctionEntrySize = i::FunctionEntry::kSize;
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000010644 const int kFunctionEntryStartOffset = 0;
10645 const int kFunctionEntryEndOffset = 1;
10646 unsigned* sd_data =
10647 reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000010648
10649 // Overwrite function bar's end position with 0.
10650 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
10651 v8::TryCatch try_catch;
10652
10653 Local<String> source = String::New(script);
10654 Local<Script> compiled_script = Script::New(source, NULL, sd);
10655 CHECK(try_catch.HasCaught());
10656 String::AsciiValue exception_value(try_catch.Message()->Get());
10657 CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
10658 *exception_value);
10659
10660 try_catch.Reset();
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010661
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000010662 // Overwrite function bar's start position with 200. The function entry
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010663 // will not be found when searching for it by position and we should fall
10664 // back on eager compilation.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +000010665 sd = v8::ScriptData::PreCompile(script, i::StrLength(script));
10666 sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000010667 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
10668 200;
10669 compiled_script = Script::New(source, NULL, sd);
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010670 CHECK(!try_catch.HasCaught());
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000010671
10672 delete sd;
10673}
10674
10675
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000010676// Verifies that the Handle<String> and const char* versions of the API produce
10677// the same results (at least for one trivial case).
10678TEST(PreCompileAPIVariationsAreSame) {
10679 v8::V8::Initialize();
10680 v8::HandleScope scope;
10681
10682 const char* cstring = "function foo(a) { return a+1; }";
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010683
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000010684 v8::ScriptData* sd_from_cstring =
10685 v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
10686
10687 TestAsciiResource* resource = new TestAsciiResource(cstring);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010688 v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile(
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000010689 v8::String::NewExternal(resource));
10690
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010691 v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile(
10692 v8::String::New(cstring));
10693
10694 CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000010695 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010696 sd_from_external_string->Data(),
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000010697 sd_from_cstring->Length()));
10698
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010699 CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length());
10700 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
10701 sd_from_string->Data(),
10702 sd_from_cstring->Length()));
10703
10704
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000010705 delete sd_from_cstring;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010706 delete sd_from_external_string;
10707 delete sd_from_string;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000010708}
10709
10710
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010711// This tests that we do not allow dictionary load/call inline caches
10712// to use functions that have not yet been compiled. The potential
10713// problem of loading a function that has not yet been compiled can
10714// arise because we share code between contexts via the compilation
10715// cache.
10716THREADED_TEST(DictionaryICLoadedFunction) {
10717 v8::HandleScope scope;
10718 // Test LoadIC.
10719 for (int i = 0; i < 2; i++) {
10720 LocalContext context;
10721 context->Global()->Set(v8_str("tmp"), v8::True());
10722 context->Global()->Delete(v8_str("tmp"));
10723 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
10724 }
10725 // Test CallIC.
10726 for (int i = 0; i < 2; i++) {
10727 LocalContext context;
10728 context->Global()->Set(v8_str("tmp"), v8::True());
10729 context->Global()->Delete(v8_str("tmp"));
10730 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
10731 }
10732}
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010733
10734
10735// Test that cross-context new calls use the context of the callee to
10736// create the new JavaScript object.
10737THREADED_TEST(CrossContextNew) {
10738 v8::HandleScope scope;
10739 v8::Persistent<Context> context0 = Context::New();
10740 v8::Persistent<Context> context1 = Context::New();
10741
10742 // Allow cross-domain access.
10743 Local<String> token = v8_str("<security token>");
10744 context0->SetSecurityToken(token);
10745 context1->SetSecurityToken(token);
10746
10747 // Set an 'x' property on the Object prototype and define a
10748 // constructor function in context0.
10749 context0->Enter();
10750 CompileRun("Object.prototype.x = 42; function C() {};");
10751 context0->Exit();
10752
10753 // Call the constructor function from context0 and check that the
10754 // result has the 'x' property.
10755 context1->Enter();
10756 context1->Global()->Set(v8_str("other"), context0->Global());
10757 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
10758 CHECK(value->IsInt32());
10759 CHECK_EQ(42, value->Int32Value());
10760 context1->Exit();
10761
10762 // Dispose the contexts to allow them to be garbage collected.
10763 context0.Dispose();
10764 context1.Dispose();
10765}
ager@chromium.org381abbb2009-02-25 13:23:22 +000010766
10767
10768class RegExpInterruptTest {
10769 public:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010770 RegExpInterruptTest() : block_(NULL) {}
10771 ~RegExpInterruptTest() { delete block_; }
ager@chromium.org381abbb2009-02-25 13:23:22 +000010772 void RunTest() {
10773 block_ = i::OS::CreateSemaphore(0);
10774 gc_count_ = 0;
10775 gc_during_regexp_ = 0;
10776 regexp_success_ = false;
10777 gc_success_ = false;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010778 GCThread gc_thread(this);
ager@chromium.org381abbb2009-02-25 13:23:22 +000010779 gc_thread.Start();
10780 v8::Locker::StartPreemption(1);
10781
10782 LongRunningRegExp();
10783 {
10784 v8::Unlocker unlock;
10785 gc_thread.Join();
10786 }
10787 v8::Locker::StopPreemption();
10788 CHECK(regexp_success_);
10789 CHECK(gc_success_);
10790 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000010791
ager@chromium.org381abbb2009-02-25 13:23:22 +000010792 private:
10793 // Number of garbage collections required.
10794 static const int kRequiredGCs = 5;
10795
10796 class GCThread : public i::Thread {
10797 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010798 explicit GCThread(RegExpInterruptTest* test)
10799 : Thread("GCThread"), test_(test) {}
ager@chromium.org381abbb2009-02-25 13:23:22 +000010800 virtual void Run() {
10801 test_->CollectGarbage();
10802 }
10803 private:
10804 RegExpInterruptTest* test_;
10805 };
10806
10807 void CollectGarbage() {
10808 block_->Wait();
10809 while (gc_during_regexp_ < kRequiredGCs) {
10810 {
10811 v8::Locker lock;
10812 // TODO(lrn): Perhaps create some garbage before collecting.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010813 HEAP->CollectAllGarbage(false);
ager@chromium.org381abbb2009-02-25 13:23:22 +000010814 gc_count_++;
10815 }
10816 i::OS::Sleep(1);
10817 }
10818 gc_success_ = true;
10819 }
10820
10821 void LongRunningRegExp() {
10822 block_->Signal(); // Enable garbage collection thread on next preemption.
10823 int rounds = 0;
10824 while (gc_during_regexp_ < kRequiredGCs) {
10825 int gc_before = gc_count_;
10826 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010827 // Match 15-30 "a"'s against 14 and a "b".
ager@chromium.org381abbb2009-02-25 13:23:22 +000010828 const char* c_source =
10829 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
10830 ".exec('aaaaaaaaaaaaaaab') === null";
10831 Local<String> source = String::New(c_source);
10832 Local<Script> script = Script::Compile(source);
10833 Local<Value> result = script->Run();
10834 if (!result->BooleanValue()) {
10835 gc_during_regexp_ = kRequiredGCs; // Allow gc thread to exit.
10836 return;
10837 }
10838 }
10839 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010840 // Match 15-30 "a"'s against 15 and a "b".
ager@chromium.org381abbb2009-02-25 13:23:22 +000010841 const char* c_source =
10842 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
10843 ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
10844 Local<String> source = String::New(c_source);
10845 Local<Script> script = Script::Compile(source);
10846 Local<Value> result = script->Run();
10847 if (!result->BooleanValue()) {
10848 gc_during_regexp_ = kRequiredGCs;
10849 return;
10850 }
10851 }
10852 int gc_after = gc_count_;
10853 gc_during_regexp_ += gc_after - gc_before;
10854 rounds++;
10855 i::OS::Sleep(1);
10856 }
10857 regexp_success_ = true;
10858 }
10859
10860 i::Semaphore* block_;
10861 int gc_count_;
10862 int gc_during_regexp_;
10863 bool regexp_success_;
10864 bool gc_success_;
10865};
10866
10867
10868// Test that a regular expression execution can be interrupted and
10869// survive a garbage collection.
10870TEST(RegExpInterruption) {
10871 v8::Locker lock;
10872 v8::V8::Initialize();
10873 v8::HandleScope scope;
10874 Local<Context> local_env;
10875 {
10876 LocalContext env;
10877 local_env = env.local();
10878 }
10879
10880 // Local context should still be live.
10881 CHECK(!local_env.IsEmpty());
10882 local_env->Enter();
10883
10884 // Should complete without problems.
10885 RegExpInterruptTest().RunTest();
10886
10887 local_env->Exit();
10888}
ager@chromium.org3b45ab52009-03-19 22:21:34 +000010889
10890
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010891class ApplyInterruptTest {
10892 public:
10893 ApplyInterruptTest() : block_(NULL) {}
10894 ~ApplyInterruptTest() { delete block_; }
10895 void RunTest() {
10896 block_ = i::OS::CreateSemaphore(0);
10897 gc_count_ = 0;
10898 gc_during_apply_ = 0;
10899 apply_success_ = false;
10900 gc_success_ = false;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010901 GCThread gc_thread(this);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010902 gc_thread.Start();
10903 v8::Locker::StartPreemption(1);
10904
10905 LongRunningApply();
10906 {
10907 v8::Unlocker unlock;
10908 gc_thread.Join();
10909 }
10910 v8::Locker::StopPreemption();
10911 CHECK(apply_success_);
10912 CHECK(gc_success_);
10913 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000010914
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010915 private:
10916 // Number of garbage collections required.
10917 static const int kRequiredGCs = 2;
10918
10919 class GCThread : public i::Thread {
10920 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010921 explicit GCThread(ApplyInterruptTest* test)
10922 : Thread("GCThread"), test_(test) {}
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010923 virtual void Run() {
10924 test_->CollectGarbage();
10925 }
10926 private:
10927 ApplyInterruptTest* test_;
10928 };
10929
10930 void CollectGarbage() {
10931 block_->Wait();
10932 while (gc_during_apply_ < kRequiredGCs) {
10933 {
10934 v8::Locker lock;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010935 HEAP->CollectAllGarbage(false);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010936 gc_count_++;
10937 }
10938 i::OS::Sleep(1);
10939 }
10940 gc_success_ = true;
10941 }
10942
10943 void LongRunningApply() {
10944 block_->Signal();
10945 int rounds = 0;
10946 while (gc_during_apply_ < kRequiredGCs) {
10947 int gc_before = gc_count_;
10948 {
10949 const char* c_source =
10950 "function do_very_little(bar) {"
10951 " this.foo = bar;"
10952 "}"
10953 "for (var i = 0; i < 100000; i++) {"
10954 " do_very_little.apply(this, ['bar']);"
10955 "}";
10956 Local<String> source = String::New(c_source);
10957 Local<Script> script = Script::Compile(source);
10958 Local<Value> result = script->Run();
ager@chromium.org3a37e9b2009-04-27 09:26:21 +000010959 // Check that no exception was thrown.
10960 CHECK(!result.IsEmpty());
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010961 }
10962 int gc_after = gc_count_;
10963 gc_during_apply_ += gc_after - gc_before;
10964 rounds++;
10965 }
10966 apply_success_ = true;
10967 }
10968
10969 i::Semaphore* block_;
10970 int gc_count_;
10971 int gc_during_apply_;
10972 bool apply_success_;
10973 bool gc_success_;
10974};
10975
10976
10977// Test that nothing bad happens if we get a preemption just when we were
10978// about to do an apply().
10979TEST(ApplyInterruption) {
10980 v8::Locker lock;
10981 v8::V8::Initialize();
10982 v8::HandleScope scope;
10983 Local<Context> local_env;
10984 {
10985 LocalContext env;
10986 local_env = env.local();
10987 }
10988
10989 // Local context should still be live.
10990 CHECK(!local_env.IsEmpty());
10991 local_env->Enter();
10992
10993 // Should complete without problems.
10994 ApplyInterruptTest().RunTest();
10995
10996 local_env->Exit();
10997}
10998
10999
ager@chromium.org3b45ab52009-03-19 22:21:34 +000011000// Verify that we can clone an object
11001TEST(ObjectClone) {
11002 v8::HandleScope scope;
11003 LocalContext env;
11004
11005 const char* sample =
11006 "var rv = {};" \
11007 "rv.alpha = 'hello';" \
11008 "rv.beta = 123;" \
11009 "rv;";
11010
11011 // Create an object, verify basics.
11012 Local<Value> val = CompileRun(sample);
11013 CHECK(val->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011014 Local<v8::Object> obj = val.As<v8::Object>();
ager@chromium.org3b45ab52009-03-19 22:21:34 +000011015 obj->Set(v8_str("gamma"), v8_str("cloneme"));
11016
11017 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
11018 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
11019 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
11020
11021 // Clone it.
11022 Local<v8::Object> clone = obj->Clone();
11023 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
11024 CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
11025 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
11026
11027 // Set a property on the clone, verify each object.
11028 clone->Set(v8_str("beta"), v8::Integer::New(456));
11029 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
11030 CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
11031}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011032
11033
ager@chromium.org5ec48922009-05-05 07:25:34 +000011034class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
11035 public:
11036 explicit AsciiVectorResource(i::Vector<const char> vector)
11037 : data_(vector) {}
11038 virtual ~AsciiVectorResource() {}
11039 virtual size_t length() const { return data_.length(); }
11040 virtual const char* data() const { return data_.start(); }
11041 private:
11042 i::Vector<const char> data_;
11043};
11044
11045
11046class UC16VectorResource : public v8::String::ExternalStringResource {
11047 public:
11048 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
11049 : data_(vector) {}
11050 virtual ~UC16VectorResource() {}
11051 virtual size_t length() const { return data_.length(); }
11052 virtual const i::uc16* data() const { return data_.start(); }
11053 private:
11054 i::Vector<const i::uc16> data_;
11055};
11056
11057
11058static void MorphAString(i::String* string,
11059 AsciiVectorResource* ascii_resource,
11060 UC16VectorResource* uc16_resource) {
11061 CHECK(i::StringShape(string).IsExternal());
11062 if (string->IsAsciiRepresentation()) {
11063 // Check old map is not symbol or long.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011064 CHECK(string->map() == HEAP->external_ascii_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000011065 // Morph external string to be TwoByte string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011066 string->set_map(HEAP->external_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000011067 i::ExternalTwoByteString* morphed =
11068 i::ExternalTwoByteString::cast(string);
11069 morphed->set_resource(uc16_resource);
11070 } else {
11071 // Check old map is not symbol or long.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011072 CHECK(string->map() == HEAP->external_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000011073 // Morph external string to be ASCII string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011074 string->set_map(HEAP->external_ascii_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000011075 i::ExternalAsciiString* morphed =
11076 i::ExternalAsciiString::cast(string);
11077 morphed->set_resource(ascii_resource);
11078 }
11079}
11080
11081
11082// Test that we can still flatten a string if the components it is built up
11083// from have been turned into 16 bit strings in the mean time.
11084THREADED_TEST(MorphCompositeStringTest) {
11085 const char* c_string = "Now is the time for all good men"
11086 " to come to the aid of the party";
11087 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
11088 {
11089 v8::HandleScope scope;
11090 LocalContext env;
11091 AsciiVectorResource ascii_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011092 i::Vector<const char>(c_string, i::StrLength(c_string)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000011093 UC16VectorResource uc16_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011094 i::Vector<const uint16_t>(two_byte_string,
11095 i::StrLength(c_string)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000011096
11097 Local<String> lhs(v8::Utils::ToLocal(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011098 FACTORY->NewExternalStringFromAscii(&ascii_resource)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000011099 Local<String> rhs(v8::Utils::ToLocal(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011100 FACTORY->NewExternalStringFromAscii(&ascii_resource)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000011101
11102 env->Global()->Set(v8_str("lhs"), lhs);
11103 env->Global()->Set(v8_str("rhs"), rhs);
11104
11105 CompileRun(
11106 "var cons = lhs + rhs;"
11107 "var slice = lhs.substring(1, lhs.length - 1);"
11108 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
11109
11110 MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
11111 MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
11112
11113 // Now do some stuff to make sure the strings are flattened, etc.
11114 CompileRun(
11115 "/[^a-z]/.test(cons);"
11116 "/[^a-z]/.test(slice);"
11117 "/[^a-z]/.test(slice_on_cons);");
11118 const char* expected_cons =
11119 "Now is the time for all good men to come to the aid of the party"
11120 "Now is the time for all good men to come to the aid of the party";
11121 const char* expected_slice =
11122 "ow is the time for all good men to come to the aid of the part";
11123 const char* expected_slice_on_cons =
11124 "ow is the time for all good men to come to the aid of the party"
11125 "Now is the time for all good men to come to the aid of the part";
11126 CHECK_EQ(String::New(expected_cons),
11127 env->Global()->Get(v8_str("cons")));
11128 CHECK_EQ(String::New(expected_slice),
11129 env->Global()->Get(v8_str("slice")));
11130 CHECK_EQ(String::New(expected_slice_on_cons),
11131 env->Global()->Get(v8_str("slice_on_cons")));
11132 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011133 i::DeleteArray(two_byte_string);
ager@chromium.org5ec48922009-05-05 07:25:34 +000011134}
11135
11136
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011137TEST(CompileExternalTwoByteSource) {
11138 v8::HandleScope scope;
11139 LocalContext context;
11140
11141 // This is a very short list of sources, which currently is to check for a
11142 // regression caused by r2703.
11143 const char* ascii_sources[] = {
11144 "0.5",
11145 "-0.5", // This mainly testes PushBack in the Scanner.
11146 "--0.5", // This mainly testes PushBack in the Scanner.
11147 NULL
11148 };
11149
11150 // Compile the sources as external two byte strings.
11151 for (int i = 0; ascii_sources[i] != NULL; i++) {
11152 uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
11153 UC16VectorResource uc16_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011154 i::Vector<const uint16_t>(two_byte_string,
11155 i::StrLength(ascii_sources[i])));
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011156 v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
11157 v8::Script::Compile(source);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011158 i::DeleteArray(two_byte_string);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011159 }
11160}
11161
11162
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011163class RegExpStringModificationTest {
11164 public:
11165 RegExpStringModificationTest()
11166 : block_(i::OS::CreateSemaphore(0)),
11167 morphs_(0),
11168 morphs_during_regexp_(0),
11169 ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
11170 uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
11171 ~RegExpStringModificationTest() { delete block_; }
11172 void RunTest() {
11173 regexp_success_ = false;
11174 morph_success_ = false;
11175
11176 // Initialize the contents of two_byte_content_ to be a uc16 representation
11177 // of "aaaaaaaaaaaaaab".
11178 for (int i = 0; i < 14; i++) {
11179 two_byte_content_[i] = 'a';
11180 }
11181 two_byte_content_[14] = 'b';
11182
11183 // Create the input string for the regexp - the one we are going to change
11184 // properties of.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011185 input_ = FACTORY->NewExternalStringFromAscii(&ascii_resource_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011186
11187 // Inject the input as a global variable.
11188 i::Handle<i::String> input_name =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011189 FACTORY->NewStringFromAscii(i::Vector<const char>("input", 5));
11190 i::Isolate::Current()->global_context()->global()->SetProperty(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011191 *input_name,
11192 *input_,
11193 NONE,
11194 i::kNonStrictMode)->ToObjectChecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011195
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011196 MorphThread morph_thread(this);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011197 morph_thread.Start();
11198 v8::Locker::StartPreemption(1);
11199 LongRunningRegExp();
11200 {
11201 v8::Unlocker unlock;
11202 morph_thread.Join();
11203 }
11204 v8::Locker::StopPreemption();
11205 CHECK(regexp_success_);
11206 CHECK(morph_success_);
11207 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011208
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000011209 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011210 // Number of string modifications required.
11211 static const int kRequiredModifications = 5;
11212 static const int kMaxModifications = 100;
11213
11214 class MorphThread : public i::Thread {
11215 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011216 explicit MorphThread(RegExpStringModificationTest* test)
11217 : Thread("MorphThread"), test_(test) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011218 virtual void Run() {
11219 test_->MorphString();
11220 }
11221 private:
11222 RegExpStringModificationTest* test_;
11223 };
11224
11225 void MorphString() {
11226 block_->Wait();
11227 while (morphs_during_regexp_ < kRequiredModifications &&
11228 morphs_ < kMaxModifications) {
11229 {
11230 v8::Locker lock;
11231 // Swap string between ascii and two-byte representation.
11232 i::String* string = *input_;
ager@chromium.org5ec48922009-05-05 07:25:34 +000011233 MorphAString(string, &ascii_resource_, &uc16_resource_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011234 morphs_++;
11235 }
11236 i::OS::Sleep(1);
11237 }
11238 morph_success_ = true;
11239 }
11240
11241 void LongRunningRegExp() {
11242 block_->Signal(); // Enable morphing thread on next preemption.
11243 while (morphs_during_regexp_ < kRequiredModifications &&
11244 morphs_ < kMaxModifications) {
11245 int morphs_before = morphs_;
11246 {
erik.corry@gmail.com145eff52010-08-23 11:36:18 +000011247 v8::HandleScope scope;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011248 // Match 15-30 "a"'s against 14 and a "b".
11249 const char* c_source =
11250 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
11251 ".exec(input) === null";
11252 Local<String> source = String::New(c_source);
11253 Local<Script> script = Script::Compile(source);
11254 Local<Value> result = script->Run();
11255 CHECK(result->IsTrue());
11256 }
11257 int morphs_after = morphs_;
11258 morphs_during_regexp_ += morphs_after - morphs_before;
11259 }
11260 regexp_success_ = true;
11261 }
11262
11263 i::uc16 two_byte_content_[15];
11264 i::Semaphore* block_;
11265 int morphs_;
11266 int morphs_during_regexp_;
11267 bool regexp_success_;
11268 bool morph_success_;
11269 i::Handle<i::String> input_;
11270 AsciiVectorResource ascii_resource_;
11271 UC16VectorResource uc16_resource_;
11272};
11273
11274
11275// Test that a regular expression execution can be interrupted and
11276// the string changed without failing.
11277TEST(RegExpStringModification) {
11278 v8::Locker lock;
11279 v8::V8::Initialize();
11280 v8::HandleScope scope;
11281 Local<Context> local_env;
11282 {
11283 LocalContext env;
11284 local_env = env.local();
11285 }
11286
11287 // Local context should still be live.
11288 CHECK(!local_env.IsEmpty());
11289 local_env->Enter();
11290
11291 // Should complete without problems.
11292 RegExpStringModificationTest().RunTest();
11293
11294 local_env->Exit();
11295}
11296
11297
11298// Test that we can set a property on the global object even if there
11299// is a read-only property in the prototype chain.
11300TEST(ReadOnlyPropertyInGlobalProto) {
11301 v8::HandleScope scope;
11302 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11303 LocalContext context(0, templ);
11304 v8::Handle<v8::Object> global = context->Global();
11305 v8::Handle<v8::Object> global_proto =
11306 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
11307 global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
11308 global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
11309 // Check without 'eval' or 'with'.
11310 v8::Handle<v8::Value> res =
11311 CompileRun("function f() { x = 42; return x; }; f()");
11312 // Check with 'eval'.
11313 res = CompileRun("function f() { eval('1'); y = 42; return y; }; f()");
11314 CHECK_EQ(v8::Integer::New(42), res);
11315 // Check with 'with'.
11316 res = CompileRun("function f() { with (this) { y = 42 }; return y; }; f()");
11317 CHECK_EQ(v8::Integer::New(42), res);
11318}
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011319
11320static int force_set_set_count = 0;
11321static int force_set_get_count = 0;
11322bool pass_on_get = false;
11323
11324static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
11325 const v8::AccessorInfo& info) {
11326 force_set_get_count++;
11327 if (pass_on_get) {
11328 return v8::Handle<v8::Value>();
11329 } else {
11330 return v8::Int32::New(3);
11331 }
11332}
11333
11334static void ForceSetSetter(v8::Local<v8::String> name,
11335 v8::Local<v8::Value> value,
11336 const v8::AccessorInfo& info) {
11337 force_set_set_count++;
11338}
11339
11340static v8::Handle<v8::Value> ForceSetInterceptSetter(
11341 v8::Local<v8::String> name,
11342 v8::Local<v8::Value> value,
11343 const v8::AccessorInfo& info) {
11344 force_set_set_count++;
11345 return v8::Undefined();
11346}
11347
11348TEST(ForceSet) {
11349 force_set_get_count = 0;
11350 force_set_set_count = 0;
11351 pass_on_get = false;
11352
11353 v8::HandleScope scope;
11354 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11355 v8::Handle<v8::String> access_property = v8::String::New("a");
11356 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
11357 LocalContext context(NULL, templ);
11358 v8::Handle<v8::Object> global = context->Global();
11359
11360 // Ordinary properties
11361 v8::Handle<v8::String> simple_property = v8::String::New("p");
11362 global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
11363 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11364 // This should fail because the property is read-only
11365 global->Set(simple_property, v8::Int32::New(5));
11366 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11367 // This should succeed even though the property is read-only
11368 global->ForceSet(simple_property, v8::Int32::New(6));
11369 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
11370
11371 // Accessors
11372 CHECK_EQ(0, force_set_set_count);
11373 CHECK_EQ(0, force_set_get_count);
11374 CHECK_EQ(3, global->Get(access_property)->Int32Value());
11375 // CHECK_EQ the property shouldn't override it, just call the setter
11376 // which in this case does nothing.
11377 global->Set(access_property, v8::Int32::New(7));
11378 CHECK_EQ(3, global->Get(access_property)->Int32Value());
11379 CHECK_EQ(1, force_set_set_count);
11380 CHECK_EQ(2, force_set_get_count);
11381 // Forcing the property to be set should override the accessor without
11382 // calling it
11383 global->ForceSet(access_property, v8::Int32::New(8));
11384 CHECK_EQ(8, global->Get(access_property)->Int32Value());
11385 CHECK_EQ(1, force_set_set_count);
11386 CHECK_EQ(2, force_set_get_count);
11387}
11388
11389TEST(ForceSetWithInterceptor) {
11390 force_set_get_count = 0;
11391 force_set_set_count = 0;
11392 pass_on_get = false;
11393
11394 v8::HandleScope scope;
11395 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11396 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
11397 LocalContext context(NULL, templ);
11398 v8::Handle<v8::Object> global = context->Global();
11399
11400 v8::Handle<v8::String> some_property = v8::String::New("a");
11401 CHECK_EQ(0, force_set_set_count);
11402 CHECK_EQ(0, force_set_get_count);
11403 CHECK_EQ(3, global->Get(some_property)->Int32Value());
11404 // Setting the property shouldn't override it, just call the setter
11405 // which in this case does nothing.
11406 global->Set(some_property, v8::Int32::New(7));
11407 CHECK_EQ(3, global->Get(some_property)->Int32Value());
11408 CHECK_EQ(1, force_set_set_count);
11409 CHECK_EQ(2, force_set_get_count);
11410 // Getting the property when the interceptor returns an empty handle
11411 // should yield undefined, since the property isn't present on the
11412 // object itself yet.
11413 pass_on_get = true;
11414 CHECK(global->Get(some_property)->IsUndefined());
11415 CHECK_EQ(1, force_set_set_count);
11416 CHECK_EQ(3, force_set_get_count);
11417 // Forcing the property to be set should cause the value to be
11418 // set locally without calling the interceptor.
11419 global->ForceSet(some_property, v8::Int32::New(8));
11420 CHECK_EQ(8, global->Get(some_property)->Int32Value());
11421 CHECK_EQ(1, force_set_set_count);
11422 CHECK_EQ(4, force_set_get_count);
11423 // Reenabling the interceptor should cause it to take precedence over
11424 // the property
11425 pass_on_get = false;
11426 CHECK_EQ(3, global->Get(some_property)->Int32Value());
11427 CHECK_EQ(1, force_set_set_count);
11428 CHECK_EQ(5, force_set_get_count);
11429 // The interceptor should also work for other properties
11430 CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
11431 CHECK_EQ(1, force_set_set_count);
11432 CHECK_EQ(6, force_set_get_count);
11433}
ager@chromium.org1bf0cd02009-05-20 11:34:19 +000011434
11435
ager@chromium.orge2902be2009-06-08 12:21:35 +000011436THREADED_TEST(ForceDelete) {
11437 v8::HandleScope scope;
11438 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11439 LocalContext context(NULL, templ);
11440 v8::Handle<v8::Object> global = context->Global();
11441
11442 // Ordinary properties
11443 v8::Handle<v8::String> simple_property = v8::String::New("p");
11444 global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
11445 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11446 // This should fail because the property is dont-delete.
11447 CHECK(!global->Delete(simple_property));
11448 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11449 // This should succeed even though the property is dont-delete.
11450 CHECK(global->ForceDelete(simple_property));
11451 CHECK(global->Get(simple_property)->IsUndefined());
11452}
11453
11454
11455static int force_delete_interceptor_count = 0;
11456static bool pass_on_delete = false;
11457
11458
11459static v8::Handle<v8::Boolean> ForceDeleteDeleter(
11460 v8::Local<v8::String> name,
11461 const v8::AccessorInfo& info) {
11462 force_delete_interceptor_count++;
11463 if (pass_on_delete) {
11464 return v8::Handle<v8::Boolean>();
11465 } else {
11466 return v8::True();
11467 }
11468}
11469
11470
11471THREADED_TEST(ForceDeleteWithInterceptor) {
11472 force_delete_interceptor_count = 0;
11473 pass_on_delete = false;
11474
11475 v8::HandleScope scope;
11476 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11477 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
11478 LocalContext context(NULL, templ);
11479 v8::Handle<v8::Object> global = context->Global();
11480
11481 v8::Handle<v8::String> some_property = v8::String::New("a");
11482 global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
11483
11484 // Deleting a property should get intercepted and nothing should
11485 // happen.
11486 CHECK_EQ(0, force_delete_interceptor_count);
11487 CHECK(global->Delete(some_property));
11488 CHECK_EQ(1, force_delete_interceptor_count);
11489 CHECK_EQ(42, global->Get(some_property)->Int32Value());
11490 // Deleting the property when the interceptor returns an empty
11491 // handle should not delete the property since it is DontDelete.
11492 pass_on_delete = true;
11493 CHECK(!global->Delete(some_property));
11494 CHECK_EQ(2, force_delete_interceptor_count);
11495 CHECK_EQ(42, global->Get(some_property)->Int32Value());
11496 // Forcing the property to be deleted should delete the value
11497 // without calling the interceptor.
11498 CHECK(global->ForceDelete(some_property));
11499 CHECK(global->Get(some_property)->IsUndefined());
11500 CHECK_EQ(2, force_delete_interceptor_count);
11501}
11502
11503
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000011504// Make sure that forcing a delete invalidates any IC stubs, so we
11505// don't read the hole value.
11506THREADED_TEST(ForceDeleteIC) {
11507 v8::HandleScope scope;
11508 LocalContext context;
11509 // Create a DontDelete variable on the global object.
11510 CompileRun("this.__proto__ = { foo: 'horse' };"
11511 "var foo = 'fish';"
11512 "function f() { return foo.length; }");
11513 // Initialize the IC for foo in f.
11514 CompileRun("for (var i = 0; i < 4; i++) f();");
11515 // Make sure the value of foo is correct before the deletion.
11516 CHECK_EQ(4, CompileRun("f()")->Int32Value());
11517 // Force the deletion of foo.
11518 CHECK(context->Global()->ForceDelete(v8_str("foo")));
11519 // Make sure the value for foo is read from the prototype, and that
11520 // we don't get in trouble with reading the deleted cell value
11521 // sentinel.
11522 CHECK_EQ(5, CompileRun("f()")->Int32Value());
11523}
11524
11525
ager@chromium.org1bf0cd02009-05-20 11:34:19 +000011526v8::Persistent<Context> calling_context0;
11527v8::Persistent<Context> calling_context1;
11528v8::Persistent<Context> calling_context2;
11529
11530
11531// Check that the call to the callback is initiated in
11532// calling_context2, the directly calling context is calling_context1
11533// and the callback itself is in calling_context0.
11534static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
11535 ApiTestFuzzer::Fuzz();
11536 CHECK(Context::GetCurrent() == calling_context0);
11537 CHECK(Context::GetCalling() == calling_context1);
11538 CHECK(Context::GetEntered() == calling_context2);
11539 return v8::Integer::New(42);
11540}
11541
11542
11543THREADED_TEST(GetCallingContext) {
11544 v8::HandleScope scope;
11545
11546 calling_context0 = Context::New();
11547 calling_context1 = Context::New();
11548 calling_context2 = Context::New();
11549
11550 // Allow cross-domain access.
11551 Local<String> token = v8_str("<security token>");
11552 calling_context0->SetSecurityToken(token);
11553 calling_context1->SetSecurityToken(token);
11554 calling_context2->SetSecurityToken(token);
11555
11556 // Create an object with a C++ callback in context0.
11557 calling_context0->Enter();
11558 Local<v8::FunctionTemplate> callback_templ =
11559 v8::FunctionTemplate::New(GetCallingContextCallback);
11560 calling_context0->Global()->Set(v8_str("callback"),
11561 callback_templ->GetFunction());
11562 calling_context0->Exit();
11563
11564 // Expose context0 in context1 and setup a function that calls the
11565 // callback function.
11566 calling_context1->Enter();
11567 calling_context1->Global()->Set(v8_str("context0"),
11568 calling_context0->Global());
11569 CompileRun("function f() { context0.callback() }");
11570 calling_context1->Exit();
11571
11572 // Expose context1 in context2 and call the callback function in
11573 // context0 indirectly through f in context1.
11574 calling_context2->Enter();
11575 calling_context2->Global()->Set(v8_str("context1"),
11576 calling_context1->Global());
11577 CompileRun("context1.f()");
11578 calling_context2->Exit();
11579
11580 // Dispose the contexts to allow them to be garbage collected.
11581 calling_context0.Dispose();
11582 calling_context1.Dispose();
11583 calling_context2.Dispose();
11584 calling_context0.Clear();
11585 calling_context1.Clear();
11586 calling_context2.Clear();
11587}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011588
11589
11590// Check that a variable declaration with no explicit initialization
11591// value does not shadow an existing property in the prototype chain.
11592//
11593// This is consistent with Firefox and Safari.
11594//
11595// See http://crbug.com/12548.
11596THREADED_TEST(InitGlobalVarInProtoChain) {
11597 v8::HandleScope scope;
11598 LocalContext context;
11599 // Introduce a variable in the prototype chain.
11600 CompileRun("__proto__.x = 42");
11601 v8::Handle<v8::Value> result = CompileRun("var x; x");
11602 CHECK(!result->IsUndefined());
11603 CHECK_EQ(42, result->Int32Value());
11604}
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000011605
11606
11607// Regression test for issue 398.
11608// If a function is added to an object, creating a constant function
11609// field, and the result is cloned, replacing the constant function on the
11610// original should not affect the clone.
11611// See http://code.google.com/p/v8/issues/detail?id=398
11612THREADED_TEST(ReplaceConstantFunction) {
11613 v8::HandleScope scope;
11614 LocalContext context;
11615 v8::Handle<v8::Object> obj = v8::Object::New();
11616 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
11617 v8::Handle<v8::String> foo_string = v8::String::New("foo");
11618 obj->Set(foo_string, func_templ->GetFunction());
11619 v8::Handle<v8::Object> obj_clone = obj->Clone();
11620 obj_clone->Set(foo_string, v8::String::New("Hello"));
11621 CHECK(!obj->Get(foo_string)->IsUndefined());
11622}
kasperl@chromium.orge959c182009-07-27 08:59:04 +000011623
11624
11625// Regression test for http://crbug.com/16276.
11626THREADED_TEST(Regress16276) {
11627 v8::HandleScope scope;
11628 LocalContext context;
11629 // Force the IC in f to be a dictionary load IC.
11630 CompileRun("function f(obj) { return obj.x; }\n"
11631 "var obj = { x: { foo: 42 }, y: 87 };\n"
11632 "var x = obj.x;\n"
11633 "delete obj.y;\n"
11634 "for (var i = 0; i < 5; i++) f(obj);");
11635 // Detach the global object to make 'this' refer directly to the
11636 // global object (not the proxy), and make sure that the dictionary
11637 // load IC doesn't mess up loading directly from the global object.
11638 context->DetachGlobal();
11639 CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
11640}
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011641
11642
11643THREADED_TEST(PixelArray) {
11644 v8::HandleScope scope;
11645 LocalContext context;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011646 const int kElementCount = 260;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011647 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000011648 i::Handle<i::ExternalPixelArray> pixels =
11649 i::Handle<i::ExternalPixelArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011650 FACTORY->NewExternalArray(kElementCount,
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000011651 v8::kExternalPixelArray,
11652 pixel_data));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011653 HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011654 for (int i = 0; i < kElementCount; i++) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011655 pixels->set(i, i % 256);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011656 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011657 HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011658 for (int i = 0; i < kElementCount; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011659 CHECK_EQ(i % 256, pixels->get_scalar(i));
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011660 CHECK_EQ(i % 256, pixel_data[i]);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011661 }
11662
11663 v8::Handle<v8::Object> obj = v8::Object::New();
11664 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
11665 // Set the elements to be the pixels.
11666 // jsobj->set_elements(*pixels);
11667 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011668 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011669 obj->Set(v8_str("field"), v8::Int32::New(1503));
11670 context->Global()->Set(v8_str("pixels"), obj);
11671 v8::Handle<v8::Value> result = CompileRun("pixels.field");
11672 CHECK_EQ(1503, result->Int32Value());
11673 result = CompileRun("pixels[1]");
11674 CHECK_EQ(1, result->Int32Value());
sgjesse@chromium.org9eceac12009-09-30 07:18:41 +000011675
11676 result = CompileRun("var sum = 0;"
11677 "for (var i = 0; i < 8; i++) {"
11678 " sum += pixels[i] = pixels[i] = -i;"
11679 "}"
11680 "sum;");
11681 CHECK_EQ(-28, result->Int32Value());
11682
11683 result = CompileRun("var sum = 0;"
11684 "for (var i = 0; i < 8; i++) {"
11685 " sum += pixels[i] = pixels[i] = 0;"
11686 "}"
11687 "sum;");
11688 CHECK_EQ(0, result->Int32Value());
11689
11690 result = CompileRun("var sum = 0;"
11691 "for (var i = 0; i < 8; i++) {"
11692 " sum += pixels[i] = pixels[i] = 255;"
11693 "}"
11694 "sum;");
11695 CHECK_EQ(8 * 255, result->Int32Value());
11696
11697 result = CompileRun("var sum = 0;"
11698 "for (var i = 0; i < 8; i++) {"
11699 " sum += pixels[i] = pixels[i] = 256 + i;"
11700 "}"
11701 "sum;");
11702 CHECK_EQ(2076, result->Int32Value());
11703
11704 result = CompileRun("var sum = 0;"
11705 "for (var i = 0; i < 8; i++) {"
11706 " sum += pixels[i] = pixels[i] = i;"
11707 "}"
11708 "sum;");
11709 CHECK_EQ(28, result->Int32Value());
11710
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011711 result = CompileRun("var sum = 0;"
11712 "for (var i = 0; i < 8; i++) {"
11713 " sum += pixels[i];"
11714 "}"
11715 "sum;");
11716 CHECK_EQ(28, result->Int32Value());
11717
11718 i::Handle<i::Smi> value(i::Smi::FromInt(2));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011719 i::SetElement(jsobj, 1, value, i::kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011720 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011721 *value.location() = i::Smi::FromInt(256);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011722 i::SetElement(jsobj, 1, value, i::kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011723 CHECK_EQ(255,
11724 i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011725 *value.location() = i::Smi::FromInt(-1);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011726 i::SetElement(jsobj, 1, value, i::kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011727 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011728
11729 result = CompileRun("for (var i = 0; i < 8; i++) {"
11730 " pixels[i] = (i * 65) - 109;"
11731 "}"
11732 "pixels[1] + pixels[6];");
11733 CHECK_EQ(255, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011734 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
11735 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
11736 CHECK_EQ(21,
11737 i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
11738 CHECK_EQ(86,
11739 i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
11740 CHECK_EQ(151,
11741 i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
11742 CHECK_EQ(216,
11743 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
11744 CHECK_EQ(255,
11745 i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
11746 CHECK_EQ(255,
11747 i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011748 result = CompileRun("var sum = 0;"
11749 "for (var i = 0; i < 8; i++) {"
11750 " sum += pixels[i];"
11751 "}"
11752 "sum;");
11753 CHECK_EQ(984, result->Int32Value());
11754
11755 result = CompileRun("for (var i = 0; i < 8; i++) {"
11756 " pixels[i] = (i * 1.1);"
11757 "}"
11758 "pixels[1] + pixels[6];");
11759 CHECK_EQ(8, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011760 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
11761 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
11762 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
11763 CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
11764 CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
11765 CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
11766 CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
11767 CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011768
11769 result = CompileRun("for (var i = 0; i < 8; i++) {"
11770 " pixels[7] = undefined;"
11771 "}"
11772 "pixels[7];");
11773 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011774 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011775
11776 result = CompileRun("for (var i = 0; i < 8; i++) {"
11777 " pixels[6] = '2.3';"
11778 "}"
11779 "pixels[6];");
11780 CHECK_EQ(2, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011781 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011782
11783 result = CompileRun("for (var i = 0; i < 8; i++) {"
11784 " pixels[5] = NaN;"
11785 "}"
11786 "pixels[5];");
11787 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011788 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011789
11790 result = CompileRun("for (var i = 0; i < 8; i++) {"
11791 " pixels[8] = Infinity;"
11792 "}"
11793 "pixels[8];");
11794 CHECK_EQ(255, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011795 CHECK_EQ(255,
11796 i::Smi::cast(jsobj->GetElement(8)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011797
11798 result = CompileRun("for (var i = 0; i < 8; i++) {"
11799 " pixels[9] = -Infinity;"
11800 "}"
11801 "pixels[9];");
11802 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011803 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011804
11805 result = CompileRun("pixels[3] = 33;"
11806 "delete pixels[3];"
11807 "pixels[3];");
11808 CHECK_EQ(33, result->Int32Value());
11809
11810 result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
11811 "pixels[2] = 12; pixels[3] = 13;"
11812 "pixels.__defineGetter__('2',"
11813 "function() { return 120; });"
11814 "pixels[2];");
11815 CHECK_EQ(12, result->Int32Value());
11816
11817 result = CompileRun("var js_array = new Array(40);"
11818 "js_array[0] = 77;"
11819 "js_array;");
11820 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
11821
11822 result = CompileRun("pixels[1] = 23;"
11823 "pixels.__proto__ = [];"
11824 "js_array.__proto__ = pixels;"
11825 "js_array.concat(pixels);");
11826 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
11827 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
11828
sgjesse@chromium.org9eceac12009-09-30 07:18:41 +000011829 result = CompileRun("pixels[1] = 23;");
11830 CHECK_EQ(23, result->Int32Value());
11831
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011832 // Test for index greater than 255. Regression test for:
11833 // http://code.google.com/p/chromium/issues/detail?id=26337.
11834 result = CompileRun("pixels[256] = 255;");
11835 CHECK_EQ(255, result->Int32Value());
11836 result = CompileRun("var i = 0;"
11837 "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
11838 "i");
11839 CHECK_EQ(255, result->Int32Value());
11840
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011841 // Make sure that pixel array ICs recognize when a non-pixel array
11842 // is passed to it.
11843 result = CompileRun("function pa_load(p) {"
11844 " var sum = 0;"
11845 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
11846 " return sum;"
11847 "}"
11848 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11849 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
11850 "just_ints = new Object();"
11851 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11852 "for (var i = 0; i < 10; ++i) {"
11853 " result = pa_load(just_ints);"
11854 "}"
11855 "result");
11856 CHECK_EQ(32640, result->Int32Value());
11857
11858 // Make sure that pixel array ICs recognize out-of-bound accesses.
11859 result = CompileRun("function pa_load(p, start) {"
11860 " var sum = 0;"
11861 " for (var j = start; j < 256; j++) { sum += p[j]; }"
11862 " return sum;"
11863 "}"
11864 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11865 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
11866 "for (var i = 0; i < 10; ++i) {"
11867 " result = pa_load(pixels,-10);"
11868 "}"
11869 "result");
11870 CHECK_EQ(0, result->Int32Value());
11871
11872 // Make sure that generic ICs properly handles a pixel array.
11873 result = CompileRun("function pa_load(p) {"
11874 " var sum = 0;"
11875 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
11876 " return sum;"
11877 "}"
11878 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11879 "just_ints = new Object();"
11880 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11881 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
11882 "for (var i = 0; i < 10; ++i) {"
11883 " result = pa_load(pixels);"
11884 "}"
11885 "result");
11886 CHECK_EQ(32640, result->Int32Value());
11887
11888 // Make sure that generic load ICs recognize out-of-bound accesses in
11889 // pixel arrays.
11890 result = CompileRun("function pa_load(p, start) {"
11891 " var sum = 0;"
11892 " for (var j = start; j < 256; j++) { sum += p[j]; }"
11893 " return sum;"
11894 "}"
11895 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11896 "just_ints = new Object();"
11897 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11898 "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
11899 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
11900 "for (var i = 0; i < 10; ++i) {"
11901 " result = pa_load(pixels,-10);"
11902 "}"
11903 "result");
11904 CHECK_EQ(0, result->Int32Value());
11905
11906 // Make sure that generic ICs properly handles other types than pixel
11907 // arrays (that the inlined fast pixel array test leaves the right information
11908 // in the right registers).
11909 result = CompileRun("function pa_load(p) {"
11910 " var sum = 0;"
11911 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
11912 " return sum;"
11913 "}"
11914 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11915 "just_ints = new Object();"
11916 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11917 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
11918 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
11919 "sparse_array = new Object();"
11920 "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
11921 "sparse_array[1000000] = 3;"
11922 "for (var i = 0; i < 10; ++i) {"
11923 " result = pa_load(sparse_array);"
11924 "}"
11925 "result");
11926 CHECK_EQ(32640, result->Int32Value());
11927
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +000011928 // Make sure that pixel array store ICs clamp values correctly.
11929 result = CompileRun("function pa_store(p) {"
11930 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
11931 "}"
11932 "pa_store(pixels);"
11933 "var sum = 0;"
11934 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
11935 "sum");
11936 CHECK_EQ(48896, result->Int32Value());
11937
11938 // Make sure that pixel array stores correctly handle accesses outside
11939 // of the pixel array..
11940 result = CompileRun("function pa_store(p,start) {"
11941 " for (var j = 0; j < 256; j++) {"
11942 " p[j+start] = j * 2;"
11943 " }"
11944 "}"
11945 "pa_store(pixels,0);"
11946 "pa_store(pixels,-128);"
11947 "var sum = 0;"
11948 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
11949 "sum");
11950 CHECK_EQ(65280, result->Int32Value());
11951
11952 // Make sure that the generic store stub correctly handle accesses outside
11953 // of the pixel array..
11954 result = CompileRun("function pa_store(p,start) {"
11955 " for (var j = 0; j < 256; j++) {"
11956 " p[j+start] = j * 2;"
11957 " }"
11958 "}"
11959 "pa_store(pixels,0);"
11960 "just_ints = new Object();"
11961 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11962 "pa_store(just_ints, 0);"
11963 "pa_store(pixels,-128);"
11964 "var sum = 0;"
11965 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
11966 "sum");
11967 CHECK_EQ(65280, result->Int32Value());
11968
11969 // Make sure that the generic keyed store stub clamps pixel array values
11970 // correctly.
11971 result = CompileRun("function pa_store(p) {"
11972 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
11973 "}"
11974 "pa_store(pixels);"
11975 "just_ints = new Object();"
11976 "pa_store(just_ints);"
11977 "pa_store(pixels);"
11978 "var sum = 0;"
11979 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
11980 "sum");
11981 CHECK_EQ(48896, result->Int32Value());
11982
11983 // Make sure that pixel array loads are optimized by crankshaft.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011984 result = CompileRun("function pa_load(p) {"
11985 " var sum = 0;"
11986 " for (var i=0; i<256; ++i) {"
11987 " sum += p[i];"
11988 " }"
11989 " return sum; "
11990 "}"
11991 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000011992 "for (var i = 0; i < 5000; ++i) {"
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011993 " result = pa_load(pixels);"
11994 "}"
11995 "result");
11996 CHECK_EQ(32640, result->Int32Value());
11997
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000011998 // Make sure that pixel array stores are optimized by crankshaft.
11999 result = CompileRun("function pa_init(p) {"
12000 "for (var i = 0; i < 256; ++i) { p[i] = i; }"
12001 "}"
12002 "function pa_load(p) {"
12003 " var sum = 0;"
12004 " for (var i=0; i<256; ++i) {"
12005 " sum += p[i];"
12006 " }"
12007 " return sum; "
12008 "}"
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012009 "for (var i = 0; i < 5000; ++i) {"
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000012010 " pa_init(pixels);"
12011 "}"
12012 "result = pa_load(pixels);"
12013 "result");
12014 CHECK_EQ(32640, result->Int32Value());
12015
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012016 free(pixel_data);
12017}
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000012018
ager@chromium.org96c75b52009-08-26 09:13:16 +000012019
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000012020THREADED_TEST(PixelArrayInfo) {
12021 v8::HandleScope scope;
12022 LocalContext context;
12023 for (int size = 0; size < 100; size += 10) {
12024 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
12025 v8::Handle<v8::Object> obj = v8::Object::New();
12026 obj->SetIndexedPropertiesToPixelData(pixel_data, size);
12027 CHECK(obj->HasIndexedPropertiesInPixelData());
12028 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
12029 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
12030 free(pixel_data);
12031 }
12032}
12033
12034
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000012035static v8::Handle<Value> NotHandledIndexedPropertyGetter(
12036 uint32_t index,
12037 const AccessorInfo& info) {
12038 ApiTestFuzzer::Fuzz();
12039 return v8::Handle<Value>();
12040}
12041
12042
12043static v8::Handle<Value> NotHandledIndexedPropertySetter(
12044 uint32_t index,
12045 Local<Value> value,
12046 const AccessorInfo& info) {
12047 ApiTestFuzzer::Fuzz();
12048 return v8::Handle<Value>();
12049}
12050
12051
12052THREADED_TEST(PixelArrayWithInterceptor) {
12053 v8::HandleScope scope;
12054 LocalContext context;
12055 const int kElementCount = 260;
12056 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012057 i::Handle<i::ExternalPixelArray> pixels =
12058 i::Handle<i::ExternalPixelArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012059 FACTORY->NewExternalArray(kElementCount,
12060 v8::kExternalPixelArray,
12061 pixel_data));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000012062 for (int i = 0; i < kElementCount; i++) {
12063 pixels->set(i, i % 256);
12064 }
12065 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12066 templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
12067 NotHandledIndexedPropertySetter);
12068 v8::Handle<v8::Object> obj = templ->NewInstance();
12069 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
12070 context->Global()->Set(v8_str("pixels"), obj);
12071 v8::Handle<v8::Value> result = CompileRun("pixels[1]");
12072 CHECK_EQ(1, result->Int32Value());
12073 result = CompileRun("var sum = 0;"
12074 "for (var i = 0; i < 8; i++) {"
12075 " sum += pixels[i] = pixels[i] = -i;"
12076 "}"
12077 "sum;");
12078 CHECK_EQ(-28, result->Int32Value());
12079 result = CompileRun("pixels.hasOwnProperty('1')");
12080 CHECK(result->BooleanValue());
12081 free(pixel_data);
12082}
12083
12084
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000012085static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
12086 switch (array_type) {
12087 case v8::kExternalByteArray:
12088 case v8::kExternalUnsignedByteArray:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012089 case v8::kExternalPixelArray:
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000012090 return 1;
12091 break;
12092 case v8::kExternalShortArray:
12093 case v8::kExternalUnsignedShortArray:
12094 return 2;
12095 break;
12096 case v8::kExternalIntArray:
12097 case v8::kExternalUnsignedIntArray:
12098 case v8::kExternalFloatArray:
12099 return 4;
12100 break;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000012101 case v8::kExternalDoubleArray:
12102 return 8;
12103 break;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000012104 default:
12105 UNREACHABLE();
12106 return -1;
12107 }
12108 UNREACHABLE();
12109 return -1;
12110}
12111
12112
ager@chromium.org3811b432009-10-28 14:53:37 +000012113template <class ExternalArrayClass, class ElementType>
12114static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
12115 int64_t low,
12116 int64_t high) {
12117 v8::HandleScope scope;
12118 LocalContext context;
12119 const int kElementCount = 40;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000012120 int element_size = ExternalArrayElementSize(array_type);
ager@chromium.org3811b432009-10-28 14:53:37 +000012121 ElementType* array_data =
12122 static_cast<ElementType*>(malloc(kElementCount * element_size));
12123 i::Handle<ExternalArrayClass> array =
12124 i::Handle<ExternalArrayClass>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012125 FACTORY->NewExternalArray(kElementCount, array_type, array_data));
12126 HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
ager@chromium.org3811b432009-10-28 14:53:37 +000012127 for (int i = 0; i < kElementCount; i++) {
12128 array->set(i, static_cast<ElementType>(i));
12129 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012130 HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
ager@chromium.org3811b432009-10-28 14:53:37 +000012131 for (int i = 0; i < kElementCount; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012132 CHECK_EQ(static_cast<int64_t>(i),
12133 static_cast<int64_t>(array->get_scalar(i)));
ager@chromium.org3811b432009-10-28 14:53:37 +000012134 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
12135 }
12136
12137 v8::Handle<v8::Object> obj = v8::Object::New();
12138 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
12139 // Set the elements to be the external array.
12140 obj->SetIndexedPropertiesToExternalArrayData(array_data,
12141 array_type,
12142 kElementCount);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012143 CHECK_EQ(
12144 1, static_cast<int>(jsobj->GetElement(1)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000012145 obj->Set(v8_str("field"), v8::Int32::New(1503));
12146 context->Global()->Set(v8_str("ext_array"), obj);
12147 v8::Handle<v8::Value> result = CompileRun("ext_array.field");
12148 CHECK_EQ(1503, result->Int32Value());
12149 result = CompileRun("ext_array[1]");
12150 CHECK_EQ(1, result->Int32Value());
12151
12152 // Check pass through of assigned smis
12153 result = CompileRun("var sum = 0;"
12154 "for (var i = 0; i < 8; i++) {"
12155 " sum += ext_array[i] = ext_array[i] = -i;"
12156 "}"
12157 "sum;");
12158 CHECK_EQ(-28, result->Int32Value());
12159
12160 // Check assigned smis
12161 result = CompileRun("for (var i = 0; i < 8; i++) {"
12162 " ext_array[i] = i;"
12163 "}"
12164 "var sum = 0;"
12165 "for (var i = 0; i < 8; i++) {"
12166 " sum += ext_array[i];"
12167 "}"
12168 "sum;");
12169 CHECK_EQ(28, result->Int32Value());
12170
12171 // Check assigned smis in reverse order
12172 result = CompileRun("for (var i = 8; --i >= 0; ) {"
12173 " ext_array[i] = i;"
12174 "}"
12175 "var sum = 0;"
12176 "for (var i = 0; i < 8; i++) {"
12177 " sum += ext_array[i];"
12178 "}"
12179 "sum;");
12180 CHECK_EQ(28, result->Int32Value());
12181
12182 // Check pass through of assigned HeapNumbers
12183 result = CompileRun("var sum = 0;"
12184 "for (var i = 0; i < 16; i+=2) {"
12185 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
12186 "}"
12187 "sum;");
12188 CHECK_EQ(-28, result->Int32Value());
12189
12190 // Check assigned HeapNumbers
12191 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
12192 " ext_array[i] = (i * 0.5);"
12193 "}"
12194 "var sum = 0;"
12195 "for (var i = 0; i < 16; i+=2) {"
12196 " sum += ext_array[i];"
12197 "}"
12198 "sum;");
12199 CHECK_EQ(28, result->Int32Value());
12200
12201 // Check assigned HeapNumbers in reverse order
12202 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
12203 " ext_array[i] = (i * 0.5);"
12204 "}"
12205 "var sum = 0;"
12206 "for (var i = 0; i < 16; i+=2) {"
12207 " sum += ext_array[i];"
12208 "}"
12209 "sum;");
12210 CHECK_EQ(28, result->Int32Value());
12211
12212 i::ScopedVector<char> test_buf(1024);
12213
12214 // Check legal boundary conditions.
12215 // The repeated loads and stores ensure the ICs are exercised.
12216 const char* boundary_program =
12217 "var res = 0;"
12218 "for (var i = 0; i < 16; i++) {"
12219 " ext_array[i] = %lld;"
12220 " if (i > 8) {"
12221 " res = ext_array[i];"
12222 " }"
12223 "}"
12224 "res;";
12225 i::OS::SNPrintF(test_buf,
12226 boundary_program,
12227 low);
12228 result = CompileRun(test_buf.start());
12229 CHECK_EQ(low, result->IntegerValue());
12230
12231 i::OS::SNPrintF(test_buf,
12232 boundary_program,
12233 high);
12234 result = CompileRun(test_buf.start());
12235 CHECK_EQ(high, result->IntegerValue());
12236
12237 // Check misprediction of type in IC.
12238 result = CompileRun("var tmp_array = ext_array;"
12239 "var sum = 0;"
12240 "for (var i = 0; i < 8; i++) {"
12241 " tmp_array[i] = i;"
12242 " sum += tmp_array[i];"
12243 " if (i == 4) {"
12244 " tmp_array = {};"
12245 " }"
12246 "}"
12247 "sum;");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012248 HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
ager@chromium.org3811b432009-10-28 14:53:37 +000012249 CHECK_EQ(28, result->Int32Value());
12250
12251 // Make sure out-of-range loads do not throw.
12252 i::OS::SNPrintF(test_buf,
12253 "var caught_exception = false;"
12254 "try {"
12255 " ext_array[%d];"
12256 "} catch (e) {"
12257 " caught_exception = true;"
12258 "}"
12259 "caught_exception;",
12260 kElementCount);
12261 result = CompileRun(test_buf.start());
12262 CHECK_EQ(false, result->BooleanValue());
12263
12264 // Make sure out-of-range stores do not throw.
12265 i::OS::SNPrintF(test_buf,
12266 "var caught_exception = false;"
12267 "try {"
12268 " ext_array[%d] = 1;"
12269 "} catch (e) {"
12270 " caught_exception = true;"
12271 "}"
12272 "caught_exception;",
12273 kElementCount);
12274 result = CompileRun(test_buf.start());
12275 CHECK_EQ(false, result->BooleanValue());
12276
12277 // Check other boundary conditions, values and operations.
12278 result = CompileRun("for (var i = 0; i < 8; i++) {"
12279 " ext_array[7] = undefined;"
12280 "}"
12281 "ext_array[7];");
12282 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012283 CHECK_EQ(
12284 0, static_cast<int>(jsobj->GetElement(7)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000012285
12286 result = CompileRun("for (var i = 0; i < 8; i++) {"
12287 " ext_array[6] = '2.3';"
12288 "}"
12289 "ext_array[6];");
12290 CHECK_EQ(2, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012291 CHECK_EQ(
12292 2, static_cast<int>(jsobj->GetElement(6)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000012293
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000012294 if (array_type != v8::kExternalFloatArray &&
12295 array_type != v8::kExternalDoubleArray) {
ager@chromium.org3811b432009-10-28 14:53:37 +000012296 // Though the specification doesn't state it, be explicit about
12297 // converting NaNs and +/-Infinity to zero.
12298 result = CompileRun("for (var i = 0; i < 8; i++) {"
12299 " ext_array[i] = 5;"
12300 "}"
12301 "for (var i = 0; i < 8; i++) {"
12302 " ext_array[i] = NaN;"
12303 "}"
12304 "ext_array[5];");
12305 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012306 CHECK_EQ(0,
12307 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
ager@chromium.org3811b432009-10-28 14:53:37 +000012308
12309 result = CompileRun("for (var i = 0; i < 8; i++) {"
12310 " ext_array[i] = 5;"
12311 "}"
12312 "for (var i = 0; i < 8; i++) {"
12313 " ext_array[i] = Infinity;"
12314 "}"
12315 "ext_array[5];");
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012316 int expected_value =
12317 (array_type == v8::kExternalPixelArray) ? 255 : 0;
12318 CHECK_EQ(expected_value, result->Int32Value());
12319 CHECK_EQ(expected_value,
lrn@chromium.org303ada72010-10-27 09:33:13 +000012320 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
ager@chromium.org3811b432009-10-28 14:53:37 +000012321
12322 result = CompileRun("for (var i = 0; i < 8; i++) {"
12323 " ext_array[i] = 5;"
12324 "}"
12325 "for (var i = 0; i < 8; i++) {"
12326 " ext_array[i] = -Infinity;"
12327 "}"
12328 "ext_array[5];");
12329 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012330 CHECK_EQ(0,
12331 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000012332
12333 // Check truncation behavior of integral arrays.
12334 const char* unsigned_data =
12335 "var source_data = [0.6, 10.6];"
12336 "var expected_results = [0, 10];";
12337 const char* signed_data =
12338 "var source_data = [0.6, 10.6, -0.6, -10.6];"
12339 "var expected_results = [0, 10, 0, -10];";
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012340 const char* pixel_data =
12341 "var source_data = [0.6, 10.6];"
12342 "var expected_results = [1, 11];";
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000012343 bool is_unsigned =
12344 (array_type == v8::kExternalUnsignedByteArray ||
12345 array_type == v8::kExternalUnsignedShortArray ||
12346 array_type == v8::kExternalUnsignedIntArray);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012347 bool is_pixel_data = array_type == v8::kExternalPixelArray;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000012348
12349 i::OS::SNPrintF(test_buf,
12350 "%s"
12351 "var all_passed = true;"
12352 "for (var i = 0; i < source_data.length; i++) {"
12353 " for (var j = 0; j < 8; j++) {"
12354 " ext_array[j] = source_data[i];"
12355 " }"
12356 " all_passed = all_passed &&"
12357 " (ext_array[5] == expected_results[i]);"
12358 "}"
12359 "all_passed;",
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012360 (is_unsigned ?
12361 unsigned_data :
12362 (is_pixel_data ? pixel_data : signed_data)));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000012363 result = CompileRun(test_buf.start());
12364 CHECK_EQ(true, result->BooleanValue());
ager@chromium.org3811b432009-10-28 14:53:37 +000012365 }
12366
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000012367 for (int i = 0; i < kElementCount; i++) {
12368 array->set(i, static_cast<ElementType>(i));
12369 }
12370 // Test complex assignments
12371 result = CompileRun("function ee_op_test_complex_func(sum) {"
12372 " for (var i = 0; i < 40; ++i) {"
12373 " sum += (ext_array[i] += 1);"
12374 " sum += (ext_array[i] -= 1);"
12375 " } "
12376 " return sum;"
12377 "}"
12378 "sum=0;"
12379 "for (var i=0;i<10000;++i) {"
12380 " sum=ee_op_test_complex_func(sum);"
12381 "}"
12382 "sum;");
12383 CHECK_EQ(16000000, result->Int32Value());
12384
12385 // Test count operations
12386 result = CompileRun("function ee_op_test_count_func(sum) {"
12387 " for (var i = 0; i < 40; ++i) {"
12388 " sum += (++ext_array[i]);"
12389 " sum += (--ext_array[i]);"
12390 " } "
12391 " return sum;"
12392 "}"
12393 "sum=0;"
12394 "for (var i=0;i<10000;++i) {"
12395 " sum=ee_op_test_count_func(sum);"
12396 "}"
12397 "sum;");
12398 CHECK_EQ(16000000, result->Int32Value());
12399
ager@chromium.org3811b432009-10-28 14:53:37 +000012400 result = CompileRun("ext_array[3] = 33;"
12401 "delete ext_array[3];"
12402 "ext_array[3];");
12403 CHECK_EQ(33, result->Int32Value());
12404
12405 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
12406 "ext_array[2] = 12; ext_array[3] = 13;"
12407 "ext_array.__defineGetter__('2',"
12408 "function() { return 120; });"
12409 "ext_array[2];");
12410 CHECK_EQ(12, result->Int32Value());
12411
12412 result = CompileRun("var js_array = new Array(40);"
12413 "js_array[0] = 77;"
12414 "js_array;");
12415 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
12416
12417 result = CompileRun("ext_array[1] = 23;"
12418 "ext_array.__proto__ = [];"
12419 "js_array.__proto__ = ext_array;"
12420 "js_array.concat(ext_array);");
12421 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
12422 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
12423
12424 result = CompileRun("ext_array[1] = 23;");
12425 CHECK_EQ(23, result->Int32Value());
12426
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012427 // Test more complex manipulations which cause eax to contain values
12428 // that won't be completely overwritten by loads from the arrays.
12429 // This catches bugs in the instructions used for the KeyedLoadIC
12430 // for byte and word types.
12431 {
12432 const int kXSize = 300;
12433 const int kYSize = 300;
12434 const int kLargeElementCount = kXSize * kYSize * 4;
12435 ElementType* large_array_data =
12436 static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
12437 i::Handle<ExternalArrayClass> large_array =
12438 i::Handle<ExternalArrayClass>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012439 FACTORY->NewExternalArray(kLargeElementCount,
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012440 array_type,
12441 array_data));
12442 v8::Handle<v8::Object> large_obj = v8::Object::New();
12443 // Set the elements to be the external array.
12444 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
12445 array_type,
12446 kLargeElementCount);
12447 context->Global()->Set(v8_str("large_array"), large_obj);
12448 // Initialize contents of a few rows.
12449 for (int x = 0; x < 300; x++) {
12450 int row = 0;
12451 int offset = row * 300 * 4;
12452 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
12453 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
12454 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
12455 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
12456 row = 150;
12457 offset = row * 300 * 4;
12458 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
12459 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
12460 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
12461 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
12462 row = 298;
12463 offset = row * 300 * 4;
12464 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
12465 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
12466 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
12467 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
12468 }
12469 // The goal of the code below is to make "offset" large enough
12470 // that the computation of the index (which goes into eax) has
12471 // high bits set which will not be overwritten by a byte or short
12472 // load.
12473 result = CompileRun("var failed = false;"
12474 "var offset = 0;"
12475 "for (var i = 0; i < 300; i++) {"
12476 " if (large_array[4 * i] != 127 ||"
12477 " large_array[4 * i + 1] != 0 ||"
12478 " large_array[4 * i + 2] != 0 ||"
12479 " large_array[4 * i + 3] != 127) {"
12480 " failed = true;"
12481 " }"
12482 "}"
12483 "offset = 150 * 300 * 4;"
12484 "for (var i = 0; i < 300; i++) {"
12485 " if (large_array[offset + 4 * i] != 127 ||"
12486 " large_array[offset + 4 * i + 1] != 0 ||"
12487 " large_array[offset + 4 * i + 2] != 0 ||"
12488 " large_array[offset + 4 * i + 3] != 127) {"
12489 " failed = true;"
12490 " }"
12491 "}"
12492 "offset = 298 * 300 * 4;"
12493 "for (var i = 0; i < 300; i++) {"
12494 " if (large_array[offset + 4 * i] != 127 ||"
12495 " large_array[offset + 4 * i + 1] != 0 ||"
12496 " large_array[offset + 4 * i + 2] != 0 ||"
12497 " large_array[offset + 4 * i + 3] != 127) {"
12498 " failed = true;"
12499 " }"
12500 "}"
12501 "!failed;");
12502 CHECK_EQ(true, result->BooleanValue());
12503 free(large_array_data);
12504 }
12505
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012506 // The "" property descriptor is overloaded to store information about
12507 // the external array. Ensure that setting and accessing the "" property
12508 // works (it should overwrite the information cached about the external
12509 // array in the DescriptorArray) in various situations.
12510 result = CompileRun("ext_array[''] = 23; ext_array['']");
12511 CHECK_EQ(23, result->Int32Value());
12512
12513 // Property "" set after the external array is associated with the object.
12514 {
12515 v8::Handle<v8::Object> obj2 = v8::Object::New();
12516 obj2->Set(v8_str("ee_test_field"), v8::Int32::New(256));
12517 obj2->Set(v8_str(""), v8::Int32::New(1503));
12518 // Set the elements to be the external array.
12519 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
12520 array_type,
12521 kElementCount);
12522 context->Global()->Set(v8_str("ext_array"), obj2);
12523 result = CompileRun("ext_array['']");
12524 CHECK_EQ(1503, result->Int32Value());
12525 }
12526
12527 // Property "" set after the external array is associated with the object.
12528 {
12529 v8::Handle<v8::Object> obj2 = v8::Object::New();
12530 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
12531 // Set the elements to be the external array.
12532 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
12533 array_type,
12534 kElementCount);
12535 obj2->Set(v8_str(""), v8::Int32::New(1503));
12536 context->Global()->Set(v8_str("ext_array"), obj2);
12537 result = CompileRun("ext_array['']");
12538 CHECK_EQ(1503, result->Int32Value());
12539 }
12540
12541 // Should reuse the map from previous test.
12542 {
12543 v8::Handle<v8::Object> obj2 = v8::Object::New();
12544 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
12545 // Set the elements to be the external array. Should re-use the map
12546 // from previous test.
12547 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
12548 array_type,
12549 kElementCount);
12550 context->Global()->Set(v8_str("ext_array"), obj2);
12551 result = CompileRun("ext_array['']");
12552 }
12553
12554 // Property "" is a constant function that shouldn't not be interfered with
12555 // when an external array is set.
12556 {
12557 v8::Handle<v8::Object> obj2 = v8::Object::New();
12558 // Start
12559 obj2->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
12560
12561 // Add a constant function to an object.
12562 context->Global()->Set(v8_str("ext_array"), obj2);
12563 result = CompileRun("ext_array[''] = function() {return 1503;};"
12564 "ext_array['']();");
12565
12566 // Add an external array transition to the same map that
12567 // has the constant transition.
12568 v8::Handle<v8::Object> obj3 = v8::Object::New();
12569 obj3->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
12570 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
12571 array_type,
12572 kElementCount);
12573 context->Global()->Set(v8_str("ext_array"), obj3);
12574 }
12575
12576 // If a external array transition is in the map, it should get clobbered
12577 // by a constant function.
12578 {
12579 // Add an external array transition.
12580 v8::Handle<v8::Object> obj3 = v8::Object::New();
12581 obj3->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
12582 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
12583 array_type,
12584 kElementCount);
12585
12586 // Add a constant function to the same map that just got an external array
12587 // transition.
12588 v8::Handle<v8::Object> obj2 = v8::Object::New();
12589 obj2->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
12590 context->Global()->Set(v8_str("ext_array"), obj2);
12591 result = CompileRun("ext_array[''] = function() {return 1503;};"
12592 "ext_array['']();");
12593 }
12594
ager@chromium.org3811b432009-10-28 14:53:37 +000012595 free(array_data);
12596}
12597
12598
12599THREADED_TEST(ExternalByteArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000012600 ExternalArrayTestHelper<i::ExternalByteArray, int8_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000012601 v8::kExternalByteArray,
12602 -128,
12603 127);
12604}
12605
12606
12607THREADED_TEST(ExternalUnsignedByteArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000012608 ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000012609 v8::kExternalUnsignedByteArray,
12610 0,
12611 255);
12612}
12613
12614
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012615THREADED_TEST(ExternalPixelArray) {
12616 ExternalArrayTestHelper<i::ExternalPixelArray, uint8_t>(
12617 v8::kExternalPixelArray,
12618 0,
12619 255);
12620}
12621
12622
ager@chromium.org3811b432009-10-28 14:53:37 +000012623THREADED_TEST(ExternalShortArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000012624 ExternalArrayTestHelper<i::ExternalShortArray, int16_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000012625 v8::kExternalShortArray,
12626 -32768,
12627 32767);
12628}
12629
12630
12631THREADED_TEST(ExternalUnsignedShortArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000012632 ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000012633 v8::kExternalUnsignedShortArray,
12634 0,
12635 65535);
12636}
12637
12638
12639THREADED_TEST(ExternalIntArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000012640 ExternalArrayTestHelper<i::ExternalIntArray, int32_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000012641 v8::kExternalIntArray,
12642 INT_MIN, // -2147483648
12643 INT_MAX); // 2147483647
12644}
12645
12646
12647THREADED_TEST(ExternalUnsignedIntArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000012648 ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000012649 v8::kExternalUnsignedIntArray,
12650 0,
12651 UINT_MAX); // 4294967295
12652}
12653
12654
12655THREADED_TEST(ExternalFloatArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000012656 ExternalArrayTestHelper<i::ExternalFloatArray, float>(
ager@chromium.org3811b432009-10-28 14:53:37 +000012657 v8::kExternalFloatArray,
12658 -500,
12659 500);
12660}
12661
12662
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000012663THREADED_TEST(ExternalDoubleArray) {
12664 ExternalArrayTestHelper<i::ExternalDoubleArray, double>(
12665 v8::kExternalDoubleArray,
12666 -500,
12667 500);
12668}
12669
12670
ager@chromium.org3811b432009-10-28 14:53:37 +000012671THREADED_TEST(ExternalArrays) {
12672 TestExternalByteArray();
12673 TestExternalUnsignedByteArray();
12674 TestExternalShortArray();
12675 TestExternalUnsignedShortArray();
12676 TestExternalIntArray();
12677 TestExternalUnsignedIntArray();
12678 TestExternalFloatArray();
12679}
12680
12681
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000012682void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
12683 v8::HandleScope scope;
12684 LocalContext context;
12685 for (int size = 0; size < 100; size += 10) {
12686 int element_size = ExternalArrayElementSize(array_type);
12687 void* external_data = malloc(size * element_size);
12688 v8::Handle<v8::Object> obj = v8::Object::New();
12689 obj->SetIndexedPropertiesToExternalArrayData(
12690 external_data, array_type, size);
12691 CHECK(obj->HasIndexedPropertiesInExternalArrayData());
12692 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
12693 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
12694 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
12695 free(external_data);
12696 }
12697}
12698
12699
12700THREADED_TEST(ExternalArrayInfo) {
12701 ExternalArrayInfoTestHelper(v8::kExternalByteArray);
12702 ExternalArrayInfoTestHelper(v8::kExternalUnsignedByteArray);
12703 ExternalArrayInfoTestHelper(v8::kExternalShortArray);
12704 ExternalArrayInfoTestHelper(v8::kExternalUnsignedShortArray);
12705 ExternalArrayInfoTestHelper(v8::kExternalIntArray);
12706 ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray);
12707 ExternalArrayInfoTestHelper(v8::kExternalFloatArray);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000012708 ExternalArrayInfoTestHelper(v8::kExternalDoubleArray);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012709 ExternalArrayInfoTestHelper(v8::kExternalPixelArray);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000012710}
12711
12712
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000012713THREADED_TEST(ScriptContextDependence) {
12714 v8::HandleScope scope;
12715 LocalContext c1;
12716 const char *source = "foo";
12717 v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
12718 v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
12719 c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
12720 CHECK_EQ(dep->Run()->Int32Value(), 100);
12721 CHECK_EQ(indep->Run()->Int32Value(), 100);
12722 LocalContext c2;
12723 c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
12724 CHECK_EQ(dep->Run()->Int32Value(), 100);
12725 CHECK_EQ(indep->Run()->Int32Value(), 101);
12726}
12727
ager@chromium.org96c75b52009-08-26 09:13:16 +000012728
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000012729THREADED_TEST(StackTrace) {
12730 v8::HandleScope scope;
12731 LocalContext context;
12732 v8::TryCatch try_catch;
12733 const char *source = "function foo() { FAIL.FAIL; }; foo();";
12734 v8::Handle<v8::String> src = v8::String::New(source);
12735 v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
12736 v8::Script::New(src, origin)->Run();
12737 CHECK(try_catch.HasCaught());
12738 v8::String::Utf8Value stack(try_catch.StackTrace());
12739 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
12740}
ager@chromium.org96c75b52009-08-26 09:13:16 +000012741
12742
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000012743// Checks that a StackFrame has certain expected values.
12744void checkStackFrame(const char* expected_script_name,
12745 const char* expected_func_name, int expected_line_number,
12746 int expected_column, bool is_eval, bool is_constructor,
12747 v8::Handle<v8::StackFrame> frame) {
12748 v8::HandleScope scope;
12749 v8::String::Utf8Value func_name(frame->GetFunctionName());
12750 v8::String::Utf8Value script_name(frame->GetScriptName());
12751 if (*script_name == NULL) {
12752 // The situation where there is no associated script, like for evals.
12753 CHECK(expected_script_name == NULL);
12754 } else {
12755 CHECK(strstr(*script_name, expected_script_name) != NULL);
12756 }
12757 CHECK(strstr(*func_name, expected_func_name) != NULL);
12758 CHECK_EQ(expected_line_number, frame->GetLineNumber());
12759 CHECK_EQ(expected_column, frame->GetColumn());
12760 CHECK_EQ(is_eval, frame->IsEval());
12761 CHECK_EQ(is_constructor, frame->IsConstructor());
12762}
12763
12764
12765v8::Handle<Value> AnalyzeStackInNativeCode(const v8::Arguments& args) {
12766 v8::HandleScope scope;
12767 const char* origin = "capture-stack-trace-test";
12768 const int kOverviewTest = 1;
12769 const int kDetailedTest = 2;
12770
12771 ASSERT(args.Length() == 1);
12772
12773 int testGroup = args[0]->Int32Value();
12774 if (testGroup == kOverviewTest) {
12775 v8::Handle<v8::StackTrace> stackTrace =
12776 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
12777 CHECK_EQ(4, stackTrace->GetFrameCount());
12778 checkStackFrame(origin, "bar", 2, 10, false, false,
12779 stackTrace->GetFrame(0));
12780 checkStackFrame(origin, "foo", 6, 3, false, false,
12781 stackTrace->GetFrame(1));
whesse@chromium.org030d38e2011-07-13 13:23:34 +000012782 // This is the source string inside the eval which has the call to foo.
12783 checkStackFrame(NULL, "", 1, 5, false, false,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000012784 stackTrace->GetFrame(2));
whesse@chromium.org030d38e2011-07-13 13:23:34 +000012785 // The last frame is an anonymous function which has the initial eval call.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000012786 checkStackFrame(origin, "", 8, 7, false, false,
12787 stackTrace->GetFrame(3));
12788
12789 CHECK(stackTrace->AsArray()->IsArray());
12790 } else if (testGroup == kDetailedTest) {
12791 v8::Handle<v8::StackTrace> stackTrace =
12792 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
12793 CHECK_EQ(4, stackTrace->GetFrameCount());
12794 checkStackFrame(origin, "bat", 4, 22, false, false,
12795 stackTrace->GetFrame(0));
12796 checkStackFrame(origin, "baz", 8, 3, false, true,
12797 stackTrace->GetFrame(1));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000012798#ifdef ENABLE_DEBUGGER_SUPPORT
12799 bool is_eval = true;
12800#else // ENABLE_DEBUGGER_SUPPORT
12801 bool is_eval = false;
12802#endif // ENABLE_DEBUGGER_SUPPORT
12803
whesse@chromium.org030d38e2011-07-13 13:23:34 +000012804 // This is the source string inside the eval which has the call to baz.
12805 checkStackFrame(NULL, "", 1, 5, is_eval, false,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000012806 stackTrace->GetFrame(2));
whesse@chromium.org030d38e2011-07-13 13:23:34 +000012807 // The last frame is an anonymous function which has the initial eval call.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000012808 checkStackFrame(origin, "", 10, 1, false, false,
12809 stackTrace->GetFrame(3));
12810
12811 CHECK(stackTrace->AsArray()->IsArray());
12812 }
12813 return v8::Undefined();
12814}
12815
12816
12817// Tests the C++ StackTrace API.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012818// TODO(3074796): Reenable this as a THREADED_TEST once it passes.
12819// THREADED_TEST(CaptureStackTrace) {
12820TEST(CaptureStackTrace) {
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000012821 v8::HandleScope scope;
12822 v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
12823 Local<ObjectTemplate> templ = ObjectTemplate::New();
12824 templ->Set(v8_str("AnalyzeStackInNativeCode"),
12825 v8::FunctionTemplate::New(AnalyzeStackInNativeCode));
12826 LocalContext context(0, templ);
12827
12828 // Test getting OVERVIEW information. Should ignore information that is not
12829 // script name, function name, line number, and column offset.
12830 const char *overview_source =
12831 "function bar() {\n"
12832 " var y; AnalyzeStackInNativeCode(1);\n"
12833 "}\n"
12834 "function foo() {\n"
12835 "\n"
12836 " bar();\n"
12837 "}\n"
12838 "var x;eval('new foo();');";
12839 v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
12840 v8::Handle<Value> overview_result =
12841 v8::Script::New(overview_src, origin)->Run();
12842 ASSERT(!overview_result.IsEmpty());
12843 ASSERT(overview_result->IsObject());
12844
12845 // Test getting DETAILED information.
12846 const char *detailed_source =
12847 "function bat() {AnalyzeStackInNativeCode(2);\n"
12848 "}\n"
12849 "\n"
12850 "function baz() {\n"
12851 " bat();\n"
12852 "}\n"
12853 "eval('new baz();');";
12854 v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
12855 // Make the script using a non-zero line and column offset.
12856 v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
12857 v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
12858 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
12859 v8::Handle<v8::Script> detailed_script(
12860 v8::Script::New(detailed_src, &detailed_origin));
12861 v8::Handle<Value> detailed_result = detailed_script->Run();
12862 ASSERT(!detailed_result.IsEmpty());
12863 ASSERT(detailed_result->IsObject());
12864}
12865
12866
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012867static void StackTraceForUncaughtExceptionListener(
12868 v8::Handle<v8::Message> message,
12869 v8::Handle<Value>) {
12870 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
12871 CHECK_EQ(2, stack_trace->GetFrameCount());
12872 checkStackFrame("origin", "foo", 2, 3, false, false,
12873 stack_trace->GetFrame(0));
12874 checkStackFrame("origin", "bar", 5, 3, false, false,
12875 stack_trace->GetFrame(1));
12876}
12877
12878TEST(CaptureStackTraceForUncaughtException) {
12879 report_count = 0;
12880 v8::HandleScope scope;
12881 LocalContext env;
12882 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
12883 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
12884
12885 Script::Compile(v8_str("function foo() {\n"
12886 " throw 1;\n"
12887 "};\n"
12888 "function bar() {\n"
12889 " foo();\n"
12890 "};"),
12891 v8_str("origin"))->Run();
12892 v8::Local<v8::Object> global = env->Global();
12893 Local<Value> trouble = global->Get(v8_str("bar"));
12894 CHECK(trouble->IsFunction());
12895 Function::Cast(*trouble)->Call(global, 0, NULL);
12896 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
12897 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
12898}
12899
12900
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000012901TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
12902 v8::HandleScope scope;
12903 LocalContext env;
12904 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
12905 1024,
12906 v8::StackTrace::kDetailed);
12907
12908 CompileRun(
12909 "var setters = ['column', 'lineNumber', 'scriptName',\n"
12910 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
12911 " 'isConstructor'];\n"
12912 "for (var i = 0; i < setters.length; i++) {\n"
12913 " var prop = setters[i];\n"
12914 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
12915 "}\n");
12916 CompileRun("throw 'exception';");
12917 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
12918}
12919
12920
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000012921v8::Handle<Value> AnalyzeStackOfEvalWithSourceURL(const v8::Arguments& args) {
12922 v8::HandleScope scope;
12923 v8::Handle<v8::StackTrace> stackTrace =
12924 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
12925 CHECK_EQ(5, stackTrace->GetFrameCount());
12926 v8::Handle<v8::String> url = v8_str("eval_url");
12927 for (int i = 0; i < 3; i++) {
12928 v8::Handle<v8::String> name =
12929 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
12930 CHECK(!name.IsEmpty());
12931 CHECK_EQ(url, name);
12932 }
12933 return v8::Undefined();
12934}
12935
12936
12937TEST(SourceURLInStackTrace) {
12938 v8::HandleScope scope;
12939 Local<ObjectTemplate> templ = ObjectTemplate::New();
12940 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
12941 v8::FunctionTemplate::New(AnalyzeStackOfEvalWithSourceURL));
12942 LocalContext context(0, templ);
12943
12944 const char *source =
12945 "function outer() {\n"
12946 "function bar() {\n"
12947 " AnalyzeStackOfEvalWithSourceURL();\n"
12948 "}\n"
12949 "function foo() {\n"
12950 "\n"
12951 " bar();\n"
12952 "}\n"
12953 "foo();\n"
12954 "}\n"
12955 "eval('(' + outer +')()//@ sourceURL=eval_url');";
12956 CHECK(CompileRun(source)->IsUndefined());
12957}
12958
12959
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000012960// Test that idle notification can be handled and eventually returns true.
ager@chromium.org96c75b52009-08-26 09:13:16 +000012961THREADED_TEST(IdleNotification) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000012962 bool rv = false;
12963 for (int i = 0; i < 100; i++) {
12964 rv = v8::V8::IdleNotification();
12965 if (rv)
12966 break;
12967 }
12968 CHECK(rv == true);
12969}
12970
12971
12972static uint32_t* stack_limit;
12973
12974static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012975 stack_limit = reinterpret_cast<uint32_t*>(
12976 i::Isolate::Current()->stack_guard()->real_climit());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000012977 return v8::Undefined();
12978}
12979
12980
12981// Uses the address of a local variable to determine the stack top now.
12982// Given a size, returns an address that is that far from the current
12983// top of stack.
12984static uint32_t* ComputeStackLimit(uint32_t size) {
12985 uint32_t* answer = &size - (size / sizeof(size));
12986 // If the size is very large and the stack is very near the bottom of
12987 // memory then the calculation above may wrap around and give an address
12988 // that is above the (downwards-growing) stack. In that case we return
12989 // a very low address.
12990 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
12991 return answer;
12992}
12993
12994
12995TEST(SetResourceConstraints) {
12996 static const int K = 1024;
12997 uint32_t* set_limit = ComputeStackLimit(128 * K);
12998
12999 // Set stack limit.
13000 v8::ResourceConstraints constraints;
13001 constraints.set_stack_limit(set_limit);
13002 CHECK(v8::SetResourceConstraints(&constraints));
13003
13004 // Execute a script.
13005 v8::HandleScope scope;
13006 LocalContext env;
13007 Local<v8::FunctionTemplate> fun_templ =
13008 v8::FunctionTemplate::New(GetStackLimitCallback);
13009 Local<Function> fun = fun_templ->GetFunction();
13010 env->Global()->Set(v8_str("get_stack_limit"), fun);
13011 CompileRun("get_stack_limit();");
13012
13013 CHECK(stack_limit == set_limit);
13014}
13015
13016
13017TEST(SetResourceConstraintsInThread) {
13018 uint32_t* set_limit;
13019 {
13020 v8::Locker locker;
13021 static const int K = 1024;
13022 set_limit = ComputeStackLimit(128 * K);
13023
13024 // Set stack limit.
13025 v8::ResourceConstraints constraints;
13026 constraints.set_stack_limit(set_limit);
13027 CHECK(v8::SetResourceConstraints(&constraints));
13028
13029 // Execute a script.
13030 v8::HandleScope scope;
13031 LocalContext env;
13032 Local<v8::FunctionTemplate> fun_templ =
13033 v8::FunctionTemplate::New(GetStackLimitCallback);
13034 Local<Function> fun = fun_templ->GetFunction();
13035 env->Global()->Set(v8_str("get_stack_limit"), fun);
13036 CompileRun("get_stack_limit();");
13037
13038 CHECK(stack_limit == set_limit);
13039 }
13040 {
13041 v8::Locker locker;
13042 CHECK(stack_limit == set_limit);
13043 }
ager@chromium.org96c75b52009-08-26 09:13:16 +000013044}
ager@chromium.org3811b432009-10-28 14:53:37 +000013045
13046
13047THREADED_TEST(GetHeapStatistics) {
13048 v8::HandleScope scope;
13049 LocalContext c1;
13050 v8::HeapStatistics heap_statistics;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000013051 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
13052 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
ager@chromium.org3811b432009-10-28 14:53:37 +000013053 v8::V8::GetHeapStatistics(&heap_statistics);
ager@chromium.orgc4c92722009-11-18 14:12:51 +000013054 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
13055 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
ager@chromium.org3811b432009-10-28 14:53:37 +000013056}
13057
13058
13059static double DoubleFromBits(uint64_t value) {
13060 double target;
ager@chromium.org3811b432009-10-28 14:53:37 +000013061 memcpy(&target, &value, sizeof(target));
ager@chromium.org3811b432009-10-28 14:53:37 +000013062 return target;
13063}
13064
13065
13066static uint64_t DoubleToBits(double value) {
13067 uint64_t target;
ager@chromium.org3811b432009-10-28 14:53:37 +000013068 memcpy(&target, &value, sizeof(target));
ager@chromium.org3811b432009-10-28 14:53:37 +000013069 return target;
13070}
13071
13072
13073static double DoubleToDateTime(double input) {
13074 double date_limit = 864e13;
13075 if (IsNaN(input) || input < -date_limit || input > date_limit) {
13076 return i::OS::nan_value();
13077 }
13078 return (input < 0) ? -(floor(-input)) : floor(input);
13079}
13080
13081// We don't have a consistent way to write 64-bit constants syntactically, so we
13082// split them into two 32-bit constants and combine them programmatically.
13083static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
13084 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
13085}
13086
13087
13088THREADED_TEST(QuietSignalingNaNs) {
13089 v8::HandleScope scope;
13090 LocalContext context;
13091 v8::TryCatch try_catch;
13092
13093 // Special double values.
13094 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
13095 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
13096 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
13097 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
13098 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
13099 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
13100 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
13101
13102 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
13103 // on either side of the epoch.
13104 double date_limit = 864e13;
13105
13106 double test_values[] = {
13107 snan,
13108 qnan,
13109 infinity,
13110 max_normal,
13111 date_limit + 1,
13112 date_limit,
13113 min_normal,
13114 max_denormal,
13115 min_denormal,
13116 0,
13117 -0,
13118 -min_denormal,
13119 -max_denormal,
13120 -min_normal,
13121 -date_limit,
13122 -date_limit - 1,
13123 -max_normal,
13124 -infinity,
13125 -qnan,
13126 -snan
13127 };
13128 int num_test_values = 20;
13129
13130 for (int i = 0; i < num_test_values; i++) {
13131 double test_value = test_values[i];
13132
13133 // Check that Number::New preserves non-NaNs and quiets SNaNs.
13134 v8::Handle<v8::Value> number = v8::Number::New(test_value);
13135 double stored_number = number->NumberValue();
13136 if (!IsNaN(test_value)) {
13137 CHECK_EQ(test_value, stored_number);
13138 } else {
13139 uint64_t stored_bits = DoubleToBits(stored_number);
13140 // Check if quiet nan (bits 51..62 all set).
13141 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
13142 }
13143
13144 // Check that Date::New preserves non-NaNs in the date range and
13145 // quiets SNaNs.
13146 v8::Handle<v8::Value> date = v8::Date::New(test_value);
13147 double expected_stored_date = DoubleToDateTime(test_value);
13148 double stored_date = date->NumberValue();
13149 if (!IsNaN(expected_stored_date)) {
13150 CHECK_EQ(expected_stored_date, stored_date);
13151 } else {
13152 uint64_t stored_bits = DoubleToBits(stored_date);
13153 // Check if quiet nan (bits 51..62 all set).
13154 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
13155 }
13156 }
13157}
christian.plesner.hansen@gmail.comb9ce6372009-11-03 11:38:18 +000013158
13159
13160static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
13161 v8::HandleScope scope;
13162 v8::TryCatch tc;
13163 v8::Handle<v8::String> str = args[0]->ToString();
13164 if (tc.HasCaught())
13165 return tc.ReThrow();
13166 return v8::Undefined();
13167}
13168
13169
13170// Test that an exception can be propagated down through a spaghetti
13171// stack using ReThrow.
13172THREADED_TEST(SpaghettiStackReThrow) {
13173 v8::HandleScope scope;
13174 LocalContext context;
13175 context->Global()->Set(
13176 v8::String::New("s"),
13177 v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
13178 v8::TryCatch try_catch;
13179 CompileRun(
13180 "var i = 0;"
13181 "var o = {"
13182 " toString: function () {"
13183 " if (i == 10) {"
13184 " throw 'Hey!';"
13185 " } else {"
13186 " i++;"
13187 " return s(o);"
13188 " }"
13189 " }"
13190 "};"
13191 "s(o);");
13192 CHECK(try_catch.HasCaught());
13193 v8::String::Utf8Value value(try_catch.Exception());
13194 CHECK_EQ(0, strcmp(*value, "Hey!"));
13195}
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013196
13197
sgjesse@chromium.org98180592009-12-02 08:17:28 +000013198TEST(Regress528) {
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013199 v8::V8::Initialize();
13200
13201 v8::HandleScope scope;
13202 v8::Persistent<Context> context;
ager@chromium.org60121232009-12-03 11:25:37 +000013203 v8::Persistent<Context> other_context;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013204 int gc_count;
13205
ager@chromium.org60121232009-12-03 11:25:37 +000013206 // Create a context used to keep the code from aging in the compilation
13207 // cache.
13208 other_context = Context::New();
13209
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013210 // Context-dependent context data creates reference from the compilation
13211 // cache to the global object.
ager@chromium.org60121232009-12-03 11:25:37 +000013212 const char* source_simple = "1";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013213 context = Context::New();
13214 {
13215 v8::HandleScope scope;
13216
13217 context->Enter();
13218 Local<v8::String> obj = v8::String::New("");
13219 context->SetData(obj);
ager@chromium.org60121232009-12-03 11:25:37 +000013220 CompileRun(source_simple);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013221 context->Exit();
13222 }
13223 context.Dispose();
13224 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000013225 other_context->Enter();
13226 CompileRun(source_simple);
13227 other_context->Exit();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013228 HEAP->CollectAllGarbage(false);
ager@chromium.org60121232009-12-03 11:25:37 +000013229 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013230 }
ager@chromium.org60121232009-12-03 11:25:37 +000013231 CHECK_GE(2, gc_count);
13232 CHECK_EQ(1, GetGlobalObjectsCount());
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013233
13234 // Eval in a function creates reference from the compilation cache to the
13235 // global object.
ager@chromium.org60121232009-12-03 11:25:37 +000013236 const char* source_eval = "function f(){eval('1')}; f()";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013237 context = Context::New();
13238 {
13239 v8::HandleScope scope;
13240
13241 context->Enter();
ager@chromium.org60121232009-12-03 11:25:37 +000013242 CompileRun(source_eval);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013243 context->Exit();
13244 }
13245 context.Dispose();
13246 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000013247 other_context->Enter();
13248 CompileRun(source_eval);
13249 other_context->Exit();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013250 HEAP->CollectAllGarbage(false);
ager@chromium.org60121232009-12-03 11:25:37 +000013251 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013252 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013253 CHECK_GE(2, gc_count);
sgjesse@chromium.org98180592009-12-02 08:17:28 +000013254 CHECK_EQ(1, GetGlobalObjectsCount());
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013255
13256 // Looking up the line number for an exception creates reference from the
13257 // compilation cache to the global object.
ager@chromium.org60121232009-12-03 11:25:37 +000013258 const char* source_exception = "function f(){throw 1;} f()";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013259 context = Context::New();
13260 {
13261 v8::HandleScope scope;
13262
13263 context->Enter();
13264 v8::TryCatch try_catch;
ager@chromium.org60121232009-12-03 11:25:37 +000013265 CompileRun(source_exception);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013266 CHECK(try_catch.HasCaught());
13267 v8::Handle<v8::Message> message = try_catch.Message();
13268 CHECK(!message.IsEmpty());
13269 CHECK_EQ(1, message->GetLineNumber());
13270 context->Exit();
13271 }
13272 context.Dispose();
13273 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000013274 other_context->Enter();
13275 CompileRun(source_exception);
13276 other_context->Exit();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013277 HEAP->CollectAllGarbage(false);
ager@chromium.org60121232009-12-03 11:25:37 +000013278 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013279 }
ager@chromium.org60121232009-12-03 11:25:37 +000013280 CHECK_GE(2, gc_count);
13281 CHECK_EQ(1, GetGlobalObjectsCount());
13282
13283 other_context.Dispose();
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013284}
ager@chromium.org5c838252010-02-19 08:53:10 +000013285
13286
13287THREADED_TEST(ScriptOrigin) {
13288 v8::HandleScope scope;
13289 LocalContext env;
13290 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
13291 v8::Handle<v8::String> script = v8::String::New(
13292 "function f() {}\n\nfunction g() {}");
13293 v8::Script::Compile(script, &origin)->Run();
13294 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
13295 env->Global()->Get(v8::String::New("f")));
13296 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
13297 env->Global()->Get(v8::String::New("g")));
13298
13299 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
13300 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
13301 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
13302
13303 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
13304 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
13305 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
13306}
13307
13308
13309THREADED_TEST(ScriptLineNumber) {
13310 v8::HandleScope scope;
13311 LocalContext env;
13312 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
13313 v8::Handle<v8::String> script = v8::String::New(
13314 "function f() {}\n\nfunction g() {}");
13315 v8::Script::Compile(script, &origin)->Run();
13316 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
13317 env->Global()->Get(v8::String::New("f")));
13318 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
13319 env->Global()->Get(v8::String::New("g")));
13320 CHECK_EQ(0, f->GetScriptLineNumber());
13321 CHECK_EQ(2, g->GetScriptLineNumber());
13322}
13323
13324
13325static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
13326 const AccessorInfo& info) {
13327 return v8_num(42);
13328}
13329
13330
13331static void SetterWhichSetsYOnThisTo23(Local<String> name,
13332 Local<Value> value,
13333 const AccessorInfo& info) {
13334 info.This()->Set(v8_str("y"), v8_num(23));
13335}
13336
13337
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013338TEST(SetterOnConstructorPrototype) {
ager@chromium.org5c838252010-02-19 08:53:10 +000013339 v8::HandleScope scope;
13340 Local<ObjectTemplate> templ = ObjectTemplate::New();
13341 templ->SetAccessor(v8_str("x"),
13342 GetterWhichReturns42,
13343 SetterWhichSetsYOnThisTo23);
13344 LocalContext context;
13345 context->Global()->Set(v8_str("P"), templ->NewInstance());
13346 CompileRun("function C1() {"
13347 " this.x = 23;"
13348 "};"
13349 "C1.prototype = P;"
13350 "function C2() {"
13351 " this.x = 23"
13352 "};"
13353 "C2.prototype = { };"
13354 "C2.prototype.__proto__ = P;");
13355
13356 v8::Local<v8::Script> script;
13357 script = v8::Script::Compile(v8_str("new C1();"));
13358 for (int i = 0; i < 10; i++) {
13359 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13360 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
13361 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
13362 }
13363
13364 script = v8::Script::Compile(v8_str("new C2();"));
13365 for (int i = 0; i < 10; i++) {
13366 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
13367 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
13368 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
13369 }
13370}
13371
13372
13373static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
13374 Local<String> name, const AccessorInfo& info) {
13375 return v8_num(42);
13376}
13377
13378
13379static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
13380 Local<String> name, Local<Value> value, const AccessorInfo& info) {
13381 if (name->Equals(v8_str("x"))) {
13382 info.This()->Set(v8_str("y"), v8_num(23));
13383 }
13384 return v8::Handle<Value>();
13385}
13386
13387
13388THREADED_TEST(InterceptorOnConstructorPrototype) {
13389 v8::HandleScope scope;
13390 Local<ObjectTemplate> templ = ObjectTemplate::New();
13391 templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
13392 NamedPropertySetterWhichSetsYOnThisTo23);
13393 LocalContext context;
13394 context->Global()->Set(v8_str("P"), templ->NewInstance());
13395 CompileRun("function C1() {"
13396 " this.x = 23;"
13397 "};"
13398 "C1.prototype = P;"
13399 "function C2() {"
13400 " this.x = 23"
13401 "};"
13402 "C2.prototype = { };"
13403 "C2.prototype.__proto__ = P;");
13404
13405 v8::Local<v8::Script> script;
13406 script = v8::Script::Compile(v8_str("new C1();"));
13407 for (int i = 0; i < 10; i++) {
13408 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13409 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
13410 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
13411 }
13412
13413 script = v8::Script::Compile(v8_str("new C2();"));
13414 for (int i = 0; i < 10; i++) {
13415 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
13416 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
13417 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
13418 }
13419}
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013420
13421
13422TEST(Bug618) {
13423 const char* source = "function C1() {"
13424 " this.x = 23;"
13425 "};"
13426 "C1.prototype = P;";
13427
13428 v8::HandleScope scope;
13429 LocalContext context;
13430 v8::Local<v8::Script> script;
13431
13432 // Use a simple object as prototype.
13433 v8::Local<v8::Object> prototype = v8::Object::New();
13434 prototype->Set(v8_str("y"), v8_num(42));
13435 context->Global()->Set(v8_str("P"), prototype);
13436
13437 // This compile will add the code to the compilation cache.
13438 CompileRun(source);
13439
13440 script = v8::Script::Compile(v8_str("new C1();"));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000013441 // Allow enough iterations for the inobject slack tracking logic
13442 // to finalize instance size and install the fast construct stub.
13443 for (int i = 0; i < 256; i++) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013444 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13445 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
13446 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
13447 }
13448
13449 // Use an API object with accessors as prototype.
13450 Local<ObjectTemplate> templ = ObjectTemplate::New();
13451 templ->SetAccessor(v8_str("x"),
13452 GetterWhichReturns42,
13453 SetterWhichSetsYOnThisTo23);
13454 context->Global()->Set(v8_str("P"), templ->NewInstance());
13455
13456 // This compile will get the code from the compilation cache.
13457 CompileRun(source);
13458
13459 script = v8::Script::Compile(v8_str("new C1();"));
13460 for (int i = 0; i < 10; i++) {
13461 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13462 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
13463 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
13464 }
13465}
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000013466
13467int prologue_call_count = 0;
13468int epilogue_call_count = 0;
13469int prologue_call_count_second = 0;
13470int epilogue_call_count_second = 0;
13471
13472void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
13473 ++prologue_call_count;
13474}
13475
13476void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
13477 ++epilogue_call_count;
13478}
13479
13480void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
13481 ++prologue_call_count_second;
13482}
13483
13484void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
13485 ++epilogue_call_count_second;
13486}
13487
13488TEST(GCCallbacks) {
13489 LocalContext context;
13490
13491 v8::V8::AddGCPrologueCallback(PrologueCallback);
13492 v8::V8::AddGCEpilogueCallback(EpilogueCallback);
13493 CHECK_EQ(0, prologue_call_count);
13494 CHECK_EQ(0, epilogue_call_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013495 HEAP->CollectAllGarbage(false);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000013496 CHECK_EQ(1, prologue_call_count);
13497 CHECK_EQ(1, epilogue_call_count);
13498 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
13499 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013500 HEAP->CollectAllGarbage(false);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000013501 CHECK_EQ(2, prologue_call_count);
13502 CHECK_EQ(2, epilogue_call_count);
13503 CHECK_EQ(1, prologue_call_count_second);
13504 CHECK_EQ(1, epilogue_call_count_second);
13505 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
13506 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013507 HEAP->CollectAllGarbage(false);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000013508 CHECK_EQ(2, prologue_call_count);
13509 CHECK_EQ(2, epilogue_call_count);
13510 CHECK_EQ(2, prologue_call_count_second);
13511 CHECK_EQ(2, epilogue_call_count_second);
13512 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
13513 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013514 HEAP->CollectAllGarbage(false);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000013515 CHECK_EQ(2, prologue_call_count);
13516 CHECK_EQ(2, epilogue_call_count);
13517 CHECK_EQ(2, prologue_call_count_second);
13518 CHECK_EQ(2, epilogue_call_count_second);
13519}
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013520
13521
13522THREADED_TEST(AddToJSFunctionResultCache) {
13523 i::FLAG_allow_natives_syntax = true;
13524 v8::HandleScope scope;
13525
13526 LocalContext context;
13527
13528 const char* code =
13529 "(function() {"
13530 " var key0 = 'a';"
13531 " var key1 = 'b';"
13532 " var r0 = %_GetFromCache(0, key0);"
13533 " var r1 = %_GetFromCache(0, key1);"
13534 " var r0_ = %_GetFromCache(0, key0);"
13535 " if (r0 !== r0_)"
13536 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
13537 " var r1_ = %_GetFromCache(0, key1);"
13538 " if (r1 !== r1_)"
13539 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
13540 " return 'PASSED';"
13541 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013542 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013543 ExpectString(code, "PASSED");
13544}
13545
13546
13547static const int k0CacheSize = 16;
13548
13549THREADED_TEST(FillJSFunctionResultCache) {
13550 i::FLAG_allow_natives_syntax = true;
13551 v8::HandleScope scope;
13552
13553 LocalContext context;
13554
13555 const char* code =
13556 "(function() {"
13557 " var k = 'a';"
13558 " var r = %_GetFromCache(0, k);"
13559 " for (var i = 0; i < 16; i++) {"
13560 " %_GetFromCache(0, 'a' + i);"
13561 " };"
13562 " if (r === %_GetFromCache(0, k))"
13563 " return 'FAILED: k0CacheSize is too small';"
13564 " return 'PASSED';"
13565 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013566 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013567 ExpectString(code, "PASSED");
13568}
13569
13570
13571THREADED_TEST(RoundRobinGetFromCache) {
13572 i::FLAG_allow_natives_syntax = true;
13573 v8::HandleScope scope;
13574
13575 LocalContext context;
13576
13577 const char* code =
13578 "(function() {"
13579 " var keys = [];"
13580 " for (var i = 0; i < 16; i++) keys.push(i);"
13581 " var values = [];"
13582 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
13583 " for (var i = 0; i < 16; i++) {"
13584 " var v = %_GetFromCache(0, keys[i]);"
13585 " if (v !== values[i])"
13586 " return 'Wrong value for ' + "
13587 " keys[i] + ': ' + v + ' vs. ' + values[i];"
13588 " };"
13589 " return 'PASSED';"
13590 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013591 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013592 ExpectString(code, "PASSED");
13593}
13594
13595
13596THREADED_TEST(ReverseGetFromCache) {
13597 i::FLAG_allow_natives_syntax = true;
13598 v8::HandleScope scope;
13599
13600 LocalContext context;
13601
13602 const char* code =
13603 "(function() {"
13604 " var keys = [];"
13605 " for (var i = 0; i < 16; i++) keys.push(i);"
13606 " var values = [];"
13607 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
13608 " for (var i = 15; i >= 16; i--) {"
13609 " var v = %_GetFromCache(0, keys[i]);"
13610 " if (v !== values[i])"
13611 " return 'Wrong value for ' + "
13612 " keys[i] + ': ' + v + ' vs. ' + values[i];"
13613 " };"
13614 " return 'PASSED';"
13615 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013616 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013617 ExpectString(code, "PASSED");
13618}
13619
13620
13621THREADED_TEST(TestEviction) {
13622 i::FLAG_allow_natives_syntax = true;
13623 v8::HandleScope scope;
13624
13625 LocalContext context;
13626
13627 const char* code =
13628 "(function() {"
13629 " for (var i = 0; i < 2*16; i++) {"
13630 " %_GetFromCache(0, 'a' + i);"
13631 " };"
13632 " return 'PASSED';"
13633 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013634 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013635 ExpectString(code, "PASSED");
13636}
lrn@chromium.org32d961d2010-06-30 09:09:34 +000013637
13638
13639THREADED_TEST(TwoByteStringInAsciiCons) {
13640 // See Chromium issue 47824.
13641 v8::HandleScope scope;
13642
13643 LocalContext context;
13644 const char* init_code =
13645 "var str1 = 'abelspendabel';"
13646 "var str2 = str1 + str1 + str1;"
13647 "str2;";
13648 Local<Value> result = CompileRun(init_code);
13649
13650 CHECK(result->IsString());
13651 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
13652 int length = string->length();
13653 CHECK(string->IsAsciiRepresentation());
13654
13655 FlattenString(string);
13656 i::Handle<i::String> flat_string = FlattenGetString(string);
13657
13658 CHECK(string->IsAsciiRepresentation());
13659 CHECK(flat_string->IsAsciiRepresentation());
13660
13661 // Create external resource.
13662 uint16_t* uc16_buffer = new uint16_t[length + 1];
13663
13664 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
13665 uc16_buffer[length] = 0;
13666
13667 TestResource resource(uc16_buffer);
13668
13669 flat_string->MakeExternal(&resource);
13670
13671 CHECK(flat_string->IsTwoByteRepresentation());
13672
13673 // At this point, we should have a Cons string which is flat and ASCII,
13674 // with a first half that is a two-byte string (although it only contains
13675 // ASCII characters). This is a valid sequence of steps, and it can happen
13676 // in real pages.
13677
13678 CHECK(string->IsAsciiRepresentation());
13679 i::ConsString* cons = i::ConsString::cast(*string);
13680 CHECK_EQ(0, cons->second()->length());
13681 CHECK(cons->first()->IsTwoByteRepresentation());
13682
13683 // Check that some string operations work.
13684
13685 // Atom RegExp.
13686 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
13687 CHECK_EQ(6, reresult->Int32Value());
13688
13689 // Nonatom RegExp.
13690 reresult = CompileRun("str2.match(/abe./g).length;");
13691 CHECK_EQ(6, reresult->Int32Value());
13692
13693 reresult = CompileRun("str2.search(/bel/g);");
13694 CHECK_EQ(1, reresult->Int32Value());
13695
13696 reresult = CompileRun("str2.search(/be./g);");
13697 CHECK_EQ(1, reresult->Int32Value());
13698
13699 ExpectTrue("/bel/g.test(str2);");
13700
13701 ExpectTrue("/be./g.test(str2);");
13702
13703 reresult = CompileRun("/bel/g.exec(str2);");
13704 CHECK(!reresult->IsNull());
13705
13706 reresult = CompileRun("/be./g.exec(str2);");
13707 CHECK(!reresult->IsNull());
13708
13709 ExpectString("str2.substring(2, 10);", "elspenda");
13710
13711 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
13712
13713 ExpectString("str2.charAt(2);", "e");
13714
13715 reresult = CompileRun("str2.charCodeAt(2);");
13716 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
13717}
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000013718
13719
13720// Failed access check callback that performs a GC on each invocation.
13721void FailedAccessCheckCallbackGC(Local<v8::Object> target,
13722 v8::AccessType type,
13723 Local<v8::Value> data) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013724 HEAP->CollectAllGarbage(true);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000013725}
13726
13727
13728TEST(GCInFailedAccessCheckCallback) {
13729 // Install a failed access check callback that performs a GC on each
13730 // invocation. Then force the callback to be called from va
13731
13732 v8::V8::Initialize();
13733 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
13734
13735 v8::HandleScope scope;
13736
13737 // Create an ObjectTemplate for global objects and install access
13738 // check callbacks that will block access.
13739 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
13740 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
13741 IndexedGetAccessBlocker,
13742 v8::Handle<v8::Value>(),
13743 false);
13744
13745 // Create a context and set an x property on it's global object.
13746 LocalContext context0(NULL, global_template);
13747 context0->Global()->Set(v8_str("x"), v8_num(42));
13748 v8::Handle<v8::Object> global0 = context0->Global();
13749
13750 // Create a context with a different security token so that the
13751 // failed access check callback will be called on each access.
13752 LocalContext context1(NULL, global_template);
13753 context1->Global()->Set(v8_str("other"), global0);
13754
13755 // Get property with failed access check.
13756 ExpectUndefined("other.x");
13757
13758 // Get element with failed access check.
13759 ExpectUndefined("other[0]");
13760
13761 // Set property with failed access check.
13762 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
13763 CHECK(result->IsObject());
13764
13765 // Set element with failed access check.
13766 result = CompileRun("other[0] = new Object()");
13767 CHECK(result->IsObject());
13768
13769 // Get property attribute with failed access check.
13770 ExpectFalse("\'x\' in other");
13771
13772 // Get property attribute for element with failed access check.
13773 ExpectFalse("0 in other");
13774
13775 // Delete property.
13776 ExpectFalse("delete other.x");
13777
13778 // Delete element.
13779 CHECK_EQ(false, global0->Delete(0));
13780
13781 // DefineAccessor.
13782 CHECK_EQ(false,
13783 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
13784
13785 // Define JavaScript accessor.
13786 ExpectUndefined("Object.prototype.__defineGetter__.call("
13787 " other, \'x\', function() { return 42; })");
13788
13789 // LookupAccessor.
13790 ExpectUndefined("Object.prototype.__lookupGetter__.call("
13791 " other, \'x\')");
13792
13793 // HasLocalElement.
13794 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
13795
13796 CHECK_EQ(false, global0->HasRealIndexedProperty(0));
13797 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
13798 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
13799
13800 // Reset the failed access check callback so it does not influence
13801 // the other tests.
13802 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
13803}
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000013804
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013805TEST(DefaultIsolateGetCurrent) {
13806 CHECK(v8::Isolate::GetCurrent() != NULL);
13807 v8::Isolate* isolate = v8::Isolate::GetCurrent();
13808 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
13809 printf("*** %s\n", "DefaultIsolateGetCurrent success");
13810}
13811
13812TEST(IsolateNewDispose) {
13813 v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
13814 v8::Isolate* isolate = v8::Isolate::New();
13815 CHECK(isolate != NULL);
13816 CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
13817 CHECK(current_isolate != isolate);
13818 CHECK(current_isolate == v8::Isolate::GetCurrent());
13819
13820 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13821 last_location = last_message = NULL;
13822 isolate->Dispose();
13823 CHECK_EQ(last_location, NULL);
13824 CHECK_EQ(last_message, NULL);
13825}
13826
13827TEST(IsolateEnterExitDefault) {
13828 v8::HandleScope scope;
13829 LocalContext context;
13830 v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
13831 CHECK(current_isolate != NULL); // Default isolate.
13832 ExpectString("'hello'", "hello");
13833 current_isolate->Enter();
13834 ExpectString("'still working'", "still working");
13835 current_isolate->Exit();
13836 ExpectString("'still working 2'", "still working 2");
13837 current_isolate->Exit();
13838 // Default isolate is always, well, 'default current'.
13839 CHECK_EQ(v8::Isolate::GetCurrent(), current_isolate);
13840 // Still working since default isolate is auto-entering any thread
13841 // that has no isolate and attempts to execute V8 APIs.
13842 ExpectString("'still working 3'", "still working 3");
13843}
13844
13845TEST(DisposeDefaultIsolate) {
13846 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13847
13848 // Run some V8 code to trigger default isolate to become 'current'.
13849 v8::HandleScope scope;
13850 LocalContext context;
13851 ExpectString("'run some V8'", "run some V8");
13852
13853 v8::Isolate* isolate = v8::Isolate::GetCurrent();
13854 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
13855 last_location = last_message = NULL;
13856 isolate->Dispose();
13857 // It is not possible to dispose default isolate via Isolate API.
13858 CHECK_NE(last_location, NULL);
13859 CHECK_NE(last_message, NULL);
13860}
13861
13862TEST(RunDefaultAndAnotherIsolate) {
13863 v8::HandleScope scope;
13864 LocalContext context;
13865
13866 // Enter new isolate.
13867 v8::Isolate* isolate = v8::Isolate::New();
13868 CHECK(isolate);
13869 isolate->Enter();
13870 { // Need this block because subsequent Exit() will deallocate Heap,
13871 // so we need all scope objects to be deconstructed when it happens.
13872 v8::HandleScope scope_new;
13873 LocalContext context_new;
13874
13875 // Run something in new isolate.
13876 CompileRun("var foo = 153;");
13877 ExpectTrue("function f() { return foo == 153; }; f()");
13878 }
13879 isolate->Exit();
13880
13881 // This runs automatically in default isolate.
13882 // Variables in another isolate should be not available.
13883 ExpectTrue("function f() {"
13884 " try {"
13885 " foo;"
13886 " return false;"
13887 " } catch(e) {"
13888 " return true;"
13889 " }"
13890 "};"
13891 "var bar = 371;"
13892 "f()");
13893
13894 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13895 last_location = last_message = NULL;
13896 isolate->Dispose();
13897 CHECK_EQ(last_location, NULL);
13898 CHECK_EQ(last_message, NULL);
13899
13900 // Check that default isolate still runs.
13901 ExpectTrue("function f() { return bar == 371; }; f()");
13902}
13903
13904TEST(DisposeIsolateWhenInUse) {
13905 v8::Isolate* isolate = v8::Isolate::New();
13906 CHECK(isolate);
13907 isolate->Enter();
13908 v8::HandleScope scope;
13909 LocalContext context;
13910 // Run something in this isolate.
13911 ExpectTrue("true");
13912 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13913 last_location = last_message = NULL;
13914 // Still entered, should fail.
13915 isolate->Dispose();
13916 CHECK_NE(last_location, NULL);
13917 CHECK_NE(last_message, NULL);
13918}
13919
13920TEST(RunTwoIsolatesOnSingleThread) {
13921 // Run isolate 1.
13922 v8::Isolate* isolate1 = v8::Isolate::New();
13923 isolate1->Enter();
13924 v8::Persistent<v8::Context> context1 = v8::Context::New();
13925
13926 {
13927 v8::Context::Scope cscope(context1);
13928 v8::HandleScope scope;
13929 // Run something in new isolate.
13930 CompileRun("var foo = 'isolate 1';");
13931 ExpectString("function f() { return foo; }; f()", "isolate 1");
13932 }
13933
13934 // Run isolate 2.
13935 v8::Isolate* isolate2 = v8::Isolate::New();
13936 v8::Persistent<v8::Context> context2;
13937
13938 {
13939 v8::Isolate::Scope iscope(isolate2);
13940 context2 = v8::Context::New();
13941 v8::Context::Scope cscope(context2);
13942 v8::HandleScope scope;
13943
13944 // Run something in new isolate.
13945 CompileRun("var foo = 'isolate 2';");
13946 ExpectString("function f() { return foo; }; f()", "isolate 2");
13947 }
13948
13949 {
13950 v8::Context::Scope cscope(context1);
13951 v8::HandleScope scope;
13952 // Now again in isolate 1
13953 ExpectString("function f() { return foo; }; f()", "isolate 1");
13954 }
13955
13956 isolate1->Exit();
13957
13958 // Run some stuff in default isolate.
13959 v8::Persistent<v8::Context> context_default = v8::Context::New();
13960
13961 {
13962 v8::Context::Scope cscope(context_default);
13963 v8::HandleScope scope;
13964 // Variables in other isolates should be not available, verify there
13965 // is an exception.
13966 ExpectTrue("function f() {"
13967 " try {"
13968 " foo;"
13969 " return false;"
13970 " } catch(e) {"
13971 " return true;"
13972 " }"
13973 "};"
13974 "var isDefaultIsolate = true;"
13975 "f()");
13976 }
13977
13978 isolate1->Enter();
13979
13980 {
13981 v8::Isolate::Scope iscope(isolate2);
13982 v8::Context::Scope cscope(context2);
13983 v8::HandleScope scope;
13984 ExpectString("function f() { return foo; }; f()", "isolate 2");
13985 }
13986
13987 {
13988 v8::Context::Scope cscope(context1);
13989 v8::HandleScope scope;
13990 ExpectString("function f() { return foo; }; f()", "isolate 1");
13991 }
13992
13993 {
13994 v8::Isolate::Scope iscope(isolate2);
13995 context2.Dispose();
13996 }
13997
13998 context1.Dispose();
13999 isolate1->Exit();
14000
14001 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14002 last_location = last_message = NULL;
14003
14004 isolate1->Dispose();
14005 CHECK_EQ(last_location, NULL);
14006 CHECK_EQ(last_message, NULL);
14007
14008 isolate2->Dispose();
14009 CHECK_EQ(last_location, NULL);
14010 CHECK_EQ(last_message, NULL);
14011
14012 // Check that default isolate still runs.
14013 {
14014 v8::Context::Scope cscope(context_default);
14015 v8::HandleScope scope;
14016 ExpectTrue("function f() { return isDefaultIsolate; }; f()");
14017 }
14018}
14019
14020static int CalcFibonacci(v8::Isolate* isolate, int limit) {
14021 v8::Isolate::Scope isolate_scope(isolate);
14022 v8::HandleScope scope;
14023 LocalContext context;
14024 i::ScopedVector<char> code(1024);
14025 i::OS::SNPrintF(code, "function fib(n) {"
14026 " if (n <= 2) return 1;"
14027 " return fib(n-1) + fib(n-2);"
14028 "}"
14029 "fib(%d)", limit);
14030 Local<Value> value = CompileRun(code.start());
14031 CHECK(value->IsNumber());
14032 return static_cast<int>(value->NumberValue());
14033}
14034
14035class IsolateThread : public v8::internal::Thread {
14036 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000014037 IsolateThread(v8::Isolate* isolate, int fib_limit)
14038 : Thread("IsolateThread"),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014039 isolate_(isolate),
14040 fib_limit_(fib_limit),
14041 result_(0) { }
14042
14043 void Run() {
14044 result_ = CalcFibonacci(isolate_, fib_limit_);
14045 }
14046
14047 int result() { return result_; }
14048
14049 private:
14050 v8::Isolate* isolate_;
14051 int fib_limit_;
14052 int result_;
14053};
14054
14055TEST(MultipleIsolatesOnIndividualThreads) {
14056 v8::Isolate* isolate1 = v8::Isolate::New();
14057 v8::Isolate* isolate2 = v8::Isolate::New();
14058
14059 IsolateThread thread1(isolate1, 21);
14060 IsolateThread thread2(isolate2, 12);
14061
14062 // Compute some fibonacci numbers on 3 threads in 3 isolates.
14063 thread1.Start();
14064 thread2.Start();
14065
14066 int result1 = CalcFibonacci(v8::Isolate::GetCurrent(), 21);
14067 int result2 = CalcFibonacci(v8::Isolate::GetCurrent(), 12);
14068
14069 thread1.Join();
14070 thread2.Join();
14071
14072 // Compare results. The actual fibonacci numbers for 12 and 21 are taken
14073 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
14074 CHECK_EQ(result1, 10946);
14075 CHECK_EQ(result2, 144);
14076 CHECK_EQ(result1, thread1.result());
14077 CHECK_EQ(result2, thread2.result());
14078
14079 isolate1->Dispose();
14080 isolate2->Dispose();
14081}
14082
lrn@chromium.org1c092762011-05-09 09:42:16 +000014083TEST(IsolateDifferentContexts) {
14084 v8::Isolate* isolate = v8::Isolate::New();
14085 Persistent<v8::Context> context;
14086 {
14087 v8::Isolate::Scope isolate_scope(isolate);
14088 v8::HandleScope handle_scope;
14089 context = v8::Context::New();
14090 v8::Context::Scope context_scope(context);
14091 Local<Value> v = CompileRun("2");
14092 CHECK(v->IsNumber());
14093 CHECK_EQ(2, static_cast<int>(v->NumberValue()));
14094 }
14095 {
14096 v8::Isolate::Scope isolate_scope(isolate);
14097 v8::HandleScope handle_scope;
14098 context = v8::Context::New();
14099 v8::Context::Scope context_scope(context);
14100 Local<Value> v = CompileRun("22");
14101 CHECK(v->IsNumber());
14102 CHECK_EQ(22, static_cast<int>(v->NumberValue()));
14103 }
14104}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014105
14106class InitDefaultIsolateThread : public v8::internal::Thread {
14107 public:
sgjesse@chromium.orge0599052011-03-25 07:34:35 +000014108 enum TestCase {
14109 IgnoreOOM,
14110 SetResourceConstraints,
14111 SetFatalHandler,
14112 SetCounterFunction,
14113 SetCreateHistogramFunction,
14114 SetAddHistogramSampleFunction
14115 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014116
14117 explicit InitDefaultIsolateThread(TestCase testCase)
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000014118 : Thread("InitDefaultIsolateThread"),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014119 testCase_(testCase),
14120 result_(false) { }
14121
14122 void Run() {
14123 switch (testCase_) {
14124 case IgnoreOOM:
14125 v8::V8::IgnoreOutOfMemoryException();
14126 break;
14127
14128 case SetResourceConstraints: {
14129 static const int K = 1024;
14130 v8::ResourceConstraints constraints;
14131 constraints.set_max_young_space_size(256 * K);
14132 constraints.set_max_old_space_size(4 * K * K);
14133 v8::SetResourceConstraints(&constraints);
14134 break;
14135 }
14136
14137 case SetFatalHandler:
14138 v8::V8::SetFatalErrorHandler(NULL);
14139 break;
sgjesse@chromium.orge0599052011-03-25 07:34:35 +000014140
14141 case SetCounterFunction:
14142 v8::V8::SetCounterFunction(NULL);
14143 break;
14144
14145 case SetCreateHistogramFunction:
14146 v8::V8::SetCreateHistogramFunction(NULL);
14147 break;
14148
14149 case SetAddHistogramSampleFunction:
14150 v8::V8::SetAddHistogramSampleFunction(NULL);
14151 break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014152 }
14153 result_ = true;
14154 }
14155
14156 bool result() { return result_; }
14157
14158 private:
14159 TestCase testCase_;
14160 bool result_;
14161};
14162
14163
14164static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
14165 InitDefaultIsolateThread thread(testCase);
14166 thread.Start();
14167 thread.Join();
14168 CHECK_EQ(thread.result(), true);
14169}
14170
14171TEST(InitializeDefaultIsolateOnSecondaryThread1) {
14172 InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM);
14173}
14174
14175TEST(InitializeDefaultIsolateOnSecondaryThread2) {
14176 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
14177}
14178
14179TEST(InitializeDefaultIsolateOnSecondaryThread3) {
14180 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
14181}
14182
sgjesse@chromium.orge0599052011-03-25 07:34:35 +000014183TEST(InitializeDefaultIsolateOnSecondaryThread4) {
14184 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
14185}
14186
14187TEST(InitializeDefaultIsolateOnSecondaryThread5) {
14188 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
14189}
14190
14191TEST(InitializeDefaultIsolateOnSecondaryThread6) {
14192 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
14193}
14194
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000014195
14196TEST(StringCheckMultipleContexts) {
14197 const char* code =
14198 "(function() { return \"a\".charAt(0); })()";
14199
14200 {
14201 // Run the code twice in the first context to initialize the call IC.
14202 v8::HandleScope scope;
14203 LocalContext context1;
14204 ExpectString(code, "a");
14205 ExpectString(code, "a");
14206 }
14207
14208 {
14209 // Change the String.prototype in the second context and check
14210 // that the right function gets called.
14211 v8::HandleScope scope;
14212 LocalContext context2;
14213 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
14214 ExpectString(code, "not a");
14215 }
14216}
14217
14218
14219TEST(NumberCheckMultipleContexts) {
14220 const char* code =
14221 "(function() { return (42).toString(); })()";
14222
14223 {
14224 // Run the code twice in the first context to initialize the call IC.
14225 v8::HandleScope scope;
14226 LocalContext context1;
14227 ExpectString(code, "42");
14228 ExpectString(code, "42");
14229 }
14230
14231 {
14232 // Change the Number.prototype in the second context and check
14233 // that the right function gets called.
14234 v8::HandleScope scope;
14235 LocalContext context2;
14236 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
14237 ExpectString(code, "not 42");
14238 }
14239}
14240
14241
14242TEST(BooleanCheckMultipleContexts) {
14243 const char* code =
14244 "(function() { return true.toString(); })()";
14245
14246 {
14247 // Run the code twice in the first context to initialize the call IC.
14248 v8::HandleScope scope;
14249 LocalContext context1;
14250 ExpectString(code, "true");
14251 ExpectString(code, "true");
14252 }
14253
14254 {
14255 // Change the Boolean.prototype in the second context and check
14256 // that the right function gets called.
14257 v8::HandleScope scope;
14258 LocalContext context2;
14259 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
14260 ExpectString(code, "");
14261 }
14262}
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000014263
14264
14265TEST(DontDeleteCellLoadIC) {
14266 const char* function_code =
14267 "function readCell() { while (true) { return cell; } }";
14268
14269 {
14270 // Run the code twice in the first context to initialize the load
14271 // IC for a don't delete cell.
14272 v8::HandleScope scope;
14273 LocalContext context1;
14274 CompileRun("var cell = \"first\";");
14275 ExpectBoolean("delete cell", false);
14276 CompileRun(function_code);
14277 ExpectString("readCell()", "first");
14278 ExpectString("readCell()", "first");
14279 }
14280
14281 {
14282 // Use a deletable cell in the second context.
14283 v8::HandleScope scope;
14284 LocalContext context2;
14285 CompileRun("cell = \"second\";");
14286 CompileRun(function_code);
14287 ExpectString("readCell()", "second");
14288 ExpectBoolean("delete cell", true);
14289 ExpectString("(function() {"
14290 " try {"
14291 " return readCell();"
14292 " } catch(e) {"
14293 " return e.toString();"
14294 " }"
14295 "})()",
14296 "ReferenceError: cell is not defined");
14297 CompileRun("cell = \"new_second\";");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014298 HEAP->CollectAllGarbage(true);
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000014299 ExpectString("readCell()", "new_second");
14300 ExpectString("readCell()", "new_second");
14301 }
14302}
14303
14304
14305TEST(DontDeleteCellLoadICForceDelete) {
14306 const char* function_code =
14307 "function readCell() { while (true) { return cell; } }";
14308
14309 // Run the code twice to initialize the load IC for a don't delete
14310 // cell.
14311 v8::HandleScope scope;
14312 LocalContext context;
14313 CompileRun("var cell = \"value\";");
14314 ExpectBoolean("delete cell", false);
14315 CompileRun(function_code);
14316 ExpectString("readCell()", "value");
14317 ExpectString("readCell()", "value");
14318
14319 // Delete the cell using the API and check the inlined code works
14320 // correctly.
14321 CHECK(context->Global()->ForceDelete(v8_str("cell")));
14322 ExpectString("(function() {"
14323 " try {"
14324 " return readCell();"
14325 " } catch(e) {"
14326 " return e.toString();"
14327 " }"
14328 "})()",
14329 "ReferenceError: cell is not defined");
14330}
14331
14332
14333TEST(DontDeleteCellLoadICAPI) {
14334 const char* function_code =
14335 "function readCell() { while (true) { return cell; } }";
14336
14337 // Run the code twice to initialize the load IC for a don't delete
14338 // cell created using the API.
14339 v8::HandleScope scope;
14340 LocalContext context;
14341 context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
14342 ExpectBoolean("delete cell", false);
14343 CompileRun(function_code);
14344 ExpectString("readCell()", "value");
14345 ExpectString("readCell()", "value");
14346
14347 // Delete the cell using the API and check the inlined code works
14348 // correctly.
14349 CHECK(context->Global()->ForceDelete(v8_str("cell")));
14350 ExpectString("(function() {"
14351 " try {"
14352 " return readCell();"
14353 " } catch(e) {"
14354 " return e.toString();"
14355 " }"
14356 "})()",
14357 "ReferenceError: cell is not defined");
14358}
14359
14360
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000014361TEST(RegExp) {
14362 v8::HandleScope scope;
14363 LocalContext context;
14364
14365 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
14366 CHECK(re->IsRegExp());
14367 CHECK(re->GetSource()->Equals(v8_str("foo")));
14368 CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
14369
14370 re = v8::RegExp::New(v8_str("bar"),
14371 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
14372 v8::RegExp::kGlobal));
14373 CHECK(re->IsRegExp());
14374 CHECK(re->GetSource()->Equals(v8_str("bar")));
14375 CHECK_EQ(static_cast<int>(re->GetFlags()),
14376 v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal);
14377
14378 re = v8::RegExp::New(v8_str("baz"),
14379 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
14380 v8::RegExp::kMultiline));
14381 CHECK(re->IsRegExp());
14382 CHECK(re->GetSource()->Equals(v8_str("baz")));
14383 CHECK_EQ(static_cast<int>(re->GetFlags()),
14384 v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline);
14385
14386 re = CompileRun("/quux/").As<v8::RegExp>();
14387 CHECK(re->IsRegExp());
14388 CHECK(re->GetSource()->Equals(v8_str("quux")));
14389 CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
14390
14391 re = CompileRun("/quux/gm").As<v8::RegExp>();
14392 CHECK(re->IsRegExp());
14393 CHECK(re->GetSource()->Equals(v8_str("quux")));
14394 CHECK_EQ(static_cast<int>(re->GetFlags()),
14395 v8::RegExp::kGlobal | v8::RegExp::kMultiline);
14396
14397 // Override the RegExp constructor and check the API constructor
14398 // still works.
14399 CompileRun("RegExp = function() {}");
14400
14401 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
14402 CHECK(re->IsRegExp());
14403 CHECK(re->GetSource()->Equals(v8_str("foobar")));
14404 CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
14405
14406 re = v8::RegExp::New(v8_str("foobarbaz"),
14407 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
14408 v8::RegExp::kMultiline));
14409 CHECK(re->IsRegExp());
14410 CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
14411 CHECK_EQ(static_cast<int>(re->GetFlags()),
14412 v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline);
14413
14414 context->Global()->Set(v8_str("re"), re);
14415 ExpectTrue("re.test('FoobarbaZ')");
14416
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000014417 // RegExps are objects on which you can set properties.
14418 re->Set(v8_str("property"), v8::Integer::New(32));
14419 v8::Handle<v8::Value> value = CompileRun("re.property");
14420 ASSERT_EQ(32, value->Int32Value());
14421
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000014422 v8::TryCatch try_catch;
14423 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
14424 CHECK(re.IsEmpty());
14425 CHECK(try_catch.HasCaught());
14426 context->Global()->Set(v8_str("ex"), try_catch.Exception());
14427 ExpectTrue("ex instanceof SyntaxError");
14428}
14429
14430
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000014431THREADED_TEST(Equals) {
14432 v8::HandleScope handleScope;
14433 LocalContext localContext;
14434
14435 v8::Handle<v8::Object> globalProxy = localContext->Global();
14436 v8::Handle<Value> global = globalProxy->GetPrototype();
14437
14438 CHECK(global->StrictEquals(global));
14439 CHECK(!global->StrictEquals(globalProxy));
14440 CHECK(!globalProxy->StrictEquals(global));
14441 CHECK(globalProxy->StrictEquals(globalProxy));
14442
14443 CHECK(global->Equals(global));
14444 CHECK(!global->Equals(globalProxy));
14445 CHECK(!globalProxy->Equals(global));
14446 CHECK(globalProxy->Equals(globalProxy));
14447}
14448
14449
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000014450static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
14451 const v8::AccessorInfo& info ) {
14452 return v8_str("42!");
14453}
14454
14455
14456static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo& info) {
14457 v8::Handle<v8::Array> result = v8::Array::New();
14458 result->Set(0, v8_str("universalAnswer"));
14459 return result;
14460}
14461
14462
14463TEST(NamedEnumeratorAndForIn) {
14464 v8::HandleScope handle_scope;
14465 LocalContext context;
14466 v8::Context::Scope context_scope(context.local());
14467
14468 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New();
14469 tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
14470 context->Global()->Set(v8_str("o"), tmpl->NewInstance());
14471 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
14472 "var result = []; for (var k in o) result.push(k); result"));
14473 CHECK_EQ(1, result->Length());
14474 CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
14475}
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000014476
14477
14478TEST(DefinePropertyPostDetach) {
14479 v8::HandleScope scope;
14480 LocalContext context;
14481 v8::Handle<v8::Object> proxy = context->Global();
14482 v8::Handle<v8::Function> define_property =
14483 CompileRun("(function() {"
14484 " Object.defineProperty("
14485 " this,"
14486 " 1,"
14487 " { configurable: true, enumerable: true, value: 3 });"
14488 "})").As<Function>();
14489 context->DetachGlobal();
14490 define_property->Call(proxy, 0, NULL);
14491}
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014492
14493
14494static void InstallContextId(v8::Handle<Context> context, int id) {
14495 Context::Scope scope(context);
14496 CompileRun("Object.prototype").As<Object>()->
14497 Set(v8_str("context_id"), v8::Integer::New(id));
14498}
14499
14500
14501static void CheckContextId(v8::Handle<Object> object, int expected) {
14502 CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
14503}
14504
14505
14506THREADED_TEST(CreationContext) {
14507 HandleScope handle_scope;
14508 Persistent<Context> context1 = Context::New();
14509 InstallContextId(context1, 1);
14510 Persistent<Context> context2 = Context::New();
14511 InstallContextId(context2, 2);
14512 Persistent<Context> context3 = Context::New();
14513 InstallContextId(context3, 3);
14514
14515 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New();
14516
14517 Local<Object> object1;
14518 Local<Function> func1;
14519 {
14520 Context::Scope scope(context1);
14521 object1 = Object::New();
14522 func1 = tmpl->GetFunction();
14523 }
14524
14525 Local<Object> object2;
14526 Local<Function> func2;
14527 {
14528 Context::Scope scope(context2);
14529 object2 = Object::New();
14530 func2 = tmpl->GetFunction();
14531 }
14532
14533 Local<Object> instance1;
14534 Local<Object> instance2;
14535
14536 {
14537 Context::Scope scope(context3);
14538 instance1 = func1->NewInstance();
14539 instance2 = func2->NewInstance();
14540 }
14541
14542 CHECK(object1->CreationContext() == context1);
14543 CheckContextId(object1, 1);
14544 CHECK(func1->CreationContext() == context1);
14545 CheckContextId(func1, 1);
14546 CHECK(instance1->CreationContext() == context1);
14547 CheckContextId(instance1, 1);
14548 CHECK(object2->CreationContext() == context2);
14549 CheckContextId(object2, 2);
14550 CHECK(func2->CreationContext() == context2);
14551 CheckContextId(func2, 2);
14552 CHECK(instance2->CreationContext() == context2);
14553 CheckContextId(instance2, 2);
14554
14555 {
14556 Context::Scope scope(context1);
14557 CHECK(object1->CreationContext() == context1);
14558 CheckContextId(object1, 1);
14559 CHECK(func1->CreationContext() == context1);
14560 CheckContextId(func1, 1);
14561 CHECK(instance1->CreationContext() == context1);
14562 CheckContextId(instance1, 1);
14563 CHECK(object2->CreationContext() == context2);
14564 CheckContextId(object2, 2);
14565 CHECK(func2->CreationContext() == context2);
14566 CheckContextId(func2, 2);
14567 CHECK(instance2->CreationContext() == context2);
14568 CheckContextId(instance2, 2);
14569 }
14570
14571 {
14572 Context::Scope scope(context2);
14573 CHECK(object1->CreationContext() == context1);
14574 CheckContextId(object1, 1);
14575 CHECK(func1->CreationContext() == context1);
14576 CheckContextId(func1, 1);
14577 CHECK(instance1->CreationContext() == context1);
14578 CheckContextId(instance1, 1);
14579 CHECK(object2->CreationContext() == context2);
14580 CheckContextId(object2, 2);
14581 CHECK(func2->CreationContext() == context2);
14582 CheckContextId(func2, 2);
14583 CHECK(instance2->CreationContext() == context2);
14584 CheckContextId(instance2, 2);
14585 }
14586
14587 context1.Dispose();
14588 context2.Dispose();
14589 context3.Dispose();
14590}
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +000014591
14592
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000014593THREADED_TEST(CreationContextOfJsFunction) {
14594 HandleScope handle_scope;
14595 Persistent<Context> context = Context::New();
14596 InstallContextId(context, 1);
14597
14598 Local<Object> function;
14599 {
14600 Context::Scope scope(context);
14601 function = CompileRun("function foo() {}; foo").As<Object>();
14602 }
14603
14604 CHECK(function->CreationContext() == context);
14605 CheckContextId(function, 1);
14606
14607 context.Dispose();
14608}
14609
14610
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +000014611Handle<Value> HasOwnPropertyIndexedPropertyGetter(uint32_t index,
14612 const AccessorInfo& info) {
14613 if (index == 42) return v8_str("yes");
14614 return Handle<v8::Integer>();
14615}
14616
14617
14618Handle<Value> HasOwnPropertyNamedPropertyGetter(Local<String> property,
14619 const AccessorInfo& info) {
14620 if (property->Equals(v8_str("foo"))) return v8_str("yes");
14621 return Handle<Value>();
14622}
14623
14624
14625Handle<v8::Integer> HasOwnPropertyIndexedPropertyQuery(
14626 uint32_t index, const AccessorInfo& info) {
14627 if (index == 42) return v8_num(1).As<v8::Integer>();
14628 return Handle<v8::Integer>();
14629}
14630
14631
14632Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery(
14633 Local<String> property, const AccessorInfo& info) {
14634 if (property->Equals(v8_str("foo"))) return v8_num(1).As<v8::Integer>();
14635 return Handle<v8::Integer>();
14636}
14637
14638
14639Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery2(
14640 Local<String> property, const AccessorInfo& info) {
14641 if (property->Equals(v8_str("bar"))) return v8_num(1).As<v8::Integer>();
14642 return Handle<v8::Integer>();
14643}
14644
14645
14646Handle<Value> HasOwnPropertyAccessorGetter(Local<String> property,
14647 const AccessorInfo& info) {
14648 return v8_str("yes");
14649}
14650
14651
14652TEST(HasOwnProperty) {
14653 v8::HandleScope scope;
14654 LocalContext env;
14655 { // Check normal properties and defined getters.
14656 Handle<Value> value = CompileRun(
14657 "function Foo() {"
14658 " this.foo = 11;"
14659 " this.__defineGetter__('baz', function() { return 1; });"
14660 "};"
14661 "function Bar() { "
14662 " this.bar = 13;"
14663 " this.__defineGetter__('bla', function() { return 2; });"
14664 "};"
14665 "Bar.prototype = new Foo();"
14666 "new Bar();");
14667 CHECK(value->IsObject());
14668 Handle<Object> object = value->ToObject();
14669 CHECK(object->Has(v8_str("foo")));
14670 CHECK(!object->HasOwnProperty(v8_str("foo")));
14671 CHECK(object->HasOwnProperty(v8_str("bar")));
14672 CHECK(object->Has(v8_str("baz")));
14673 CHECK(!object->HasOwnProperty(v8_str("baz")));
14674 CHECK(object->HasOwnProperty(v8_str("bla")));
14675 }
14676 { // Check named getter interceptors.
14677 Handle<ObjectTemplate> templ = ObjectTemplate::New();
14678 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
14679 Handle<Object> instance = templ->NewInstance();
14680 CHECK(!instance->HasOwnProperty(v8_str("42")));
14681 CHECK(instance->HasOwnProperty(v8_str("foo")));
14682 CHECK(!instance->HasOwnProperty(v8_str("bar")));
14683 }
14684 { // Check indexed getter interceptors.
14685 Handle<ObjectTemplate> templ = ObjectTemplate::New();
14686 templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
14687 Handle<Object> instance = templ->NewInstance();
14688 CHECK(instance->HasOwnProperty(v8_str("42")));
14689 CHECK(!instance->HasOwnProperty(v8_str("43")));
14690 CHECK(!instance->HasOwnProperty(v8_str("foo")));
14691 }
14692 { // Check named query interceptors.
14693 Handle<ObjectTemplate> templ = ObjectTemplate::New();
14694 templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
14695 Handle<Object> instance = templ->NewInstance();
14696 CHECK(instance->HasOwnProperty(v8_str("foo")));
14697 CHECK(!instance->HasOwnProperty(v8_str("bar")));
14698 }
14699 { // Check indexed query interceptors.
14700 Handle<ObjectTemplate> templ = ObjectTemplate::New();
14701 templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
14702 Handle<Object> instance = templ->NewInstance();
14703 CHECK(instance->HasOwnProperty(v8_str("42")));
14704 CHECK(!instance->HasOwnProperty(v8_str("41")));
14705 }
14706 { // Check callbacks.
14707 Handle<ObjectTemplate> templ = ObjectTemplate::New();
14708 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
14709 Handle<Object> instance = templ->NewInstance();
14710 CHECK(instance->HasOwnProperty(v8_str("foo")));
14711 CHECK(!instance->HasOwnProperty(v8_str("bar")));
14712 }
14713 { // Check that query wins on disagreement.
14714 Handle<ObjectTemplate> templ = ObjectTemplate::New();
14715 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
14716 0,
14717 HasOwnPropertyNamedPropertyQuery2);
14718 Handle<Object> instance = templ->NewInstance();
14719 CHECK(!instance->HasOwnProperty(v8_str("foo")));
14720 CHECK(instance->HasOwnProperty(v8_str("bar")));
14721 }
14722}
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000014723
14724
14725void CheckCodeGenerationAllowed() {
14726 Handle<Value> result = CompileRun("eval('42')");
14727 CHECK_EQ(42, result->Int32Value());
14728 result = CompileRun("(function(e) { return e('42'); })(eval)");
14729 CHECK_EQ(42, result->Int32Value());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000014730 result = CompileRun("var f = new Function('return 42'); f()");
14731 CHECK_EQ(42, result->Int32Value());
14732}
14733
14734
14735void CheckCodeGenerationDisallowed() {
14736 TryCatch try_catch;
14737
14738 Handle<Value> result = CompileRun("eval('42')");
14739 CHECK(result.IsEmpty());
14740 CHECK(try_catch.HasCaught());
14741 try_catch.Reset();
14742
14743 result = CompileRun("(function(e) { return e('42'); })(eval)");
14744 CHECK(result.IsEmpty());
14745 CHECK(try_catch.HasCaught());
14746 try_catch.Reset();
14747
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000014748 result = CompileRun("var f = new Function('return 42'); f()");
14749 CHECK(result.IsEmpty());
14750 CHECK(try_catch.HasCaught());
14751}
14752
14753
14754bool CodeGenerationAllowed(Local<Context> context) {
14755 ApiTestFuzzer::Fuzz();
14756 return true;
14757}
14758
14759
14760bool CodeGenerationDisallowed(Local<Context> context) {
14761 ApiTestFuzzer::Fuzz();
14762 return false;
14763}
14764
14765
14766THREADED_TEST(AllowCodeGenFromStrings) {
14767 v8::HandleScope scope;
14768 LocalContext context;
14769
ager@chromium.orgea91cc52011-05-23 06:06:11 +000014770 // eval and the Function constructor allowed by default.
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000014771 CheckCodeGenerationAllowed();
14772
ager@chromium.orgea91cc52011-05-23 06:06:11 +000014773 // Disallow eval and the Function constructor.
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000014774 context->AllowCodeGenerationFromStrings(false);
14775 CheckCodeGenerationDisallowed();
14776
14777 // Allow again.
14778 context->AllowCodeGenerationFromStrings(true);
14779 CheckCodeGenerationAllowed();
14780
14781 // Disallow but setting a global callback that will allow the calls.
14782 context->AllowCodeGenerationFromStrings(false);
14783 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
14784 CheckCodeGenerationAllowed();
14785
14786 // Set a callback that disallows the code generation.
14787 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
14788 CheckCodeGenerationDisallowed();
14789}
lrn@chromium.org1c092762011-05-09 09:42:16 +000014790
14791
14792static v8::Handle<Value> NonObjectThis(const v8::Arguments& args) {
14793 return v8::Undefined();
14794}
14795
14796
14797THREADED_TEST(CallAPIFunctionOnNonObject) {
14798 v8::HandleScope scope;
14799 LocalContext context;
14800 Handle<FunctionTemplate> templ = v8::FunctionTemplate::New(NonObjectThis);
14801 Handle<Function> function = templ->GetFunction();
14802 context->Global()->Set(v8_str("f"), function);
14803 TryCatch try_catch;
14804 CompileRun("f.call(2)");
lrn@chromium.org1c092762011-05-09 09:42:16 +000014805}
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000014806
14807
14808// Regression test for issue 1470.
14809THREADED_TEST(ReadOnlyIndexedProperties) {
14810 v8::HandleScope scope;
14811 Local<ObjectTemplate> templ = ObjectTemplate::New();
14812
14813 LocalContext context;
14814 Local<v8::Object> obj = templ->NewInstance();
14815 context->Global()->Set(v8_str("obj"), obj);
14816 obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
14817 obj->Set(v8_str("1"), v8_str("foobar"));
14818 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
14819 obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
14820 obj->Set(v8_num(2), v8_str("foobar"));
14821 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
14822
14823 // Test non-smi case.
14824 obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
14825 obj->Set(v8_str("2000000000"), v8_str("foobar"));
14826 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
14827}
ricow@chromium.org4f693d62011-07-04 14:01:31 +000014828
14829
14830THREADED_TEST(Regress1516) {
14831 v8::HandleScope scope;
14832
14833 LocalContext context;
14834 { v8::HandleScope temp_scope;
14835 CompileRun("({'a': 0})");
14836 }
14837
14838 int elements;
14839 { i::MapCache* map_cache =
14840 i::MapCache::cast(i::Isolate::Current()->context()->map_cache());
14841 elements = map_cache->NumberOfElements();
14842 CHECK_LE(1, elements);
14843 }
14844
14845 i::Isolate::Current()->heap()->CollectAllGarbage(true);
14846 { i::Object* raw_map_cache = i::Isolate::Current()->context()->map_cache();
14847 if (raw_map_cache != i::Isolate::Current()->heap()->undefined_value()) {
14848 i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
14849 CHECK_GT(elements, map_cache->NumberOfElements());
14850 }
14851 }
14852}